[docs] Rewrite selected Clang docs to Markdown (#209283)
Tracking issue: https://github.com/llvm/llvm-project/issues/201242 Migration guide docs: https://llvm.org/docs/SphinxQuickstartTemplate.html#markdown-migration-guidelines RFC: https://discourse.llvm.org/t/rfc-make-myst-markdown-the-llvm-docs-format-rip-rest/90840 This was prepared with rst2myst plus LLM-assisted cleanup. I paged through all the generated HTML looking for migration artifacts, and all of the differences I could find appear to be formatting error corrections. I noticed that there is a large block of literal rst text in APINotes.md, but I will defer that for later cleanup.
This commit is contained in:
parent
cf293b069a
commit
1514df3333
20 changed files with 2758 additions and 2991 deletions
|
|
@ -1,66 +1,32 @@
|
|||
.. raw:: html
|
||||
```{contents}
|
||||
:local: true
|
||||
```
|
||||
|
||||
<style type="text/css">
|
||||
.none { background-color: #FFCCCC }
|
||||
.part { background-color: #FFFF99 }
|
||||
.good { background-color: #CCFF99 }
|
||||
</style>
|
||||
|
||||
.. role:: none
|
||||
.. role:: part
|
||||
.. role:: good
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
==============
|
||||
AMDGPU Support
|
||||
==============
|
||||
# AMDGPU Support
|
||||
|
||||
Clang supports OpenCL, HIP and OpenMP on AMD GPU targets.
|
||||
|
||||
## Predefined Macros
|
||||
|
||||
Predefined Macros
|
||||
=================
|
||||
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Macro
|
||||
- Description
|
||||
* - ``__AMDGPU__``
|
||||
- Indicates that the code is being compiled for an AMD GPU.
|
||||
* - ``__AMDGCN__``
|
||||
- Defined if the GPU target is AMDGCN.
|
||||
* - ``__R600__``
|
||||
- Defined if the GPU target is R600.
|
||||
* - ``__<ArchName>__``
|
||||
- Defined with the name of the architecture (e.g., ``__gfx906__`` for the gfx906 architecture).
|
||||
* - ``__<GFXN>__``
|
||||
- Defines the GFX family (e.g., for gfx906, this macro would be ``__GFX9__``).
|
||||
* - ``__amdgcn_processor__``
|
||||
- Defined with the processor name as a string (e.g., ``"gfx906"``).
|
||||
* - ``__amdgcn_target_id__``
|
||||
- Defined with the target ID as a string.
|
||||
* - ``__amdgcn_feature_<feature-name>__``
|
||||
- Defined for each supported target feature. The value is 1 if the feature is enabled and 0 if it is disabled. Allowed feature names are sramecc and xnack.
|
||||
* - ``__AMDGCN_CUMODE__``
|
||||
- Defined as 1 if the CU mode is enabled and 0 if the WGP mode is enabled.
|
||||
* - ``__AMDGCN_UNSAFE_FP_ATOMICS__``
|
||||
- Defined if unsafe floating-point atomics are allowed.
|
||||
* - ``__HAS_FMAF__``
|
||||
- Defined if FMAF instruction is available (deprecated).
|
||||
* - ``__HAS_LDEXPF__``
|
||||
- Defined if LDEXPF instruction is available (deprecated).
|
||||
* - ``__HAS_FP64__``
|
||||
- Defined if FP64 instruction is available (deprecated).
|
||||
| Macro | Description |
|
||||
| --- | --- |
|
||||
| `__AMDGPU__` | Indicates that the code is being compiled for an AMD GPU. |
|
||||
| `__AMDGCN__` | Defined if the GPU target is AMDGCN. |
|
||||
| `__R600__` | Defined if the GPU target is R600. |
|
||||
| `__<ArchName>__` | Defined with the name of the architecture (e.g., `__gfx906__` for the gfx906 architecture). |
|
||||
| `__<GFXN>__` | Defines the GFX family (e.g., for gfx906, this macro would be `__GFX9__`). |
|
||||
| `__amdgcn_processor__` | Defined with the processor name as a string (e.g., `"gfx906"`). |
|
||||
| `__amdgcn_target_id__` | Defined with the target ID as a string. |
|
||||
| `__amdgcn_feature_<feature-name>__` | Defined for each supported target feature. The value is 1 if the feature is enabled and 0 if it is disabled. Allowed feature names are sramecc and xnack. |
|
||||
| `__AMDGCN_CUMODE__` | Defined as 1 if the CU mode is enabled and 0 if the WGP mode is enabled. |
|
||||
| `__AMDGCN_UNSAFE_FP_ATOMICS__` | Defined if unsafe floating-point atomics are allowed. |
|
||||
| `__HAS_FMAF__` | Defined if FMAF instruction is available (deprecated). |
|
||||
| `__HAS_LDEXPF__` | Defined if LDEXPF instruction is available (deprecated). |
|
||||
| `__HAS_FP64__` | Defined if FP64 instruction is available (deprecated). |
|
||||
|
||||
Please note that the specific architecture and feature names will vary depending on the GPU. Also, some macros are deprecated and may be removed in future releases.
|
||||
|
||||
|
||||
Target-Specific Builtins
|
||||
========================
|
||||
## Target-Specific Builtins
|
||||
|
||||
Clang exposes AMDGPU hardware intrinsics as target-specific builtins with the
|
||||
``__builtin_amdgcn_`` prefix. These are documented in :doc:`AMDGPUBuiltinReference`.
|
||||
`__builtin_amdgcn_` prefix. These are documented in {doc}`AMDGPUBuiltinReference`.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
================================================
|
||||
API Notes: Annotations Without Modifying Headers
|
||||
================================================
|
||||
# API Notes: Annotations Without Modifying Headers
|
||||
|
||||
**The Problem:** You have headers you want to use, but you also want to add
|
||||
extra information to the API. You don't want to put that information in the
|
||||
|
|
@ -11,9 +9,9 @@ want to modify them at all.
|
|||
**Incomplete solution:** Redeclare all the interesting parts of the API in your
|
||||
own header and add the attributes you want. Unfortunately, this:
|
||||
|
||||
* doesn't work with attributes that must be present on a definition
|
||||
* doesn't allow changing the definition in other ways
|
||||
* requires your header to be included in any client code to take effect
|
||||
- doesn't work with attributes that must be present on a definition
|
||||
- doesn't allow changing the definition in other ways
|
||||
- requires your header to be included in any client code to take effect
|
||||
|
||||
**Better solution:** Provide a "sidecar" file with the information you want to
|
||||
add, and have that automatically get picked up by the module-building logic in
|
||||
|
|
@ -22,14 +20,11 @@ the compiler.
|
|||
That's API notes.
|
||||
|
||||
API notes use a YAML-based file format. YAML is a format best explained by
|
||||
example, so here is a `small example
|
||||
<https://github.com/llvm/llvm-project/blob/main/clang/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.apinotes>`_
|
||||
example, so here is a [small example](https://github.com/llvm/llvm-project/blob/main/clang/test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.apinotes)
|
||||
from the compiler test suite of API
|
||||
notes for a hypothetical "SomeKit" framework.
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
## Usage
|
||||
|
||||
API notes files are found relative to the module map that defines a module,
|
||||
under the name "SomeKit.apinotes" for a module named "SomeKit". Additionally, a
|
||||
|
|
@ -42,34 +37,30 @@ PrivateHeaders directory as well, though it does not need an additional
|
|||
"_private" suffix on its name.
|
||||
|
||||
Clang will search for API notes files next to module maps only when passed the
|
||||
``-fapinotes-modules`` option.
|
||||
`-fapinotes-modules` option.
|
||||
|
||||
|
||||
Limitations
|
||||
===========
|
||||
## Limitations
|
||||
|
||||
- Since they're identified by module name, API notes cannot be used to modify
|
||||
arbitrary textual headers.
|
||||
|
||||
|
||||
"Versioned" API Notes
|
||||
=====================
|
||||
## "Versioned" API Notes
|
||||
|
||||
Many API notes affect how a C API is imported into Swift. In order to change
|
||||
that behavior while still remaining backwards-compatible, API notes can be
|
||||
selectively applied based on the Swift compatibility version provided to the
|
||||
compiler (e.g. ``-fapi-notes-swift-version=5``). The rule is that an
|
||||
compiler (e.g. `-fapi-notes-swift-version=5`). The rule is that an
|
||||
explicitly-versioned API note applies to that version *and all earlier
|
||||
versions,* and any applicable explicitly-versioned API note takes precedence
|
||||
over an unversioned API note.
|
||||
|
||||
|
||||
Reference
|
||||
=========
|
||||
## Reference
|
||||
|
||||
An API notes file contains a YAML dictionary with the following top-level
|
||||
entries:
|
||||
|
||||
```{eval-rst}
|
||||
|
||||
:Name:
|
||||
|
||||
The name of the module (the framework name, for frameworks). Note that this
|
||||
|
|
@ -513,3 +504,4 @@ declaration kind), all of which are optional:
|
|||
- Selector: "initWithFrame:"
|
||||
MethodKind: Instance
|
||||
DesignatedInit: true
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
=================
|
||||
Allocation Tokens
|
||||
=================
|
||||
# Allocation Tokens
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
```{contents}
|
||||
:local: true
|
||||
```
|
||||
|
||||
Introduction
|
||||
============
|
||||
## Introduction
|
||||
|
||||
Clang provides support for allocation tokens to enable allocator-level heap
|
||||
organization strategies. Clang assigns mode-dependent token IDs to allocation
|
||||
|
|
@ -15,55 +13,49 @@ compatible memory allocator.
|
|||
|
||||
Possible allocator strategies include:
|
||||
|
||||
* **Security Hardening**: Placing allocations into separate, isolated heap
|
||||
- **Security Hardening**: Placing allocations into separate, isolated heap
|
||||
partitions. For example, separating pointer-containing types from raw data
|
||||
can mitigate exploits that rely on overflowing a primitive buffer to corrupt
|
||||
object metadata.
|
||||
|
||||
* **Memory Layout Optimization**: Grouping related allocations to improve data
|
||||
- **Memory Layout Optimization**: Grouping related allocations to improve data
|
||||
locality and cache utilization.
|
||||
|
||||
* **Custom Allocation Policies**: Applying different management strategies to
|
||||
- **Custom Allocation Policies**: Applying different management strategies to
|
||||
different partitions.
|
||||
|
||||
Token Assignment Mode
|
||||
=====================
|
||||
## Token Assignment Mode
|
||||
|
||||
The default mode to calculate tokens is:
|
||||
|
||||
* ``typehashpointersplit``: This mode assigns a token ID based on the hash of
|
||||
- `typehashpointersplit`: This mode assigns a token ID based on the hash of
|
||||
the allocated type's name, where the top half ID-space is reserved for types
|
||||
that contain pointers and the bottom half for types that do not contain
|
||||
pointers.
|
||||
|
||||
Other token ID assignment modes are supported, but they may be subject to
|
||||
change or removal. These may (experimentally) be selected with ``-Xclang
|
||||
-falloc-token-mode=<mode>``:
|
||||
change or removal. These may (experimentally) be selected with `-Xclang
|
||||
-falloc-token-mode=<mode>`:
|
||||
|
||||
* ``typehash``: This mode assigns a token ID based on the hash of the allocated
|
||||
- `typehash`: This mode assigns a token ID based on the hash of the allocated
|
||||
type's name.
|
||||
|
||||
* ``random``: This mode assigns a statically-determined random token ID to each
|
||||
- `random`: This mode assigns a statically-determined random token ID to each
|
||||
allocation site.
|
||||
|
||||
* ``increment``: This mode assigns a simple, incrementally increasing token ID
|
||||
- `increment`: This mode assigns a simple, incrementally increasing token ID
|
||||
to each allocation site.
|
||||
|
||||
The following command-line options affect generated token IDs:
|
||||
|
||||
* ``-falloc-token-max=<N>``
|
||||
Configures the maximum number of token IDs. By default the number of tokens
|
||||
is bounded by ``SIZE_MAX``.
|
||||
- `-falloc-token-max=<N>`
|
||||
: Configures the maximum number of token IDs. By default the number of tokens
|
||||
is bounded by `SIZE_MAX`.
|
||||
|
||||
Querying Token IDs with ``__builtin_infer_alloc_token``
|
||||
=======================================================
|
||||
## Querying Token IDs with `__builtin_infer_alloc_token`
|
||||
|
||||
For use cases where the token ID must be known at compile time, Clang provides
|
||||
a builtin function:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
size_t __builtin_infer_alloc_token(<args>, ...);
|
||||
```c
|
||||
size_t __builtin_infer_alloc_token(<args>, ...);
|
||||
```
|
||||
|
||||
This builtin returns the token ID inferred from its argument expressions, which
|
||||
mirror arguments normally passed to any allocation function. The argument
|
||||
|
|
@ -72,168 +64,162 @@ have side effects without any runtime impact.
|
|||
|
||||
For example, it can be used as follows:
|
||||
|
||||
.. code-block:: c
|
||||
```c
|
||||
struct MyType { ... };
|
||||
void *__partition_alloc(size_t size, size_t partition);
|
||||
#define partition_alloc(...) __partition_alloc(__VA_ARGS__, __builtin_infer_alloc_token(__VA_ARGS__))
|
||||
|
||||
struct MyType { ... };
|
||||
void *__partition_alloc(size_t size, size_t partition);
|
||||
#define partition_alloc(...) __partition_alloc(__VA_ARGS__, __builtin_infer_alloc_token(__VA_ARGS__))
|
||||
void foo(void) {
|
||||
MyType *x = partition_alloc(sizeof(*x));
|
||||
}
|
||||
```
|
||||
|
||||
void foo(void) {
|
||||
MyType *x = partition_alloc(sizeof(*x));
|
||||
}
|
||||
|
||||
Allocation Token Instrumentation
|
||||
================================
|
||||
## Allocation Token Instrumentation
|
||||
|
||||
To enable instrumentation of allocation functions, code can be compiled with
|
||||
the ``-fsanitize=alloc-token`` flag:
|
||||
the `-fsanitize=alloc-token` flag:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% clang++ -fsanitize=alloc-token example.cc
|
||||
```console
|
||||
% clang++ -fsanitize=alloc-token example.cc
|
||||
```
|
||||
|
||||
The instrumentation transforms allocation calls to include a token ID. For
|
||||
example:
|
||||
|
||||
.. code-block:: c
|
||||
```c
|
||||
// Original:
|
||||
ptr = malloc(size);
|
||||
|
||||
// Original:
|
||||
ptr = malloc(size);
|
||||
// Instrumented:
|
||||
ptr = __alloc_token_malloc(size, <token id>);
|
||||
```
|
||||
|
||||
// Instrumented:
|
||||
ptr = __alloc_token_malloc(size, <token id>);
|
||||
|
||||
Runtime Interface
|
||||
-----------------
|
||||
### Runtime Interface
|
||||
|
||||
A compatible runtime must be provided that implements the token-enabled
|
||||
allocation functions. The instrumentation generates calls to functions that
|
||||
take a final ``size_t token_id`` argument.
|
||||
take a final `size_t token_id` argument.
|
||||
|
||||
.. code-block:: c
|
||||
```c
|
||||
// C standard library functions
|
||||
void *__alloc_token_malloc(size_t size, size_t token_id);
|
||||
void *__alloc_token_calloc(size_t count, size_t size, size_t token_id);
|
||||
void *__alloc_token_realloc(void *ptr, size_t size, size_t token_id);
|
||||
// ...
|
||||
|
||||
// C standard library functions
|
||||
void *__alloc_token_malloc(size_t size, size_t token_id);
|
||||
void *__alloc_token_calloc(size_t count, size_t size, size_t token_id);
|
||||
void *__alloc_token_realloc(void *ptr, size_t size, size_t token_id);
|
||||
// ...
|
||||
// C++ operators (mangled names)
|
||||
// operator new(size_t, size_t)
|
||||
void *__alloc_token__Znwm(size_t size, size_t token_id);
|
||||
// operator new[](size_t, size_t)
|
||||
void *__alloc_token__Znam(size_t size, size_t token_id);
|
||||
// ... other variants like nothrow, etc., are also instrumented.
|
||||
```
|
||||
|
||||
// C++ operators (mangled names)
|
||||
// operator new(size_t, size_t)
|
||||
void *__alloc_token__Znwm(size_t size, size_t token_id);
|
||||
// operator new[](size_t, size_t)
|
||||
void *__alloc_token__Znam(size_t size, size_t token_id);
|
||||
// ... other variants like nothrow, etc., are also instrumented.
|
||||
### Fast ABI
|
||||
|
||||
Fast ABI
|
||||
--------
|
||||
|
||||
An alternative ABI can be enabled with ``-fsanitize-alloc-token-fast-abi``,
|
||||
An alternative ABI can be enabled with `-fsanitize-alloc-token-fast-abi`,
|
||||
which encodes the token ID in the allocation function name.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void *__alloc_token_0_malloc(size_t size);
|
||||
void *__alloc_token_1_malloc(size_t size);
|
||||
void *__alloc_token_2_malloc(size_t size);
|
||||
...
|
||||
void *__alloc_token_0_Znwm(size_t size);
|
||||
void *__alloc_token_1_Znwm(size_t size);
|
||||
void *__alloc_token_2_Znwm(size_t size);
|
||||
...
|
||||
```c
|
||||
void *__alloc_token_0_malloc(size_t size);
|
||||
void *__alloc_token_1_malloc(size_t size);
|
||||
void *__alloc_token_2_malloc(size_t size);
|
||||
...
|
||||
void *__alloc_token_0_Znwm(size_t size);
|
||||
void *__alloc_token_1_Znwm(size_t size);
|
||||
void *__alloc_token_2_Znwm(size_t size);
|
||||
...
|
||||
```
|
||||
|
||||
This ABI provides a more efficient alternative where
|
||||
``-falloc-token-max`` is small.
|
||||
`-falloc-token-max` is small.
|
||||
|
||||
Instrumenting Non-Standard Allocation Functions
|
||||
-----------------------------------------------
|
||||
### Instrumenting Non-Standard Allocation Functions
|
||||
|
||||
By default, AllocToken only instruments standard library allocation functions.
|
||||
This simplifies adoption, as a compatible allocator only needs to provide
|
||||
token-enabled variants for a well-defined set of standard functions.
|
||||
|
||||
To extend instrumentation to custom allocation functions, enable broader
|
||||
coverage with ``-fsanitize-alloc-token-extended``. Such functions require being
|
||||
marked with the `malloc
|
||||
<https://clang.llvm.org/docs/AttributeReference.html#malloc>`_ or `alloc_size
|
||||
<https://clang.llvm.org/docs/AttributeReference.html#alloc-size>`_ attributes
|
||||
coverage with `-fsanitize-alloc-token-extended`. Such functions require being
|
||||
marked with the [malloc][malloc-attribute] or
|
||||
[alloc_size][alloc-size-attribute] attributes
|
||||
(or a combination).
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
```c
|
||||
void *custom_malloc(size_t size) __attribute__((malloc));
|
||||
void *my_malloc(size_t size) __attribute__((alloc_size(1)));
|
||||
|
||||
void *custom_malloc(size_t size) __attribute__((malloc));
|
||||
void *my_malloc(size_t size) __attribute__((alloc_size(1)));
|
||||
// Original:
|
||||
ptr1 = custom_malloc(size);
|
||||
ptr2 = my_malloc(size);
|
||||
|
||||
// Original:
|
||||
ptr1 = custom_malloc(size);
|
||||
ptr2 = my_malloc(size);
|
||||
// Instrumented:
|
||||
ptr1 = __alloc_token_custom_malloc(size, token_id);
|
||||
ptr2 = __alloc_token_my_malloc(size, token_id);
|
||||
```
|
||||
|
||||
// Instrumented:
|
||||
ptr1 = __alloc_token_custom_malloc(size, token_id);
|
||||
ptr2 = __alloc_token_my_malloc(size, token_id);
|
||||
|
||||
Note: Even in the default mode (without ``-fsanitize-alloc-token-extended``),
|
||||
an *inline* allocation wrapper marked with the `malloc
|
||||
<https://clang.llvm.org/docs/AttributeReference.html#malloc>`_ or `alloc_size
|
||||
<https://clang.llvm.org/docs/AttributeReference.html#alloc-size>`_ attribute is
|
||||
Note: Even in the default mode (without `-fsanitize-alloc-token-extended`),
|
||||
an *inline* allocation wrapper marked with the [malloc][malloc-attribute] or
|
||||
[alloc_size][alloc-size-attribute] attribute is
|
||||
supported if it is inlined into its caller: the inferred token is propagated to
|
||||
the allocation call the wrapper returns, which is then instrumented normally.
|
||||
Wrappers that are not inlined still require
|
||||
``-fsanitize-alloc-token-extended``.
|
||||
`-fsanitize-alloc-token-extended`.
|
||||
|
||||
Disabling Instrumentation
|
||||
-------------------------
|
||||
[malloc-attribute]: https://clang.llvm.org/docs/AttributeReference.html#malloc
|
||||
[alloc-size-attribute]: https://clang.llvm.org/docs/AttributeReference.html#alloc-size
|
||||
|
||||
### Disabling Instrumentation
|
||||
|
||||
To exclude specific functions from instrumentation, you can use the
|
||||
``no_sanitize("alloc-token")`` attribute:
|
||||
`no_sanitize("alloc-token")` attribute:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
__attribute__((no_sanitize("alloc-token")))
|
||||
void* custom_allocator(size_t size) {
|
||||
return malloc(size); // Uses original malloc
|
||||
}
|
||||
```c
|
||||
__attribute__((no_sanitize("alloc-token")))
|
||||
void* custom_allocator(size_t size) {
|
||||
return malloc(size); // Uses original malloc
|
||||
}
|
||||
```
|
||||
|
||||
Note: Independent of any given allocator support, the instrumentation aims to
|
||||
remain performance neutral. As such, ``no_sanitize("alloc-token")``
|
||||
remain performance neutral. As such, `no_sanitize("alloc-token")`
|
||||
functions may be inlined into instrumented functions and vice-versa. If
|
||||
correctness is affected, such functions should explicitly be marked
|
||||
``noinline``.
|
||||
`noinline`.
|
||||
|
||||
The ``__attribute__((disable_sanitizer_instrumentation))`` is also supported to
|
||||
The `__attribute__((disable_sanitizer_instrumentation))` is also supported to
|
||||
disable this and other sanitizer instrumentations.
|
||||
|
||||
Suppressions File (Ignorelist)
|
||||
------------------------------
|
||||
### Suppressions File (Ignorelist)
|
||||
|
||||
AllocToken respects the ``src`` and ``fun`` entity types in the
|
||||
:doc:`SanitizerSpecialCaseList`, which can be used to omit specified source
|
||||
AllocToken respects the `src` and `fun` entity types in the
|
||||
{doc}`SanitizerSpecialCaseList`, which can be used to omit specified source
|
||||
files or functions from instrumentation.
|
||||
|
||||
.. code-block:: bash
|
||||
```bash
|
||||
[alloc-token]
|
||||
# Exclude specific source files
|
||||
src:third_party/allocator.c
|
||||
# Exclude function name patterns
|
||||
fun:*custom_malloc*
|
||||
fun:LowLevel::*
|
||||
```
|
||||
|
||||
[alloc-token]
|
||||
# Exclude specific source files
|
||||
src:third_party/allocator.c
|
||||
# Exclude function name patterns
|
||||
fun:*custom_malloc*
|
||||
fun:LowLevel::*
|
||||
```console
|
||||
% clang++ -fsanitize=alloc-token -fsanitize-ignorelist=my_ignorelist.txt example.cc
|
||||
```
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% clang++ -fsanitize=alloc-token -fsanitize-ignorelist=my_ignorelist.txt example.cc
|
||||
|
||||
Conditional Compilation with ``__SANITIZE_ALLOC_TOKEN__``
|
||||
-----------------------------------------------------------
|
||||
### Conditional Compilation with `__SANITIZE_ALLOC_TOKEN__`
|
||||
|
||||
In some cases, one may need to execute different code depending on whether
|
||||
AllocToken instrumentation is enabled. The ``__SANITIZE_ALLOC_TOKEN__`` macro
|
||||
AllocToken instrumentation is enabled. The `__SANITIZE_ALLOC_TOKEN__` macro
|
||||
can be used for this purpose.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#ifdef __SANITIZE_ALLOC_TOKEN__
|
||||
// Code specific to -fsanitize=alloc-token builds
|
||||
#endif
|
||||
```c
|
||||
#ifdef __SANITIZE_ALLOC_TOKEN__
|
||||
// Code specific to -fsanitize=alloc-token builds
|
||||
#endif
|
||||
```
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,90 +1,82 @@
|
|||
======================================
|
||||
Adoption Guide for ``-fbounds-safety``
|
||||
======================================
|
||||
# Adoption Guide for `-fbounds-safety`
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
```{contents}
|
||||
:local: true
|
||||
```
|
||||
|
||||
Where to get ``-fbounds-safety``
|
||||
================================
|
||||
## Where to get `-fbounds-safety`
|
||||
|
||||
The open sourcing to llvm.org's ``llvm-project`` is still on going and the
|
||||
The open sourcing to llvm.org's `llvm-project` is still on going and the
|
||||
feature is not available yet. In the mean time, the preview implementation is
|
||||
available
|
||||
`here <https://github.com/swiftlang/llvm-project/tree/stable/20240723>`_ in a
|
||||
fork of ``llvm-project``. Please follow
|
||||
`Building LLVM with CMake <https://llvm.org/docs/CMake.html>`_ to build the
|
||||
[here](https://github.com/swiftlang/llvm-project/tree/stable/20240723) in a
|
||||
fork of `llvm-project`. Please follow
|
||||
[Building LLVM with CMake](https://llvm.org/docs/CMake.html) to build the
|
||||
compiler.
|
||||
|
||||
Feature flag
|
||||
============
|
||||
## Feature flag
|
||||
|
||||
Pass ``-fbounds-safety`` as a Clang compilation flag for the C file that you
|
||||
Pass `-fbounds-safety` as a Clang compilation flag for the C file that you
|
||||
want to adopt. We recommend adopting the model file by file, because adoption
|
||||
requires some effort to add bounds annotations and fix compiler diagnostics.
|
||||
|
||||
Include ``ptrcheck.h``
|
||||
======================
|
||||
## Include `ptrcheck.h`
|
||||
|
||||
``ptrcheck.h`` is a Clang toolchain header to provide definition of the bounds
|
||||
annotations such as ``__counted_by``, ``__counted_by_or_null``, ``__sized_by``,
|
||||
`ptrcheck.h` is a Clang toolchain header to provide definition of the bounds
|
||||
annotations such as `__counted_by`, `__counted_by_or_null`, `__sized_by`,
|
||||
etc. In the LLVM source tree, the header is located in
|
||||
``llvm-project/clang/lib/Headers/ptrcheck.h``.
|
||||
`llvm-project/clang/lib/Headers/ptrcheck.h`.
|
||||
|
||||
|
||||
Add bounds annotations on pointers as necessary
|
||||
===============================================
|
||||
## Add bounds annotations on pointers as necessary
|
||||
|
||||
Annotate pointers on struct fields and function parameters if they are pointing
|
||||
to an array of object, with appropriate bounds annotations. Please see
|
||||
:doc:`BoundsSafety` to learn what kind of bounds annotations are available and
|
||||
{doc}`BoundsSafety` to learn what kind of bounds annotations are available and
|
||||
their semantics. Note that local pointer variables typically don't need bounds
|
||||
annotations because they are implicitly a wide pointer (``__bidi_indexable``)
|
||||
annotations because they are implicitly a wide pointer (`__bidi_indexable`)
|
||||
that automatically carries the bounds information.
|
||||
|
||||
Address compiler diagnostics
|
||||
============================
|
||||
## Address compiler diagnostics
|
||||
|
||||
Once you pass ``-fbounds-safety`` to compile a C file, you will see some new
|
||||
compiler warnings and errors, which guide adoption of ``-fbounds-safety``.
|
||||
Once you pass `-fbounds-safety` to compile a C file, you will see some new
|
||||
compiler warnings and errors, which guide adoption of `-fbounds-safety`.
|
||||
Consider the following example:
|
||||
|
||||
.. code-block:: c
|
||||
```c
|
||||
#include <ptrcheck.h>
|
||||
|
||||
#include <ptrcheck.h>
|
||||
void init_buf(int *p, int n) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
p[i] = 0; // error: array subscript on single pointer 'p' must use a constant index of 0 to be in bounds
|
||||
}
|
||||
```
|
||||
|
||||
void init_buf(int *p, int n) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
p[i] = 0; // error: array subscript on single pointer 'p' must use a constant index of 0 to be in bounds
|
||||
}
|
||||
|
||||
The parameter ``int *p`` doesn't have a bounds annotation, so the compiler will
|
||||
complain about the code indexing into it (``p[i]``) as it assumes that ``p`` is
|
||||
pointing to a single ``int`` object or null. To address the diagnostics, you
|
||||
should add a bounds annotation on ``int *p`` so that the compiler can reason
|
||||
about the safety of the array subscript. In the following example, ``p`` is now
|
||||
``int *__counted_by(n)``, so the compiler will allow the array subscript with
|
||||
The parameter `int *p` doesn't have a bounds annotation, so the compiler will
|
||||
complain about the code indexing into it (`p[i]`) as it assumes that `p` is
|
||||
pointing to a single `int` object or null. To address the diagnostics, you
|
||||
should add a bounds annotation on `int *p` so that the compiler can reason
|
||||
about the safety of the array subscript. In the following example, `p` is now
|
||||
`int *__counted_by(n)`, so the compiler will allow the array subscript with
|
||||
additional run-time checks as necessary.
|
||||
|
||||
.. code-block:: c
|
||||
```c
|
||||
#include <ptrcheck.h>
|
||||
|
||||
#include <ptrcheck.h>
|
||||
void init_buf(int *__counted_by(n) p, int n) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
p[i] = 0; // ok; `p` is now has a type with bounds annotation.
|
||||
}
|
||||
```
|
||||
|
||||
void init_buf(int *__counted_by(n) p, int n) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
p[i] = 0; // ok; `p` is now has a type with bounds annotation.
|
||||
}
|
||||
## Run test suites to fix new run-time traps
|
||||
|
||||
Run test suites to fix new run-time traps
|
||||
=========================================
|
||||
|
||||
Adopting ``-fbounds-safety`` may cause your program to trap if it violates
|
||||
Adopting `-fbounds-safety` may cause your program to trap if it violates
|
||||
bounds safety or it has incorrect adoption. Thus, it is necessary to perform
|
||||
run-time testing of your program to gain confidence that it won't trap at
|
||||
run time.
|
||||
|
||||
Repeat the process for each remaining file
|
||||
==========================================
|
||||
## Repeat the process for each remaining file
|
||||
|
||||
Once you've done with adopting a single C file, please repeat the same process
|
||||
for each remaining C file that you want to adopt.
|
||||
for each remaining C file that you want to adopt.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,60 +1,53 @@
|
|||
============================================
|
||||
Implementation plans for ``-fbounds-safety``
|
||||
============================================
|
||||
# Implementation plans for `-fbounds-safety`
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
```{contents}
|
||||
:local: true
|
||||
```
|
||||
|
||||
Gradual updates with experimental flag
|
||||
======================================
|
||||
## Gradual updates with experimental flag
|
||||
|
||||
The feature will be implemented as a series of smaller PRs and we will guard our
|
||||
implementation with an experimental flag ``-fexperimental-bounds-safety`` until
|
||||
implementation with an experimental flag `-fexperimental-bounds-safety` until
|
||||
the usable model is fully available. Once the model is ready for use, we will
|
||||
expose the flag ``-fbounds-safety``.
|
||||
expose the flag `-fbounds-safety`.
|
||||
|
||||
Possible patch sets
|
||||
-------------------
|
||||
### Possible patch sets
|
||||
|
||||
* External bounds annotations and the (late) parsing logic.
|
||||
* Internal bounds annotations (wide pointers) and their parsing logic.
|
||||
* Clang code generation for wide pointers with debug information.
|
||||
* Pointer cast semantics involving bounds annotations (this could be divided
|
||||
- External bounds annotations and the (late) parsing logic.
|
||||
- Internal bounds annotations (wide pointers) and their parsing logic.
|
||||
- Clang code generation for wide pointers with debug information.
|
||||
- Pointer cast semantics involving bounds annotations (this could be divided
|
||||
into multiple sub-PRs).
|
||||
* CFG analysis for pairs of related pointer and count assignments and the likes.
|
||||
* Bounds check expressions in AST and the Clang code generation (this could also
|
||||
- CFG analysis for pairs of related pointer and count assignments and the likes.
|
||||
- Bounds check expressions in AST and the Clang code generation (this could also
|
||||
be divided into multiple sub-PRs).
|
||||
|
||||
Proposed implementation
|
||||
=======================
|
||||
## Proposed implementation
|
||||
|
||||
External bounds annotations
|
||||
---------------------------
|
||||
### External bounds annotations
|
||||
|
||||
The bounds annotations are C type attributes appertaining to pointer types. If
|
||||
an attribute is added to the position of a declaration attribute, e.g., ``int
|
||||
*ptr __counted_by(size)``, the attribute appertains to the outermost pointer
|
||||
type of the declaration (``int *``).
|
||||
an attribute is added to the position of a declaration attribute, e.g., `int
|
||||
*ptr __counted_by(size)`, the attribute appertains to the outermost pointer
|
||||
type of the declaration (`int *`).
|
||||
|
||||
New sugar types
|
||||
---------------
|
||||
### New sugar types
|
||||
|
||||
An external bounds annotation creates a type sugar of the underlying pointer
|
||||
types. We will introduce a new sugar type, ``DynamicBoundsPointerType`` to
|
||||
represent ``__counted_by`` or ``__sized_by``. Using ``AttributedType`` would not
|
||||
types. We will introduce a new sugar type, `DynamicBoundsPointerType` to
|
||||
represent `__counted_by` or `__sized_by`. Using `AttributedType` would not
|
||||
be sufficient because the type needs to hold the count or size expression as
|
||||
well as some metadata necessary for analysis, while this type may be implemented
|
||||
through inheritance from ``AttributedType``. Treating the annotations as type
|
||||
through inheritance from `AttributedType`. Treating the annotations as type
|
||||
sugars means two types with incompatible external bounds annotations may be
|
||||
considered canonically the same types. This is sometimes necessary, for example,
|
||||
to make the ``__counted_by`` and friends not participate in function
|
||||
to make the `__counted_by` and friends not participate in function
|
||||
overloading. However, this design requires a separate logic to walk through the
|
||||
entire type hierarchy to check type compatibility of bounds annotations.
|
||||
|
||||
Late parsing for C
|
||||
------------------
|
||||
### Late parsing for C
|
||||
|
||||
A bounds annotation such as ``__counted_by(count)`` can be added to type of a
|
||||
A bounds annotation such as `__counted_by(count)` can be added to type of a
|
||||
struct field declaration where count is another field of the same struct
|
||||
declared later. Similarly, the annotation may apply to type of a function
|
||||
parameter declaration which precedes the parameter count in the same function.
|
||||
|
|
@ -65,14 +58,13 @@ while the C declaration attributes and C/C++ type attributes do not have the
|
|||
same logic. This requires introducing late parsing logic for C/C++ type
|
||||
attributes.
|
||||
|
||||
Internal bounds annotations
|
||||
---------------------------
|
||||
### Internal bounds annotations
|
||||
|
||||
``__indexable`` and ``__bidi_indexable`` alter pointer representations to be
|
||||
`__indexable` and `__bidi_indexable` alter pointer representations to be
|
||||
equivalent to a struct with the pointer and the corresponding bounds fields.
|
||||
Despite this difference in their representations, they are still pointers in
|
||||
terms of types of operations that are allowed and their semantics. For instance,
|
||||
a pointer dereference on a ``__bidi_indexable`` pointer will return the
|
||||
a pointer dereference on a `__bidi_indexable` pointer will return the
|
||||
dereferenced value same as plain C pointers, modulo the extra bounds checks
|
||||
being performed before dereferencing the wide pointer. This means mapping the
|
||||
wide pointers to struct types with equivalent layout won’t be sufficient. To
|
||||
|
|
@ -83,16 +75,15 @@ while they are still treated as pointers.
|
|||
|
||||
In LLVM IR, wide pointers will be emitted as structs of equivalent
|
||||
representations. Clang CodeGen will handle them as Aggregate in
|
||||
``TypeEvaluationKind (TEK)``. ``AggExprEmitter`` was extended to handle pointer
|
||||
operations returning wide pointers. Alternatively, a new ``TEK`` and an
|
||||
`TypeEvaluationKind (TEK)`. `AggExprEmitter` was extended to handle pointer
|
||||
operations returning wide pointers. Alternatively, a new `TEK` and an
|
||||
expression emitter dedicated to wide pointers could be introduced.
|
||||
|
||||
Default bounds annotations
|
||||
--------------------------
|
||||
### Default bounds annotations
|
||||
|
||||
The model may implicitly add ``__bidi_indexable`` or ``__single`` depending on
|
||||
the context of the declaration that has the pointer type. ``__bidi_indexable``
|
||||
implicitly adds to local variables, while ``__single`` implicitly adds to
|
||||
The model may implicitly add `__bidi_indexable` or `__single` depending on
|
||||
the context of the declaration that has the pointer type. `__bidi_indexable`
|
||||
implicitly adds to local variables, while `__single` implicitly adds to
|
||||
pointer types specifying struct fields, function parameters, or global
|
||||
variables. This means the parser may first create the pointer type without any
|
||||
default pointer attribute and then recreate the type once the parser has the
|
||||
|
|
@ -101,154 +92,144 @@ declaration context and determined the default attribute accordingly.
|
|||
This also requires the parser to reset the type of the declaration with the
|
||||
newly created type with the right default attribute.
|
||||
|
||||
Promotion expression
|
||||
--------------------
|
||||
### Promotion expression
|
||||
|
||||
A new expression will be introduced to represent the conversion from a pointer
|
||||
with an external bounds annotation, such as ``__counted_by``, to
|
||||
``__bidi_indexable``. This type of conversion cannot be handled by normal
|
||||
with an external bounds annotation, such as `__counted_by`, to
|
||||
`__bidi_indexable`. This type of conversion cannot be handled by normal
|
||||
CastExprs because it requires an extra subexpression(s) to provide the bounds
|
||||
information necessary to create a wide pointer.
|
||||
|
||||
Bounds check expression
|
||||
-----------------------
|
||||
### Bounds check expression
|
||||
|
||||
Bounds checks are part of semantics defined in the ``-fbounds-safety`` language
|
||||
Bounds checks are part of semantics defined in the `-fbounds-safety` language
|
||||
model. Hence, exposing the bounds checks and other semantic actions in the AST
|
||||
is desirable. A new expression for bounds checks has been added to the AST. The
|
||||
bounds check expression has a ``BoundsCheckKind`` to indicate the kind of checks
|
||||
bounds check expression has a `BoundsCheckKind` to indicate the kind of checks
|
||||
and has the additional sub-expressions that are necessary to perform the check
|
||||
according to the kind.
|
||||
|
||||
Paired assignment check
|
||||
-----------------------
|
||||
### Paired assignment check
|
||||
|
||||
``-fbounds-safety`` enforces that variables or fields related with the same
|
||||
external bounds annotation (e.g., ``buf`` and ``count`` related with
|
||||
``__counted_by`` in the example below) must be updated side by side within the
|
||||
`-fbounds-safety` enforces that variables or fields related with the same
|
||||
external bounds annotation (e.g., `buf` and `count` related with
|
||||
`__counted_by` in the example below) must be updated side by side within the
|
||||
same basic block and without side effect in between.
|
||||
|
||||
.. code-block:: c
|
||||
```c
|
||||
typedef struct {
|
||||
int *__counted_by(count) buf; size_t count;
|
||||
} sized_buf_t;
|
||||
|
||||
typedef struct {
|
||||
int *__counted_by(count) buf; size_t count;
|
||||
} sized_buf_t;
|
||||
|
||||
void alloc_buf(sized_buf_t *sbuf, size_t nelems) {
|
||||
sbuf->buf = (int *)malloc(sizeof(int) * nelems);
|
||||
sbuf->count = nelems;
|
||||
}
|
||||
void alloc_buf(sized_buf_t *sbuf, size_t nelems) {
|
||||
sbuf->buf = (int *)malloc(sizeof(int) * nelems);
|
||||
sbuf->count = nelems;
|
||||
}
|
||||
```
|
||||
|
||||
To implement this rule, the compiler requires a linear representation of
|
||||
statements to understand the ordering and the adjacency between the two or more
|
||||
assignments. The Clang CFG is used to implement this analysis as Clang CFG
|
||||
provides a linear view of statements within each ``CFGBlock`` (Clang
|
||||
``CFGBlock`` represents a single basic block in a source-level CFG).
|
||||
provides a linear view of statements within each `CFGBlock` (Clang
|
||||
`CFGBlock` represents a single basic block in a source-level CFG).
|
||||
|
||||
Bounds check optimizations
|
||||
--------------------------
|
||||
### Bounds check optimizations
|
||||
|
||||
In ``-fbounds-safety``, the Clang frontend emits run-time checks for every
|
||||
In `-fbounds-safety`, the Clang frontend emits run-time checks for every
|
||||
memory dereference if the type system or analyses in the frontend couldn’t
|
||||
verify its bounds safety. The implementation relies on LLVM optimizations to
|
||||
remove redundant run-time checks. Using this optimization strategy, if the
|
||||
original source code already has bounds checks, the fewer additional checks
|
||||
``-fbounds-safety`` will introduce. The LLVM ``ConstraintElimination`` pass is
|
||||
`-fbounds-safety` will introduce. The LLVM `ConstraintElimination` pass is
|
||||
designed to remove provable redundant checks (please check Florian Hahn’s
|
||||
presentation in 2021 LLVM Dev Meeting and the implementation to learn more). In
|
||||
the following example, ``-fbounds-safety`` implicitly adds the redundant bounds
|
||||
the following example, `-fbounds-safety` implicitly adds the redundant bounds
|
||||
checks that the optimizer can remove:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void fill_array_with_indices(int *__counted_by(count) p, size_t count) {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
// implicit bounds checks:
|
||||
// if (p + i < p || p + i + 1 > p + count) trap();
|
||||
p[i] = i;
|
||||
}
|
||||
```c
|
||||
void fill_array_with_indices(int *__counted_by(count) p, size_t count) {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
// implicit bounds checks:
|
||||
// if (p + i < p || p + i + 1 > p + count) trap();
|
||||
p[i] = i;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
``ConstraintElimination`` collects the following facts and determines if the
|
||||
`ConstraintElimination` collects the following facts and determines if the
|
||||
bounds checks can be safely removed:
|
||||
|
||||
* Inside the for-loop, ``0 <= i < count``, hence ``1 <= i + 1 <= count``.
|
||||
* Pointer arithmetic ``p + count`` in the if-condition doesn’t wrap.
|
||||
* ``-fbounds-safety`` treats pointer arithmetic overflow as deterministically
|
||||
- Inside the for-loop, `0 <= i < count`, hence `1 <= i + 1 <= count`.
|
||||
- Pointer arithmetic `p + count` in the if-condition doesn’t wrap.
|
||||
- `-fbounds-safety` treats pointer arithmetic overflow as deterministically
|
||||
two’s complement computation, not an undefined behavior. Therefore,
|
||||
getelementptr does not typically have inbounds keyword. However, the compiler
|
||||
does emit inbounds for ``p + count`` in this case because
|
||||
``__counted_by(count)`` has the invariant that p has at least as many as
|
||||
elements as count. Using this information, ``ConstraintElimination`` is able
|
||||
to determine ``p + count`` doesn’t wrap.
|
||||
* Accordingly, ``p + i`` and ``p + i + 1`` also don’t wrap.
|
||||
* Therefore, ``p <= p + i`` and ``p + i + 1 <= p + count``.
|
||||
* The if-condition simplifies to false and becomes dead code that the subsequent
|
||||
does emit inbounds for `p + count` in this case because
|
||||
`__counted_by(count)` has the invariant that p has at least as many as
|
||||
elements as count. Using this information, `ConstraintElimination` is able
|
||||
to determine `p + count` doesn’t wrap.
|
||||
- Accordingly, `p + i` and `p + i + 1` also don’t wrap.
|
||||
- Therefore, `p <= p + i` and `p + i + 1 <= p + count`.
|
||||
- The if-condition simplifies to false and becomes dead code that the subsequent
|
||||
optimization passes can remove.
|
||||
|
||||
``OptRemarks`` can be utilized to provide insights into performance tuning. It
|
||||
`OptRemarks` can be utilized to provide insights into performance tuning. It
|
||||
has the capability to report on checks that it cannot eliminate, possibly with
|
||||
reasons, allowing programmers to adjust their code to unlock further
|
||||
optimizations.
|
||||
|
||||
Debugging
|
||||
=========
|
||||
## Debugging
|
||||
|
||||
Internal bounds annotations
|
||||
---------------------------
|
||||
### Internal bounds annotations
|
||||
|
||||
Internal bounds annotations change a pointer into a wide pointer. The debugger
|
||||
needs to understand that wide pointers are essentially pointers with a struct
|
||||
layout. To handle this, a wide pointer is described as a record type in the
|
||||
debug info. The type name has a special name prefix (e.g.,
|
||||
``__bounds_safety$bidi_indexable``) which can be recognized by a debug info
|
||||
`__bounds_safety$bidi_indexable`) which can be recognized by a debug info
|
||||
consumer to provide support that goes beyond showing the internal structure of
|
||||
the wide pointer. There are no DWARF extensions needed to support wide pointers.
|
||||
In our implementation, LLDB recognizes wide pointer types by name and
|
||||
reconstructs them as wide pointer Clang AST types for use in the expression
|
||||
evaluator.
|
||||
|
||||
External bounds annotations
|
||||
---------------------------
|
||||
### External bounds annotations
|
||||
|
||||
Similar to internal bounds annotations, external bound annotations are described
|
||||
as a typedef to their underlying pointer type in the debug info, and the bounds
|
||||
are encoded as strings in the typedef’s name (e.g.,
|
||||
``__bounds_safety$counted_by:N``).
|
||||
`__bounds_safety$counted_by:N`).
|
||||
|
||||
Recognizing ``-fbounds-safety`` traps
|
||||
-------------------------------------
|
||||
### Recognizing `-fbounds-safety` traps
|
||||
|
||||
Clang emits debug info for ``-fbounds-safety`` traps as inlined functions, where
|
||||
Clang emits debug info for `-fbounds-safety` traps as inlined functions, where
|
||||
the function name encodes the error message. LLDB implements a frame recognizer
|
||||
to surface a human-readable error cause to the end user. A debug info consumer
|
||||
that is unaware of this sees an inlined function whose name encodes an error
|
||||
message (e.g., : ``__bounds_safety$Bounds check failed``).
|
||||
message (e.g., : `__bounds_safety$Bounds check failed`).
|
||||
|
||||
Expression Parsing
|
||||
------------------
|
||||
### Expression Parsing
|
||||
|
||||
In our implementation, LLDB’s expression evaluator does not enable the
|
||||
``-fbounds-safety`` language option because it’s currently unable to fully
|
||||
`-fbounds-safety` language option because it’s currently unable to fully
|
||||
reconstruct the pointers with external bounds annotations, and also because the
|
||||
evaluator operates in C++ mode, utilizing C++ reference types, while
|
||||
``-fbounds-safety`` does not currently support C++. This means LLDB’s expression
|
||||
evaluator can only evaluate a subset of the ``-fbounds-safety`` language model.
|
||||
`-fbounds-safety` does not currently support C++. This means LLDB’s expression
|
||||
evaluator can only evaluate a subset of the `-fbounds-safety` language model.
|
||||
Specifically, it’s capable of evaluating the wide pointers that already exist in
|
||||
the source code. All other expressions are evaluated according to C/C++
|
||||
semantics.
|
||||
|
||||
C++ support
|
||||
===========
|
||||
## C++ support
|
||||
|
||||
C++ has multiple options to write code in a bounds-safe manner, such as
|
||||
following the bounds-safety core guidelines and/or using hardened libc++ along
|
||||
with the `C++ Safe Buffer model
|
||||
<https://discourse.llvm.org/t/rfc-c-buffer-hardening/65734>`_. However, these
|
||||
with the [C++ Safe Buffer model](https://discourse.llvm.org/t/rfc-c-buffer-hardening/65734). However, these
|
||||
techniques may require ABI changes and may not be applicable to code
|
||||
interoperating with C. When the ABI of an existing program needs to be preserved
|
||||
and for headers shared between C and C++, ``-fbounds-safety`` offers a potential
|
||||
and for headers shared between C and C++, `-fbounds-safety` offers a potential
|
||||
solution.
|
||||
|
||||
``-fbounds-safety`` is not currently supported in C++, but we believe the
|
||||
`-fbounds-safety` is not currently supported in C++, but we believe the
|
||||
general approach would be applicable for future efforts.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
=======
|
||||
ClangIR
|
||||
=======
|
||||
# ClangIR
|
||||
|
||||
.. warning::
|
||||
The project of upstreaming ClangIR support from the incubator repository is
|
||||
still in progress, and ClangIR is not included in a default clang build. The
|
||||
documentation may be incomplete and out-of-date.
|
||||
:::{warning}
|
||||
The project of upstreaming ClangIR support from the incubator repository is
|
||||
still in progress, and ClangIR is not included in a default clang build. The
|
||||
documentation may be incomplete and out-of-date.
|
||||
:::
|
||||
|
||||
ClangIR is a high-level representation in Clang that reflects aspects of the
|
||||
C/C++ languages and their extensions. It is implemented using MLIR and occupies
|
||||
a position between Clang's AST and LLVM IR.
|
||||
|
||||
ClangIR Design Documents
|
||||
========================
|
||||
## ClangIR Design Documents
|
||||
|
||||
.. toctree::
|
||||
:numbered:
|
||||
:maxdepth: 1
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
:numbered: true
|
||||
|
||||
ABILowering
|
||||
CleanupAndEHDesign
|
||||
CodeDuplication
|
||||
```
|
||||
|
||||
ABILowering
|
||||
CleanupAndEHDesign
|
||||
CodeDuplication
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
=========================
|
||||
C++ Type Aware Allocators
|
||||
=========================
|
||||
# C++ Type Aware Allocators
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
```{contents}
|
||||
:local: true
|
||||
```
|
||||
|
||||
Introduction
|
||||
============
|
||||
## Introduction
|
||||
|
||||
Clang includes an implementation of P2719 "Type-aware allocation and deallocation
|
||||
functions".
|
||||
|
|
@ -19,27 +17,27 @@ allocators.
|
|||
|
||||
P2719 introduces a type-identity tag as valid parameter type for all allocation
|
||||
operators. This tag is a default initialized value of type `std::type_identity<T>`
|
||||
where T is the type being allocated or deallocated. Unlike the other placement
|
||||
where T is the type being allocated or deallocated. Unlike the other placement
|
||||
arguments this tag is passed as the first parameter to the operator.
|
||||
|
||||
The most basic use case is as follows
|
||||
|
||||
.. code-block:: c++
|
||||
```c++
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
struct S {
|
||||
// ...
|
||||
};
|
||||
|
||||
struct S {
|
||||
// ...
|
||||
};
|
||||
void *operator new(std::type_identity<S>, size_t, std::align_val_t);
|
||||
void operator delete(std::type_identity<S>, void *, size_t, std::align_val_t);
|
||||
|
||||
void *operator new(std::type_identity<S>, size_t, std::align_val_t);
|
||||
void operator delete(std::type_identity<S>, void *, size_t, std::align_val_t);
|
||||
|
||||
void f() {
|
||||
S *s = new S; // calls ::operator new(std::type_identity<S>(), sizeof(S), alignof(S))
|
||||
delete s; // calls ::operator delete(std::type_identity<S>(), s, sizeof(S), alignof(S))
|
||||
}
|
||||
void f() {
|
||||
S *s = new S; // calls ::operator new(std::type_identity<S>(), sizeof(S), alignof(S))
|
||||
delete s; // calls ::operator delete(std::type_identity<S>(), s, sizeof(S), alignof(S))
|
||||
}
|
||||
```
|
||||
|
||||
While this functionality alone is powerful and useful, the true power comes
|
||||
by using templates. In addition to adding the type-identity tag, P2719 allows
|
||||
|
|
@ -53,38 +51,38 @@ This allows arbitrarily constrained definitions of the operators that resolve
|
|||
as would be expected for any other template function resolution, e.g (only
|
||||
showing `operator new` for brevity)
|
||||
|
||||
.. code-block:: c++
|
||||
```c++
|
||||
template <typename T, unsigned Size> struct Array {
|
||||
T buffer[Size];
|
||||
};
|
||||
|
||||
template <typename T, unsigned Size> struct Array {
|
||||
T buffer[Size];
|
||||
};
|
||||
// Starting with a concrete type
|
||||
void *operator new(std::type_identity<Array<int, 5>>, size_t, std::align_val_t);
|
||||
|
||||
// Starting with a concrete type
|
||||
void *operator new(std::type_identity<Array<int, 5>>, size_t, std::align_val_t);
|
||||
// Only care about five element arrays
|
||||
template <typename T>
|
||||
void *operator new(std::type_identity<Array<T, 5>>, size_t, std::align_val_t);
|
||||
|
||||
// Only care about five element arrays
|
||||
template <typename T>
|
||||
void *operator new(std::type_identity<Array<T, 5>>, size_t, std::align_val_t);
|
||||
// An array of N floats
|
||||
template <unsigned N>
|
||||
void *operator new(std::type_identity<Array<float, N>>, size_t, std::align_val_t);
|
||||
|
||||
// An array of N floats
|
||||
template <unsigned N>
|
||||
void *operator new(std::type_identity<Array<float, N>>, size_t, std::align_val_t);
|
||||
// Any array
|
||||
template <typename T, unsigned N>
|
||||
void *operator new(std::type_identity<Array<T, N>>, size_t, std::align_val_t);
|
||||
|
||||
// Any array
|
||||
template <typename T, unsigned N>
|
||||
void *operator new(std::type_identity<Array<T, N>>, size_t, std::align_val_t);
|
||||
// A handy concept
|
||||
template <typename T> concept Polymorphic = std::is_polymorphic_v<T>;
|
||||
|
||||
// A handy concept
|
||||
template <typename T> concept Polymorphic = std::is_polymorphic_v<T>;
|
||||
// Only applies is T is Polymorphic
|
||||
template <Polymorphic T, unsigned N>
|
||||
void *operator new(std::type_identity<Array<T, N>>, size_t, std::align_val_t);
|
||||
|
||||
// Only applies is T is Polymorphic
|
||||
template <Polymorphic T, unsigned N>
|
||||
void *operator new(std::type_identity<Array<T, N>>, size_t, std::align_val_t);
|
||||
|
||||
// Any even length array
|
||||
template <typename T, unsigned N>
|
||||
void *operator new(std::type_identity<Array<T, N>>, size_t, std::align_val_t)
|
||||
requires(N%2 == 0);
|
||||
// Any even length array
|
||||
template <typename T, unsigned N>
|
||||
void *operator new(std::type_identity<Array<T, N>>, size_t, std::align_val_t)
|
||||
requires(N%2 == 0);
|
||||
```
|
||||
|
||||
Operator selection then proceeds according to the usual rules for choosing
|
||||
the best/most constrained match.
|
||||
|
|
@ -92,19 +90,16 @@ the best/most constrained match.
|
|||
Any declaration of a type aware operator new or operator delete must include a
|
||||
matching complementary operator defined in the same scope.
|
||||
|
||||
Notes
|
||||
=====
|
||||
## Notes
|
||||
|
||||
Unconstrained Global Operators
|
||||
------------------------------
|
||||
### Unconstrained Global Operators
|
||||
|
||||
Declaring an unconstrained type aware global operator `new` or `delete` (or
|
||||
`[]` variants) creates numerous hazards, similar to, but different from, those
|
||||
created by attempting to replace the non-type aware global operators. For that
|
||||
reason unconstrained operators are strongly discouraged.
|
||||
|
||||
Mismatching Constraints
|
||||
-----------------------
|
||||
### Mismatching Constraints
|
||||
|
||||
When declaring global type aware operators you should ensure the constraints
|
||||
applied to new and delete match exactly, and declare them together. This
|
||||
|
|
@ -112,8 +107,7 @@ limits the risk of having mismatching operators selected due to differing
|
|||
constraints resulting in changes to prioritization when determining the most
|
||||
viable candidate.
|
||||
|
||||
Declarations Across Libraries
|
||||
-----------------------------
|
||||
### Declarations Across Libraries
|
||||
|
||||
Declaring a typed allocator for a type in a separate TU or library creates
|
||||
similar hazards as different libraries and TUs may see (or select) different
|
||||
|
|
@ -121,35 +115,34 @@ definitions.
|
|||
|
||||
Under this model something like this would be risky
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
template<typename T>
|
||||
void *operator new(std::type_identity<std::vector<T>>, size_t, std::align_val_t);
|
||||
```c++
|
||||
template<typename T>
|
||||
void *operator new(std::type_identity<std::vector<T>>, size_t, std::align_val_t);
|
||||
```
|
||||
|
||||
However this hazard is not present simply due to the use of the a type from
|
||||
another library:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
template<typename T>
|
||||
struct MyType {
|
||||
T thing;
|
||||
};
|
||||
template<typename T>
|
||||
void *operator new(std::type_identity<MyType<std::vector<T>>>, size_t, std::align_val_t);
|
||||
```c++
|
||||
template<typename T>
|
||||
struct MyType {
|
||||
T thing;
|
||||
};
|
||||
template<typename T>
|
||||
void *operator new(std::type_identity<MyType<std::vector<T>>>, size_t, std::align_val_t);
|
||||
```
|
||||
|
||||
Here we see `std::vector` being used, but that is not the actual type being
|
||||
allocated.
|
||||
|
||||
Implicit and Placement Parameters
|
||||
---------------------------------
|
||||
### Implicit and Placement Parameters
|
||||
|
||||
Type aware allocators are always passed both the implicit alignment and size
|
||||
parameters in all cases. Explicit placement parameters are supported after the
|
||||
mandatory implicit parameters.
|
||||
|
||||
Publication
|
||||
===========
|
||||
## Publication
|
||||
|
||||
`Type-aware allocation and deallocation functions <https://wg21.link/P2719>`_.
|
||||
[Type-aware allocation and deallocation functions](https://wg21.link/P2719).
|
||||
Louis Dionne, Oliver Hunt.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,139 +1,125 @@
|
|||
=============
|
||||
Clang Plugins
|
||||
=============
|
||||
# Clang Plugins
|
||||
|
||||
Clang Plugins make it possible to run extra user defined actions during a
|
||||
compilation. This document will provide a basic walkthrough of how to write and
|
||||
run a Clang Plugin.
|
||||
|
||||
Introduction
|
||||
============
|
||||
## Introduction
|
||||
|
||||
Clang Plugins run FrontendActions over code. See the :doc:`FrontendAction
|
||||
tutorial <RAVFrontendAction>` on how to write a ``FrontendAction`` using the
|
||||
``RecursiveASTVisitor``. In this tutorial, we'll demonstrate how to write a
|
||||
Clang Plugins run FrontendActions over code. See the {doc}`FrontendAction
|
||||
tutorial <RAVFrontendAction>` on how to write a `FrontendAction` using the
|
||||
`RecursiveASTVisitor`. In this tutorial, we'll demonstrate how to write a
|
||||
simple clang plugin.
|
||||
|
||||
Writing a ``PluginASTAction``
|
||||
=============================
|
||||
## Writing a `PluginASTAction`
|
||||
|
||||
The main difference from writing normal ``FrontendActions`` is that you can
|
||||
handle plugin command line options. The ``PluginASTAction`` base class declares
|
||||
a ``ParseArgs`` method which you have to implement in your plugin.
|
||||
The main difference from writing normal `FrontendActions` is that you can
|
||||
handle plugin command line options. The `PluginASTAction` base class declares
|
||||
a `ParseArgs` method which you have to implement in your plugin.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
bool ParseArgs(const CompilerInstance &CI,
|
||||
const std::vector<std::string>& args) {
|
||||
for (unsigned i = 0, e = args.size(); i != e; ++i) {
|
||||
if (args[i] == "-some-arg") {
|
||||
// Handle the command line argument.
|
||||
}
|
||||
```c++
|
||||
bool ParseArgs(const CompilerInstance &CI,
|
||||
const std::vector<std::string>& args) {
|
||||
for (unsigned i = 0, e = args.size(); i != e; ++i) {
|
||||
if (args[i] == "-some-arg") {
|
||||
// Handle the command line argument.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
Registering a plugin
|
||||
====================
|
||||
## Registering a plugin
|
||||
|
||||
A plugin is loaded from a dynamic library at runtime by the compiler. To
|
||||
register a plugin in a library, use ``FrontendPluginRegistry::Add<>``:
|
||||
register a plugin in a library, use `FrontendPluginRegistry::Add<>`:
|
||||
|
||||
.. code-block:: c++
|
||||
```c++
|
||||
static FrontendPluginRegistry::Add<MyPlugin> X("my-plugin-name", "my plugin description");
|
||||
```
|
||||
|
||||
static FrontendPluginRegistry::Add<MyPlugin> X("my-plugin-name", "my plugin description");
|
||||
## Defining pragmas
|
||||
|
||||
Defining pragmas
|
||||
================
|
||||
Plugins can also define pragmas by declaring a `PragmaHandler` and
|
||||
registering it using `PragmaHandlerRegistry::Add<>`:
|
||||
|
||||
Plugins can also define pragmas by declaring a ``PragmaHandler`` and
|
||||
registering it using ``PragmaHandlerRegistry::Add<>``:
|
||||
```c++
|
||||
// Define a pragma handler for #pragma example_pragma
|
||||
class ExamplePragmaHandler : public PragmaHandler {
|
||||
public:
|
||||
ExamplePragmaHandler() : PragmaHandler("example_pragma") { }
|
||||
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
|
||||
Token &PragmaTok) {
|
||||
// Handle the pragma
|
||||
}
|
||||
};
|
||||
|
||||
.. code-block:: c++
|
||||
static PragmaHandlerRegistry::Add<ExamplePragmaHandler> Y("example_pragma","example pragma description");
|
||||
```
|
||||
|
||||
// Define a pragma handler for #pragma example_pragma
|
||||
class ExamplePragmaHandler : public PragmaHandler {
|
||||
public:
|
||||
ExamplePragmaHandler() : PragmaHandler("example_pragma") { }
|
||||
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
|
||||
Token &PragmaTok) {
|
||||
// Handle the pragma
|
||||
}
|
||||
};
|
||||
## Defining attributes
|
||||
|
||||
static PragmaHandlerRegistry::Add<ExamplePragmaHandler> Y("example_pragma","example pragma description");
|
||||
Plugins can define attributes by declaring a `ParsedAttrInfo` and registering
|
||||
it using `ParsedAttrInfoRegister::Add<>`:
|
||||
|
||||
Defining attributes
|
||||
===================
|
||||
```c++
|
||||
class ExampleAttrInfo : public ParsedAttrInfo {
|
||||
public:
|
||||
ExampleAttrInfo() {
|
||||
Spellings.push_back({ParsedAttr::AS_GNU,"example"});
|
||||
}
|
||||
AttrHandling handleDeclAttribute(Sema &S, Decl *D,
|
||||
const ParsedAttr &Attr) const override {
|
||||
// Handle the attribute
|
||||
return AttributeApplied;
|
||||
}
|
||||
};
|
||||
|
||||
Plugins can define attributes by declaring a ``ParsedAttrInfo`` and registering
|
||||
it using ``ParsedAttrInfoRegister::Add<>``:
|
||||
static ParsedAttrInfoRegistry::Add<ExampleAttrInfo> Z("example_attr","example attribute description");
|
||||
```
|
||||
|
||||
.. code-block:: c++
|
||||
The members of `ParsedAttrInfo` that a plugin attribute must define are:
|
||||
|
||||
class ExampleAttrInfo : public ParsedAttrInfo {
|
||||
public:
|
||||
ExampleAttrInfo() {
|
||||
Spellings.push_back({ParsedAttr::AS_GNU,"example"});
|
||||
}
|
||||
AttrHandling handleDeclAttribute(Sema &S, Decl *D,
|
||||
const ParsedAttr &Attr) const override {
|
||||
// Handle the attribute
|
||||
return AttributeApplied;
|
||||
}
|
||||
};
|
||||
- `Spellings`, which must be populated with every [Spelling](https://clang.llvm.org/doxygen/structclang_1_1ParsedAttrInfo_1_1Spelling.html) of the
|
||||
attribute, each of which consists of an attribute syntax and how the
|
||||
attribute name is spelled for that syntax. If the syntax allows a scope then
|
||||
the spelling must be "scope::attr" if a scope is present or "::attr" if not.
|
||||
|
||||
static ParsedAttrInfoRegistry::Add<ExampleAttrInfo> Z("example_attr","example attribute description");
|
||||
|
||||
The members of ``ParsedAttrInfo`` that a plugin attribute must define are:
|
||||
|
||||
* ``Spellings``, which must be populated with every `Spelling
|
||||
</doxygen/structclang_1_1ParsedAttrInfo_1_1Spelling.html>`_ of the
|
||||
attribute, each of which consists of an attribute syntax and how the
|
||||
attribute name is spelled for that syntax. If the syntax allows a scope then
|
||||
the spelling must be "scope::attr" if a scope is present or "::attr" if not.
|
||||
|
||||
The members of ``ParsedAttrInfo`` that may need to be defined, depending on the
|
||||
The members of `ParsedAttrInfo` that may need to be defined, depending on the
|
||||
attribute, are:
|
||||
|
||||
* ``NumArgs`` and ``OptArgs``, which set the number of required and optional
|
||||
arguments to the attribute.
|
||||
* ``diagAppertainsToDecl``, which checks if the attribute has been used on the
|
||||
right kind of declaration and issues a diagnostic if not.
|
||||
* ``handleDeclAttribute``, which is the function that applies the attribute to
|
||||
a declaration. It is responsible for checking that the attribute's arguments
|
||||
are valid, and typically applies the attribute by adding an ``Attr`` to the
|
||||
``Decl``. It returns either ``AttributeApplied``, to indicate that the
|
||||
attribute was successfully applied, or ``AttributeNotApplied`` if it wasn't.
|
||||
* ``diagAppertainsToStmt``, which checks if the attribute has been used on the
|
||||
right kind of statement and issues a diagnostic if not.
|
||||
* ``handleStmtAttribute``, which is the function that applies the attribute to
|
||||
a statement. It is responsible for checking that the attribute's arguments
|
||||
are valid, and typically applies the attribute by adding an ``Attr`` to the
|
||||
``Stmt``. It returns either ``AttributeApplied``, to indicate that the
|
||||
attribute was successfully applied, or ``AttributeNotApplied`` if it wasn't.
|
||||
* ``diagLangOpts``, which checks if the attribute is permitted for the current
|
||||
language mode and issues a diagnostic if not.
|
||||
* ``existsInTarget``, which checks if the attribute is permitted for the given
|
||||
target.
|
||||
- `NumArgs` and `OptArgs`, which set the number of required and optional
|
||||
arguments to the attribute.
|
||||
- `diagAppertainsToDecl`, which checks if the attribute has been used on the
|
||||
right kind of declaration and issues a diagnostic if not.
|
||||
- `handleDeclAttribute`, which is the function that applies the attribute to
|
||||
a declaration. It is responsible for checking that the attribute's arguments
|
||||
are valid, and typically applies the attribute by adding an `Attr` to the
|
||||
`Decl`. It returns either `AttributeApplied`, to indicate that the
|
||||
attribute was successfully applied, or `AttributeNotApplied` if it wasn't.
|
||||
- `diagAppertainsToStmt`, which checks if the attribute has been used on the
|
||||
right kind of statement and issues a diagnostic if not.
|
||||
- `handleStmtAttribute`, which is the function that applies the attribute to
|
||||
a statement. It is responsible for checking that the attribute's arguments
|
||||
are valid, and typically applies the attribute by adding an `Attr` to the
|
||||
`Stmt`. It returns either `AttributeApplied`, to indicate that the
|
||||
attribute was successfully applied, or `AttributeNotApplied` if it wasn't.
|
||||
- `diagLangOpts`, which checks if the attribute is permitted for the current
|
||||
language mode and issues a diagnostic if not.
|
||||
- `existsInTarget`, which checks if the attribute is permitted for the given
|
||||
target.
|
||||
|
||||
To see a working example of an attribute plugin, see `the Attribute.cpp example
|
||||
<https://github.com/llvm/llvm-project/blob/main/clang/examples/Attribute/Attribute.cpp>`_.
|
||||
To see a working example of an attribute plugin, see [the Attribute.cpp example](https://github.com/llvm/llvm-project/blob/main/clang/examples/Attribute/Attribute.cpp).
|
||||
|
||||
Putting it all together
|
||||
=======================
|
||||
## Putting it all together
|
||||
|
||||
Let's look at an example plugin that prints top-level function names. This
|
||||
Let's look at an example plugin that prints top-level function names. This
|
||||
example is checked into the clang repository; please take a look at
|
||||
the `latest version of PrintFunctionNames.cpp
|
||||
<https://github.com/llvm/llvm-project/blob/main/clang/examples/PrintFunctionNames/PrintFunctionNames.cpp>`_.
|
||||
the [latest version of PrintFunctionNames.cpp](https://github.com/llvm/llvm-project/blob/main/clang/examples/PrintFunctionNames/PrintFunctionNames.cpp).
|
||||
|
||||
Running the plugin
|
||||
==================
|
||||
## Running the plugin
|
||||
|
||||
|
||||
Using the compiler driver
|
||||
--------------------------
|
||||
### Using the compiler driver
|
||||
|
||||
The Clang driver accepts the `-fplugin` option to load a plugin.
|
||||
Clang plugins can receive arguments from the compiler driver command
|
||||
|
|
@ -141,21 +127,18 @@ line via the `fplugin-arg-<plugin name>-<argument>` option. Using this
|
|||
method, the plugin name cannot contain dashes itself, but the argument
|
||||
passed to the plugin can.
|
||||
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ export BD=/path/to/build/directory
|
||||
$ make -C $BD CallSuperAttr
|
||||
$ clang++ -fplugin=$BD/lib/CallSuperAttr.so \
|
||||
-fplugin-arg-call_super_plugin-help \
|
||||
test.cpp
|
||||
```console
|
||||
$ export BD=/path/to/build/directory
|
||||
$ make -C $BD CallSuperAttr
|
||||
$ clang++ -fplugin=$BD/lib/CallSuperAttr.so \
|
||||
-fplugin-arg-call_super_plugin-help \
|
||||
test.cpp
|
||||
```
|
||||
|
||||
If your plugin name contains dashes, either rename the plugin or use the
|
||||
cc1 command line options listed below.
|
||||
|
||||
|
||||
Using the cc1 command line
|
||||
--------------------------
|
||||
### Using the cc1 command line
|
||||
|
||||
To run a plugin, the dynamic library containing the plugin registry must be
|
||||
loaded via the `-load` command line option. This will load all plugins
|
||||
|
|
@ -166,58 +149,54 @@ that are registered, and you can select the plugins to run by specifying the
|
|||
Note that those options must reach clang's cc1 process. There are two
|
||||
ways to do so:
|
||||
|
||||
* Directly call the parsing process by using the `-cc1` option; this
|
||||
- Directly call the parsing process by using the `-cc1` option; this
|
||||
has the downside of not configuring the default header search paths, so
|
||||
you'll need to specify the full system path configuration on the command
|
||||
line.
|
||||
* Use clang as usual, but prefix all arguments to the cc1 process with
|
||||
- Use clang as usual, but prefix all arguments to the cc1 process with
|
||||
`-Xclang`.
|
||||
|
||||
For example, to run the ``print-function-names`` plugin over a source file in
|
||||
For example, to run the `print-function-names` plugin over a source file in
|
||||
clang, first build the plugin, and then call clang with the plugin from the
|
||||
source tree:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ export BD=/path/to/build/directory
|
||||
$ (cd $BD && make PrintFunctionNames )
|
||||
$ clang++ -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS \
|
||||
-D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE \
|
||||
-I$BD/tools/clang/include -Itools/clang/include -I$BD/include -Iinclude \
|
||||
tools/clang/tools/clang-check/ClangCheck.cpp -fsyntax-only \
|
||||
-Xclang -load -Xclang $BD/lib/PrintFunctionNames.so -Xclang \
|
||||
-plugin -Xclang print-fns
|
||||
```console
|
||||
$ export BD=/path/to/build/directory
|
||||
$ (cd $BD && make PrintFunctionNames )
|
||||
$ clang++ -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS \
|
||||
-D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE \
|
||||
-I$BD/tools/clang/include -Itools/clang/include -I$BD/include -Iinclude \
|
||||
tools/clang/tools/clang-check/ClangCheck.cpp -fsyntax-only \
|
||||
-Xclang -load -Xclang $BD/lib/PrintFunctionNames.so -Xclang \
|
||||
-plugin -Xclang print-fns
|
||||
```
|
||||
|
||||
Also see the print-function-name plugin example's
|
||||
`README <https://github.com/llvm/llvm-project/blob/main/clang/examples/PrintFunctionNames/README.txt>`_
|
||||
[README](https://github.com/llvm/llvm-project/blob/main/clang/examples/PrintFunctionNames/README.txt)
|
||||
|
||||
|
||||
Using the clang command line
|
||||
----------------------------
|
||||
### Using the clang command line
|
||||
|
||||
Using `-fplugin=plugin` on the clang command line passes the plugin
|
||||
through as an argument to `-load` on the cc1 command line. If the plugin
|
||||
class implements the ``getActionType`` method then the plugin is run
|
||||
class implements the `getActionType` method then the plugin is run
|
||||
automatically. For example, to run the plugin automatically after the main AST
|
||||
action (i.e. the same as using `-add-plugin`):
|
||||
|
||||
.. code-block:: c++
|
||||
```c++
|
||||
// Automatically run the plugin after the main AST action
|
||||
PluginASTAction::ActionType getActionType() override {
|
||||
return AddAfterMainAction;
|
||||
}
|
||||
```
|
||||
|
||||
// Automatically run the plugin after the main AST action
|
||||
PluginASTAction::ActionType getActionType() override {
|
||||
return AddAfterMainAction;
|
||||
}
|
||||
|
||||
Interaction with ``-clear-ast-before-backend``
|
||||
----------------------------------------------
|
||||
### Interaction with `-clear-ast-before-backend`
|
||||
|
||||
To reduce peak memory usage of the compiler, plugins are recommended to run
|
||||
*before* the main action, which is usually code generation. This is because
|
||||
having any plugins that run after the codegen action automatically turns off
|
||||
``-clear-ast-before-backend``. ``-clear-ast-before-backend`` reduces peak
|
||||
`-clear-ast-before-backend`. `-clear-ast-before-backend` reduces peak
|
||||
memory by clearing the Clang AST after generating IR and before running IR
|
||||
optimizations. Use ``CmdlineBeforeMainAction`` or ``AddBeforeMainAction`` as
|
||||
``getActionType`` to run plugins while still benefitting from
|
||||
``-clear-ast-before-backend``. Plugins must make sure not to modify the AST,
|
||||
optimizations. Use `CmdlineBeforeMainAction` or `AddBeforeMainAction` as
|
||||
`getActionType` to run plugins while still benefitting from
|
||||
`-clear-ast-before-backend`. Plugins must make sure not to modify the AST,
|
||||
otherwise they should run after the main action.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
Clang "man" pages
|
||||
-----------------
|
||||
# Clang "man" pages
|
||||
|
||||
The following documents are command descriptions for all of the Clang tools.
|
||||
These pages describe how to use the Clang commands and what their options are.
|
||||
Note that these pages do not describe all of the options available for all
|
||||
tools. To get a complete listing, pass the ``--help`` (general options) or
|
||||
``--help-hidden`` (general and debugging options) arguments to the tool you are
|
||||
tools. To get a complete listing, pass the `--help` (general options) or
|
||||
`--help-hidden` (general and debugging options) arguments to the tool you are
|
||||
interested in.
|
||||
|
||||
Basic Commands
|
||||
~~~~~~~~~~~~~~
|
||||
## Basic Commands
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
```{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
clang
|
||||
diagtool
|
||||
```
|
||||
|
||||
clang
|
||||
diagtool
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
======================
|
||||
Control Flow Integrity
|
||||
======================
|
||||
# Control Flow Integrity
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
```{toctree}
|
||||
:hidden: true
|
||||
|
||||
ControlFlowIntegrityDesign
|
||||
ControlFlowIntegrityDesign
|
||||
```
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
```{contents}
|
||||
:local: true
|
||||
```
|
||||
|
||||
Introduction
|
||||
============
|
||||
## Introduction
|
||||
|
||||
Clang includes an implementation of a number of control flow integrity (CFI)
|
||||
schemes, which are designed to abort the program upon detecting certain forms
|
||||
|
|
@ -20,11 +19,11 @@ program's control flow. These schemes have been optimized for performance,
|
|||
allowing developers to enable them in release builds.
|
||||
|
||||
To enable Clang's available CFI schemes, use the flag
|
||||
``-fsanitize=cfi``. You can also enable a subset of available
|
||||
:ref:`schemes <cfi-schemes>`. As currently implemented, all schemes
|
||||
except for ``kcfi`` rely on link-time optimization (LTO); so it is
|
||||
required to specify ``-flto`` or ``-flto=thin``, and the linker used
|
||||
must support LTO, for example via the `gold plugin`_.
|
||||
`-fsanitize=cfi`. You can also enable a subset of available
|
||||
{ref}`schemes <cfi-schemes>`. As currently implemented, all schemes
|
||||
except for `kcfi` rely on link-time optimization (LTO); so it is
|
||||
required to specify `-flto` or `-flto=thin`, and the linker used
|
||||
must support LTO, for example via the [gold plugin].
|
||||
|
||||
To allow the checks to be implemented efficiently, the program must
|
||||
be structured such that certain object files are compiled with CFI
|
||||
|
|
@ -34,92 +33,85 @@ the use of shared libraries in some cases.
|
|||
The compiler will only produce CFI checks for a class if it can infer hidden
|
||||
LTO visibility for that class. LTO visibility is a property of a class that
|
||||
is inferred from flags and attributes. For more details, see the documentation
|
||||
for :doc:`LTO visibility <LTOVisibility>`.
|
||||
for {doc}`LTO visibility <LTOVisibility>`.
|
||||
|
||||
The ``-fsanitize=cfi-{vcall,nvcall,derived-cast,unrelated-cast}`` flags
|
||||
require that a ``-fvisibility=`` flag also be specified. This is because the
|
||||
default visibility setting is ``-fvisibility=default``, which would disable
|
||||
The `-fsanitize=cfi-{vcall,nvcall,derived-cast,unrelated-cast}` flags
|
||||
require that a `-fvisibility=` flag also be specified. This is because the
|
||||
default visibility setting is `-fvisibility=default`, which would disable
|
||||
CFI checks for classes without visibility attributes. Most users will want
|
||||
to specify ``-fvisibility=hidden``, which enables CFI checks for such classes.
|
||||
to specify `-fvisibility=hidden`, which enables CFI checks for such classes.
|
||||
|
||||
When using ``-fsanitize=cfi*`` with ``-flto=thin``, it is recommended
|
||||
to reduce link times by passing `-funique-source-file-names
|
||||
<UsersManual.html#cmdoption-f-no-unique-source-file-names>`_, provided
|
||||
When using `-fsanitize=cfi*` with `-flto=thin`, it is recommended
|
||||
to reduce link times by passing [-funique-source-file-names](https://clang.llvm.org/docs/UsersManual.html#cmdoption-f-no-unique-source-file-names), provided
|
||||
that your program is compatible with it.
|
||||
|
||||
Experimental support for :ref:`cross-DSO control flow integrity
|
||||
Experimental support for {ref}`cross-DSO control flow integrity
|
||||
<cfi-cross-dso>` exists that does not require classes to have hidden LTO
|
||||
visibility. This cross-DSO support has unstable ABI at this time.
|
||||
|
||||
.. _gold plugin: https://llvm.org/docs/GoldPlugin.html
|
||||
(cfi-schemes)=
|
||||
|
||||
.. _cfi-schemes:
|
||||
|
||||
Available schemes
|
||||
=================
|
||||
## Available schemes
|
||||
|
||||
Available schemes are:
|
||||
|
||||
- ``-fsanitize=cfi-cast-strict``: Enables :ref:`strict cast checks
|
||||
<cfi-strictness>`.
|
||||
- ``-fsanitize=cfi-derived-cast``: Base-to-derived cast to the wrong
|
||||
dynamic type.
|
||||
- ``-fsanitize=cfi-unrelated-cast``: Cast from ``void*`` or another
|
||||
unrelated type to the wrong dynamic type.
|
||||
- ``-fsanitize=cfi-nvcall``: Non-virtual call via an object whose vptr is of
|
||||
the wrong dynamic type.
|
||||
- ``-fsanitize=cfi-vcall``: Virtual call via an object whose vptr is of the
|
||||
wrong dynamic type.
|
||||
- ``-fsanitize=cfi-icall``: Indirect call of a function with wrong dynamic
|
||||
type.
|
||||
- ``-fsanitize=cfi-mfcall``: Indirect call via a member function pointer with
|
||||
wrong dynamic type.
|
||||
- `-fsanitize=cfi-cast-strict`: Enables {ref}`strict cast checks
|
||||
<cfi-strictness>`.
|
||||
- `-fsanitize=cfi-derived-cast`: Base-to-derived cast to the wrong
|
||||
dynamic type.
|
||||
- `-fsanitize=cfi-unrelated-cast`: Cast from `void*` or another
|
||||
unrelated type to the wrong dynamic type.
|
||||
- `-fsanitize=cfi-nvcall`: Non-virtual call via an object whose vptr is of
|
||||
the wrong dynamic type.
|
||||
- `-fsanitize=cfi-vcall`: Virtual call via an object whose vptr is of the
|
||||
wrong dynamic type.
|
||||
- `-fsanitize=cfi-icall`: Indirect call of a function with wrong dynamic
|
||||
type.
|
||||
- `-fsanitize=cfi-mfcall`: Indirect call via a member function pointer with
|
||||
wrong dynamic type.
|
||||
|
||||
You can use ``-fsanitize=cfi`` to enable all the schemes and use
|
||||
``-fno-sanitize`` flag to narrow down the set of schemes as desired.
|
||||
You can use `-fsanitize=cfi` to enable all the schemes and use
|
||||
`-fno-sanitize` flag to narrow down the set of schemes as desired.
|
||||
For example, you can build your program with
|
||||
``-fsanitize=cfi -fno-sanitize=cfi-nvcall,cfi-icall``
|
||||
`-fsanitize=cfi -fno-sanitize=cfi-nvcall,cfi-icall`
|
||||
to use all schemes except for non-virtual member function call and indirect call
|
||||
checking.
|
||||
|
||||
Remember that you have to provide ``-flto`` or ``-flto=thin`` if at
|
||||
Remember that you have to provide `-flto` or `-flto=thin` if at
|
||||
least one CFI scheme is enabled.
|
||||
|
||||
Trapping and Diagnostics
|
||||
========================
|
||||
## Trapping and Diagnostics
|
||||
|
||||
By default, CFI will abort the program immediately upon detecting a control
|
||||
flow integrity violation. You can use the :ref:`-fno-sanitize-trap=
|
||||
flow integrity violation. You can use the {ref}`-fno-sanitize-trap=
|
||||
<controlling-code-generation>` flag to cause CFI to print a diagnostic
|
||||
similar to the one below before the program aborts.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
bad-cast.cpp:109:7: runtime error: control flow integrity check for type 'B' failed during base-to-derived cast (vtable address 0x000000425a50)
|
||||
0x000000425a50: note: vtable is of type 'A'
|
||||
00 00 00 00 f0 f1 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 5a 42 00
|
||||
^
|
||||
```console
|
||||
bad-cast.cpp:109:7: runtime error: control flow integrity check for type 'B' failed during base-to-derived cast (vtable address 0x000000425a50)
|
||||
0x000000425a50: note: vtable is of type 'A'
|
||||
00 00 00 00 f0 f1 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 5a 42 00
|
||||
^
|
||||
```
|
||||
|
||||
If diagnostics are enabled, you can also configure CFI to continue program
|
||||
execution instead of aborting by using the :ref:`-fsanitize-recover=
|
||||
execution instead of aborting by using the {ref}`-fsanitize-recover=
|
||||
<controlling-code-generation>` flag.
|
||||
|
||||
Forward-Edge CFI for Virtual Calls
|
||||
==================================
|
||||
## Forward-Edge CFI for Virtual Calls
|
||||
|
||||
This scheme checks that virtual calls take place using a vptr of the correct
|
||||
dynamic type; that is, the dynamic type of the called object must be a
|
||||
derived class of the static type of the object used to make the call.
|
||||
This CFI scheme can be enabled on its own using ``-fsanitize=cfi-vcall``.
|
||||
This CFI scheme can be enabled on its own using `-fsanitize=cfi-vcall`.
|
||||
|
||||
For this scheme to work, all translation units containing the definition
|
||||
of a virtual member function (whether inline or not), other than members
|
||||
of :ref:`ignored <cfi-ignorelist>` types or types with public :doc:`LTO
|
||||
visibility <LTOVisibility>`, must be compiled with ``-flto`` or ``-flto=thin``
|
||||
of {ref}`ignored <cfi-ignorelist>` types or types with public {doc}`LTO
|
||||
visibility <LTOVisibility>`, must be compiled with `-flto` or `-flto=thin`
|
||||
enabled and be statically linked into the program.
|
||||
|
||||
Performance
|
||||
-----------
|
||||
### Performance
|
||||
|
||||
A performance overhead of less than 1% has been measured by running the
|
||||
Dromaeo benchmark suite against an instrumented version of the Chromium
|
||||
|
|
@ -129,8 +121,7 @@ virtual-call-heavy SPEC 2006 xalancbmk.
|
|||
Note that this scheme has not yet been optimized for binary size; an increase
|
||||
of up to 15% has been observed for Chromium.
|
||||
|
||||
Bad Cast Checking
|
||||
=================
|
||||
## Bad Cast Checking
|
||||
|
||||
This scheme checks that pointer casts are made to an object of the correct
|
||||
dynamic type; that is, the dynamic type of the object must be a derived class
|
||||
|
|
@ -143,48 +134,46 @@ of the same mechanisms.
|
|||
|
||||
There are two types of bad cast that may be forbidden: bad casts
|
||||
from a base class to a derived class (which can be checked with
|
||||
``-fsanitize=cfi-derived-cast``), and bad casts from a pointer of
|
||||
type ``void*`` or another unrelated type (which can be checked with
|
||||
``-fsanitize=cfi-unrelated-cast``).
|
||||
`-fsanitize=cfi-derived-cast`), and bad casts from a pointer of
|
||||
type `void*` or another unrelated type (which can be checked with
|
||||
`-fsanitize=cfi-unrelated-cast`).
|
||||
|
||||
The difference between these two types of casts is that the first is defined
|
||||
by the C++ standard to produce an undefined value, while the second is not
|
||||
in itself undefined behavior (it is well defined to cast the pointer back
|
||||
to its original type) unless the object is uninitialized and the cast is a
|
||||
``static_cast`` (see C++14 [basic.life]p5).
|
||||
`static_cast` (see C++14 [basic.life]p5).
|
||||
|
||||
If a program as a matter of policy forbids the second type of cast, that
|
||||
restriction can normally be enforced. However it may in some cases be necessary
|
||||
for a function to perform a forbidden cast to conform with an external API
|
||||
(e.g. the ``allocate`` member function of a standard library allocator). Such
|
||||
functions may be :ref:`ignored <cfi-ignorelist>`.
|
||||
(e.g. the `allocate` member function of a standard library allocator). Such
|
||||
functions may be {ref}`ignored <cfi-ignorelist>`.
|
||||
|
||||
For this scheme to work, all translation units containing the definition
|
||||
of a virtual member function (whether inline or not), other than members
|
||||
of :ref:`ignored <cfi-ignorelist>` types or types with public :doc:`LTO
|
||||
visibility <LTOVisibility>`, must be compiled with ``-flto`` or ``-flto=thin``
|
||||
of {ref}`ignored <cfi-ignorelist>` types or types with public {doc}`LTO
|
||||
visibility <LTOVisibility>`, must be compiled with `-flto` or `-flto=thin`
|
||||
enabled and be statically linked into the program.
|
||||
|
||||
Non-Virtual Member Function Call Checking
|
||||
=========================================
|
||||
## Non-Virtual Member Function Call Checking
|
||||
|
||||
This scheme checks that non-virtual calls take place using an object of
|
||||
the correct dynamic type; that is, the dynamic type of the called object
|
||||
must be a derived class of the static type of the object used to make the
|
||||
call. The checks are currently only introduced where the object is of a
|
||||
polymorphic class type. This CFI scheme can be enabled on its own using
|
||||
``-fsanitize=cfi-nvcall``.
|
||||
polymorphic class type. This CFI scheme can be enabled on its own using
|
||||
`-fsanitize=cfi-nvcall`.
|
||||
|
||||
For this scheme to work, all translation units containing the definition
|
||||
of a virtual member function (whether inline or not), other than members
|
||||
of :ref:`ignored <cfi-ignorelist>` types or types with public :doc:`LTO
|
||||
visibility <LTOVisibility>`, must be compiled with ``-flto`` or ``-flto=thin``
|
||||
of {ref}`ignored <cfi-ignorelist>` types or types with public {doc}`LTO
|
||||
visibility <LTOVisibility>`, must be compiled with `-flto` or `-flto=thin`
|
||||
enabled and be statically linked into the program.
|
||||
|
||||
.. _cfi-strictness:
|
||||
(cfi-strictness)=
|
||||
|
||||
Strictness
|
||||
----------
|
||||
### Strictness
|
||||
|
||||
If a class has a single non-virtual base and does not introduce or override
|
||||
virtual member functions or fields other than an implicitly defined virtual
|
||||
|
|
@ -196,56 +185,53 @@ Casting an instance of a base class to such a derived class is technically
|
|||
undefined behavior, but it is a relatively common hack for introducing
|
||||
member functions on class instances with specific properties that works under
|
||||
most compilers and should not have security implications, so we allow it by
|
||||
default. It can be disabled with ``-fsanitize=cfi-cast-strict``.
|
||||
default. It can be disabled with `-fsanitize=cfi-cast-strict`.
|
||||
|
||||
Indirect Function Call Checking
|
||||
===============================
|
||||
## Indirect Function Call Checking
|
||||
|
||||
This scheme checks that function calls take place using a function of the
|
||||
correct dynamic type; that is, the dynamic type of the function must match
|
||||
the static type used at the call. This CFI scheme can be enabled on its own
|
||||
using ``-fsanitize=cfi-icall``.
|
||||
using `-fsanitize=cfi-icall`.
|
||||
|
||||
For this scheme to work, each indirect function call in the program, other
|
||||
than calls in :ref:`ignored <cfi-ignorelist>` functions, must call a
|
||||
function which was either compiled with ``-fsanitize=cfi-icall`` enabled,
|
||||
than calls in {ref}`ignored <cfi-ignorelist>` functions, must call a
|
||||
function which was either compiled with `-fsanitize=cfi-icall` enabled,
|
||||
or whose address was taken by a function in a translation unit compiled with
|
||||
``-fsanitize=cfi-icall``.
|
||||
`-fsanitize=cfi-icall`.
|
||||
|
||||
If a function in a translation unit compiled with ``-fsanitize=cfi-icall``
|
||||
takes the address of a function not compiled with ``-fsanitize=cfi-icall``,
|
||||
If a function in a translation unit compiled with `-fsanitize=cfi-icall`
|
||||
takes the address of a function not compiled with `-fsanitize=cfi-icall`,
|
||||
that address may differ from the address taken by a function in a translation
|
||||
unit not compiled with ``-fsanitize=cfi-icall``. This is technically a
|
||||
unit not compiled with `-fsanitize=cfi-icall`. This is technically a
|
||||
violation of the C and C++ standards, but it should not affect most programs.
|
||||
|
||||
Each translation unit compiled with ``-fsanitize=cfi-icall`` must be
|
||||
Each translation unit compiled with `-fsanitize=cfi-icall` must be
|
||||
statically linked into the program or shared library, and calls across
|
||||
shared library boundaries are handled as if the callee was not compiled with
|
||||
``-fsanitize=cfi-icall``.
|
||||
`-fsanitize=cfi-icall`.
|
||||
|
||||
This scheme is currently supported on a limited set of targets: x86,
|
||||
x86_64, arm, arch64 and wasm.
|
||||
|
||||
``-fsanitize-cfi-icall-generalize-pointers``
|
||||
--------------------------------------------
|
||||
### `-fsanitize-cfi-icall-generalize-pointers`
|
||||
|
||||
Mismatched pointer types are a common cause of cfi-icall check failures.
|
||||
Translation units compiled with the ``-fsanitize-cfi-icall-generalize-pointers``
|
||||
Translation units compiled with the `-fsanitize-cfi-icall-generalize-pointers`
|
||||
flag relax pointer type checking for call sites in that translation unit,
|
||||
applied across all functions compiled with ``-fsanitize=cfi-icall``.
|
||||
applied across all functions compiled with `-fsanitize=cfi-icall`.
|
||||
|
||||
Specifically, pointers in return and argument types are treated as equivalent as
|
||||
long as the qualifiers for the type they point to match. For example, ``char*``,
|
||||
``char**``, and ``int*`` are considered equivalent types. However, ``char*`` and
|
||||
``const char*`` are considered separate types.
|
||||
long as the qualifiers for the type they point to match. For example, `char*`,
|
||||
`char**`, and `int*` are considered equivalent types. However, `char*` and
|
||||
`const char*` are considered separate types.
|
||||
|
||||
``-fsanitize-cfi-icall-generalize-pointers`` is not compatible with
|
||||
``-fsanitize-cfi-cross-dso``.
|
||||
`-fsanitize-cfi-icall-generalize-pointers` is not compatible with
|
||||
`-fsanitize-cfi-cross-dso`.
|
||||
|
||||
.. _cfi-icall-experimental-normalize-integers:
|
||||
(cfi-icall-experimental-normalize-integers)=
|
||||
|
||||
``-fsanitize-cfi-icall-experimental-normalize-integers``
|
||||
--------------------------------------------------------
|
||||
### `-fsanitize-cfi-icall-experimental-normalize-integers`
|
||||
|
||||
This option enables normalizing integer types as vendor extended types for
|
||||
cross-language LLVM CFI/KCFI support with other languages that can't represent
|
||||
|
|
@ -256,21 +242,20 @@ Specifically, integer types are encoded as their defined representations (e.g.,
|
|||
compatibility with languages that define explicitly-sized integer types (e.g.,
|
||||
i8, i16, i32, ..., in Rust).
|
||||
|
||||
``-fsanitize-cfi-icall-experimental-normalize-integers`` is compatible with
|
||||
``-fsanitize-cfi-icall-generalize-pointers``.
|
||||
`-fsanitize-cfi-icall-experimental-normalize-integers` is compatible with
|
||||
`-fsanitize-cfi-icall-generalize-pointers`.
|
||||
|
||||
This option is currently experimental.
|
||||
|
||||
.. _cfi-canonical-jump-tables:
|
||||
(cfi-canonical-jump-tables)=
|
||||
|
||||
``-fsanitize-cfi-canonical-jump-tables``
|
||||
----------------------------------------
|
||||
### `-fsanitize-cfi-canonical-jump-tables`
|
||||
|
||||
The default behavior of Clang's indirect function call checker will replace
|
||||
the address of each CFI-checked function in the output file's symbol table
|
||||
with the address of a jump table entry which will pass CFI checks. We refer
|
||||
to this as making the jump table `canonical`. This property allows code that
|
||||
was not compiled with ``-fsanitize=cfi-icall`` to take a CFI-valid address
|
||||
to this as making the jump table *canonical*. This property allows code that
|
||||
was not compiled with `-fsanitize=cfi-icall` to take a CFI-valid address
|
||||
of a function, but it comes with a couple of caveats that are especially
|
||||
relevant for users of cross-DSO CFI:
|
||||
|
||||
|
|
@ -279,7 +264,6 @@ relevant for users of cross-DSO CFI:
|
|||
jump table entry, which must be emitted even in the common case where the
|
||||
function is never address-taken anywhere in the program, and must be used
|
||||
even for direct calls between DSOs, in addition to the PLT overhead.
|
||||
|
||||
- There is no good way to take a CFI-valid address of a function written in
|
||||
assembly or a language not supported by Clang. The reason is that the code
|
||||
generator would need to insert a jump table in order to form a CFI-valid
|
||||
|
|
@ -292,7 +276,7 @@ relevant for users of cross-DSO CFI:
|
|||
addition to adding runtime overhead.
|
||||
|
||||
For these reasons, we provide the option of making the jump table non-canonical
|
||||
with the flag ``-fno-sanitize-cfi-canonical-jump-tables``. When the jump
|
||||
with the flag `-fno-sanitize-cfi-canonical-jump-tables`. When the jump
|
||||
table is made non-canonical, symbol table entries point directly to the
|
||||
function body. Any instances of a function's address being taken in C will
|
||||
be replaced with a jump table address.
|
||||
|
|
@ -303,47 +287,44 @@ especially in cross-DSO mode which normally preserves function address
|
|||
equality entirely.
|
||||
|
||||
Furthermore, it is occasionally necessary for code not compiled with
|
||||
``-fsanitize=cfi-icall`` to take a function address that is valid
|
||||
`-fsanitize=cfi-icall` to take a function address that is valid
|
||||
for CFI. For example, this is necessary when a function's address
|
||||
is taken by assembly code and then called by CFI-checking C code. The
|
||||
``__attribute__((cfi_canonical_jump_table))`` attribute may be used to make
|
||||
`__attribute__((cfi_canonical_jump_table))` attribute may be used to make
|
||||
the jump table entry of a specific function canonical so that the external
|
||||
code will end up taking an address for the function that will pass CFI checks.
|
||||
|
||||
``-fsanitize=cfi-icall`` and ``-fsanitize=function``
|
||||
----------------------------------------------------
|
||||
### `-fsanitize=cfi-icall` and `-fsanitize=function`
|
||||
|
||||
This tool is similar to ``-fsanitize=function`` in that both tools check
|
||||
This tool is similar to `-fsanitize=function` in that both tools check
|
||||
the types of function calls. However, the two tools occupy different points
|
||||
on the design space; ``-fsanitize=function`` is a developer tool designed
|
||||
to find bugs in local development builds, whereas ``-fsanitize=cfi-icall``
|
||||
on the design space; `-fsanitize=function` is a developer tool designed
|
||||
to find bugs in local development builds, whereas `-fsanitize=cfi-icall`
|
||||
is a security hardening mechanism designed to be deployed in release builds.
|
||||
|
||||
``-fsanitize=function`` has a higher space and time overhead due to a more
|
||||
`-fsanitize=function` has a higher space and time overhead due to a more
|
||||
complex type check at indirect call sites, which may make it unsuitable for
|
||||
deployment.
|
||||
|
||||
On the other hand, ``-fsanitize=function`` conforms more closely with the C++
|
||||
On the other hand, `-fsanitize=function` conforms more closely with the C++
|
||||
standard and user expectations around interaction with shared libraries;
|
||||
the identity of function pointers is maintained, and calls across shared
|
||||
library boundaries are no different from calls within a single program or
|
||||
shared library.
|
||||
|
||||
.. _kcfi:
|
||||
(kcfi)=
|
||||
|
||||
``-fsanitize=kcfi``
|
||||
-------------------
|
||||
### `-fsanitize=kcfi`
|
||||
|
||||
This is an alternative indirect call control-flow integrity scheme designed
|
||||
for low-level system software, such as operating system kernels. Unlike
|
||||
``-fsanitize=cfi-icall``, it doesn't require ``-flto``, won't result in
|
||||
`-fsanitize=cfi-icall`, it doesn't require `-flto`, won't result in
|
||||
function pointers being replaced with jump table references, and never breaks
|
||||
cross-DSO function address equality. These properties make KCFI easier to
|
||||
adopt in low-level software. KCFI is limited to checking only function
|
||||
pointers, and isn't compatible with executable-only memory.
|
||||
|
||||
``-fsanitize-kcfi-arity``
|
||||
-----------------------------
|
||||
### `-fsanitize-kcfi-arity`
|
||||
|
||||
For supported targets, this feature extends kCFI by telling the compiler to
|
||||
record information about each indirect-callable function's arity (i.e., the
|
||||
|
|
@ -351,8 +332,7 @@ number of arguments passed in registers) into the binary. Some kernel CFI
|
|||
techniques, such as FineIBT, may be able to use this information to provide
|
||||
enhanced security.
|
||||
|
||||
Member Function Pointer Call Checking
|
||||
=====================================
|
||||
## Member Function Pointer Call Checking
|
||||
|
||||
This scheme checks that indirect calls via a member function pointer
|
||||
take place using an object of the correct dynamic type. Specifically, we
|
||||
|
|
@ -360,78 +340,75 @@ check that the dynamic type of the member function referenced by the member
|
|||
function pointer matches the "function pointer" part of the member function
|
||||
pointer, and that the member function's class type is related to the base
|
||||
type of the member function. This CFI scheme can be enabled on its own using
|
||||
``-fsanitize=cfi-mfcall``.
|
||||
`-fsanitize=cfi-mfcall`.
|
||||
|
||||
The compiler will only emit a full CFI check if the member function pointer's
|
||||
base type is complete. This is because the complete definition of the base
|
||||
type contains information that is necessary to correctly compile the CFI
|
||||
check. To ensure that the compiler always emits a full CFI check, it is
|
||||
recommended to also pass the flag ``-fcomplete-member-pointers``, which
|
||||
recommended to also pass the flag `-fcomplete-member-pointers`, which
|
||||
enables a non-conforming language extension that requires member pointer
|
||||
base types to be complete if they may be used for a call.
|
||||
|
||||
For this scheme to work, all translation units containing the definition
|
||||
of a virtual member function (whether inline or not), other than members
|
||||
of :ref:`ignored <cfi-ignorelist>` types or types with public :doc:`LTO
|
||||
visibility <LTOVisibility>`, must be compiled with ``-flto`` or ``-flto=thin``
|
||||
of {ref}`ignored <cfi-ignorelist>` types or types with public {doc}`LTO
|
||||
visibility <LTOVisibility>`, must be compiled with `-flto` or `-flto=thin`
|
||||
enabled and be statically linked into the program.
|
||||
|
||||
This scheme is currently not compatible with cross-DSO CFI or the
|
||||
Microsoft ABI.
|
||||
|
||||
.. _cfi-ignorelist:
|
||||
(cfi-ignorelist)=
|
||||
|
||||
Ignorelist
|
||||
==========
|
||||
## Ignorelist
|
||||
|
||||
A :doc:`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
|
||||
source files, functions and types using the ``src``, ``fun`` and ``type``
|
||||
entity types. Specific CFI modes can be be specified using ``[section]``
|
||||
A {doc}`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
|
||||
source files, functions and types using the `src`, `fun` and `type`
|
||||
entity types. Specific CFI modes can be be specified using `[section]`
|
||||
headers.
|
||||
|
||||
.. code-block:: bash
|
||||
```bash
|
||||
# Suppress all CFI checking for code in a file.
|
||||
src:bad_file.cpp
|
||||
src:bad_header.h
|
||||
# Ignore all functions with names containing MyFooBar.
|
||||
fun:*MyFooBar*
|
||||
# Ignore all types in the standard library.
|
||||
type:std::*
|
||||
# Disable only unrelated cast checks for this function
|
||||
[cfi-unrelated-cast]
|
||||
fun:*UnrelatedCast*
|
||||
# Disable CFI call checks for this function without affecting cast checks
|
||||
[cfi-vcall|cfi-nvcall|cfi-icall]
|
||||
fun:*BadCall*
|
||||
```
|
||||
|
||||
# Suppress all CFI checking for code in a file.
|
||||
src:bad_file.cpp
|
||||
src:bad_header.h
|
||||
# Ignore all functions with names containing MyFooBar.
|
||||
fun:*MyFooBar*
|
||||
# Ignore all types in the standard library.
|
||||
type:std::*
|
||||
# Disable only unrelated cast checks for this function
|
||||
[cfi-unrelated-cast]
|
||||
fun:*UnrelatedCast*
|
||||
# Disable CFI call checks for this function without affecting cast checks
|
||||
[cfi-vcall|cfi-nvcall|cfi-icall]
|
||||
fun:*BadCall*
|
||||
(cfi-cross-dso)=
|
||||
|
||||
|
||||
.. _cfi-cross-dso:
|
||||
|
||||
Shared library support
|
||||
======================
|
||||
## Shared library support
|
||||
|
||||
Use **-f[no-]sanitize-cfi-cross-dso** to enable the cross-DSO control
|
||||
flow integrity mode, which allows all CFI schemes listed above to
|
||||
apply across DSO boundaries. As in the regular CFI, each DSO must be
|
||||
built with ``-flto`` or ``-flto=thin``.
|
||||
built with `-flto` or `-flto=thin`.
|
||||
|
||||
Normally, CFI checks will only be performed for classes that have hidden LTO
|
||||
visibility. With this flag enabled, the compiler will emit cross-DSO CFI
|
||||
checks for all classes, except for those which appear in the CFI ignorelist
|
||||
or which use a ``no_sanitize`` attribute.
|
||||
or which use a `no_sanitize` attribute.
|
||||
|
||||
Design
|
||||
======
|
||||
## Design
|
||||
|
||||
Please refer to the :doc:`design document<ControlFlowIntegrityDesign>`.
|
||||
Please refer to the {doc}`design document<ControlFlowIntegrityDesign>`.
|
||||
|
||||
Publications
|
||||
============
|
||||
## Publications
|
||||
|
||||
`Control-Flow Integrity: Principles, Implementations, and Applications <https://research.microsoft.com/pubs/64250/ccs05.pdf>`_.
|
||||
[Control-Flow Integrity: Principles, Implementations, and Applications](https://research.microsoft.com/pubs/64250/ccs05.pdf).
|
||||
Martin Abadi, Mihai Budiu, Úlfar Erlingsson, Jay Ligatti.
|
||||
|
||||
`Enforcing Forward-Edge Control-Flow Integrity in GCC & LLVM <https://www.usenix.org/system/files/conference/usenixsecurity14/sec14-paper-tice.pdf>`_.
|
||||
[Enforcing Forward-Edge Control-Flow Integrity in GCC & LLVM](https://www.usenix.org/system/files/conference/usenixsecurity14/sec14-paper-tice.pdf).
|
||||
Caroline Tice, Tom Roeder, Peter Collingbourne, Stephen Checkoway,
|
||||
Úlfar Erlingsson, Luis Lozano, Geoff Pike.
|
||||
|
||||
[gold plugin]: https://llvm.org/docs/GoldPlugin.html
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,9 +1,6 @@
|
|||
=======================
|
||||
External Clang Examples
|
||||
=======================
|
||||
# External Clang Examples
|
||||
|
||||
Introduction
|
||||
============
|
||||
## Introduction
|
||||
|
||||
This page provides some examples of the kinds of things that people have
|
||||
done with Clang that might serve as useful guides (or starting points) from
|
||||
|
|
@ -19,85 +16,101 @@ where Clang is used are:
|
|||
- Documentation/cross-reference generation.
|
||||
|
||||
If you know of (or wrote!) a tool or project using Clang, please post on
|
||||
`the Discourse forums (Clang Frontend category)
|
||||
<https://discourse.llvm.org/c/clang/6>`_ to have it added.
|
||||
[the Discourse forums (Clang Frontend category)](https://discourse.llvm.org/c/clang/6) to have it added.
|
||||
(or if you are already a Clang contributor, feel free to directly commit
|
||||
additions). Since the primary purpose of this page is to provide examples
|
||||
that can help developers, generally they must have code available.
|
||||
|
||||
List of projects and tools
|
||||
==========================
|
||||
## List of projects and tools
|
||||
|
||||
`<https://github.com/Andersbakken/rtags/>`_
|
||||
"RTags is a client/server application that indexes c/c++ code and keeps
|
||||
a persistent in-memory database of references, symbolnames, completions
|
||||
etc."
|
||||
[https://github.com/Andersbakken/rtags/](https://github.com/Andersbakken/rtags/)
|
||||
|
||||
`<https://rprichard.github.io/CxxCodeBrowser/>`_
|
||||
"A C/C++ source code indexer and navigator."
|
||||
: "RTags is a client/server application that indexes c/c++ code and keeps
|
||||
a persistent in-memory database of references, symbolnames, completions
|
||||
etc."
|
||||
|
||||
`<https://github.com/etaoins/qconnectlint>`_
|
||||
"qconnectlint is a Clang tool for statically verifying the consistency
|
||||
of signal and slot connections made with Qt's ``QObject::connect``."
|
||||
[https://rprichard.github.io/CxxCodeBrowser/](https://rprichard.github.io/CxxCodeBrowser/)
|
||||
|
||||
`<https://github.com/woboq/woboq_codebrowser>`_
|
||||
"The Woboq Code Browser is a web-based code browser for C/C++ projects.
|
||||
Check out `<https://code.woboq.org/>`_ for an example!"
|
||||
: "A C/C++ source code indexer and navigator."
|
||||
|
||||
`<https://github.com/mozilla/dxr>`_
|
||||
"DXR is a source code cross-reference tool that uses static analysis
|
||||
data collected by instrumented compilers."
|
||||
[https://github.com/etaoins/qconnectlint](https://github.com/etaoins/qconnectlint)
|
||||
|
||||
`<https://github.com/eschulte/clang-mutate>`_
|
||||
"This tool performs a number of operations on C-language source files."
|
||||
: "qconnectlint is a Clang tool for statically verifying the consistency
|
||||
of signal and slot connections made with Qt's `QObject::connect`."
|
||||
|
||||
`<https://github.com/gmarpons/Crisp>`_
|
||||
"A coding rule validation add-on for LLVM/clang. Crisp rules are written
|
||||
in Prolog. A high-level declarative DSL to easily write new rules is under
|
||||
development. It will be called CRISP, an acronym for *Coding Rules in
|
||||
Sugared Prolog*."
|
||||
[https://github.com/woboq/woboq_codebrowser](https://github.com/woboq/woboq_codebrowser)
|
||||
|
||||
`<https://github.com/drothlis/clang-ctags>`_
|
||||
"Generate tag file for C++ source code."
|
||||
: "The Woboq Code Browser is a web-based code browser for C/C++ projects.
|
||||
Check out [https://code.woboq.org/](https://code.woboq.org/) for an example!"
|
||||
|
||||
`<https://github.com/exclipy/clang_indexer>`_
|
||||
"This is an indexer for C and C++ based on the libclang library."
|
||||
[https://github.com/mozilla/dxr](https://github.com/mozilla/dxr)
|
||||
|
||||
`<https://github.com/holtgrewe/linty>`_
|
||||
"Linty - C/C++ Style Checking with Python & libclang."
|
||||
: "DXR is a source code cross-reference tool that uses static analysis
|
||||
data collected by instrumented compilers."
|
||||
|
||||
`<https://github.com/axw/cmonster>`_
|
||||
"cmonster is a Python wrapper for the Clang C++ parser."
|
||||
[https://github.com/eschulte/clang-mutate](https://github.com/eschulte/clang-mutate)
|
||||
|
||||
`<https://github.com/rizsotto/Constantine>`_
|
||||
"Constantine is a toy project to learn how to write clang plugin.
|
||||
Implements pseudo const analysis. Generates warnings about variables,
|
||||
which were declared without const qualifier."
|
||||
: "This tool performs a number of operations on C-language source files."
|
||||
|
||||
`<https://github.com/jessevdk/cldoc>`_
|
||||
"cldoc is a Clang based documentation generator for C and C++.
|
||||
cldoc tries to solve the issue of writing C/C++ software documentation
|
||||
with a modern, non-intrusive and robust approach."
|
||||
[https://github.com/gmarpons/Crisp](https://github.com/gmarpons/Crisp)
|
||||
|
||||
`<https://github.com/AlexDenisov/ToyClangPlugin>`_
|
||||
"The simplest Clang plugin implementing a semantic check for Objective-C.
|
||||
This example shows how to use the ``DiagnosticsEngine`` (emit warnings,
|
||||
errors, fixit hints). See also `<http://l.rw.rw/clang_plugin>`_ for
|
||||
step-by-step instructions."
|
||||
: "A coding rule validation add-on for LLVM/clang. Crisp rules are written
|
||||
in Prolog. A high-level declarative DSL to easily write new rules is under
|
||||
development. It will be called CRISP, an acronym for *Coding Rules in
|
||||
Sugared Prolog*."
|
||||
|
||||
`<https://phabricator.kde.org/source/clazy>`_
|
||||
"clazy is a compiler plugin which allows clang to understand Qt semantics.
|
||||
You get more than 50 Qt related compiler warnings, ranging from unneeded
|
||||
memory allocations to misusage of API, including fix-its for automatic
|
||||
refactoring."
|
||||
[https://github.com/drothlis/clang-ctags](https://github.com/drothlis/clang-ctags)
|
||||
|
||||
`<https://gerrit.libreoffice.org/gitweb?p=core.git;a=blob_plain;f=compilerplugins/README;hb=HEAD>`_
|
||||
"LibreOffice uses a Clang plugin infrastructure to check during the build
|
||||
various things, some more, some less specific to the LibreOffice source code.
|
||||
There are currently around 50 such checkers, from flagging C-style casts and
|
||||
uses of reserved identifiers to ensuring that code adheres to lifecycle
|
||||
protocols for certain LibreOffice-specific classes. They may serve as
|
||||
examples for writing RecursiveASTVisitor-based plugins."
|
||||
: "Generate tag file for C++ source code."
|
||||
|
||||
[https://github.com/exclipy/clang_indexer](https://github.com/exclipy/clang_indexer)
|
||||
|
||||
: "This is an indexer for C and C++ based on the libclang library."
|
||||
|
||||
[https://github.com/holtgrewe/linty](https://github.com/holtgrewe/linty)
|
||||
|
||||
: "Linty - C/C++ Style Checking with Python & libclang."
|
||||
|
||||
[https://github.com/axw/cmonster](https://github.com/axw/cmonster)
|
||||
|
||||
: "cmonster is a Python wrapper for the Clang C++ parser."
|
||||
|
||||
[https://github.com/rizsotto/Constantine](https://github.com/rizsotto/Constantine)
|
||||
|
||||
: "Constantine is a toy project to learn how to write clang plugin.
|
||||
Implements pseudo const analysis. Generates warnings about variables,
|
||||
which were declared without const qualifier."
|
||||
|
||||
[https://github.com/jessevdk/cldoc](https://github.com/jessevdk/cldoc)
|
||||
|
||||
: "cldoc is a Clang based documentation generator for C and C++.
|
||||
cldoc tries to solve the issue of writing C/C++ software documentation
|
||||
with a modern, non-intrusive and robust approach."
|
||||
|
||||
[https://github.com/AlexDenisov/ToyClangPlugin](https://github.com/AlexDenisov/ToyClangPlugin)
|
||||
|
||||
: "The simplest Clang plugin implementing a semantic check for Objective-C.
|
||||
This example shows how to use the `DiagnosticsEngine` (emit warnings,
|
||||
errors, fixit hints). See also [http://l.rw.rw/clang_plugin](http://l.rw.rw/clang_plugin) for
|
||||
step-by-step instructions."
|
||||
|
||||
[https://phabricator.kde.org/source/clazy](https://phabricator.kde.org/source/clazy)
|
||||
|
||||
: "clazy is a compiler plugin which allows clang to understand Qt semantics.
|
||||
You get more than 50 Qt related compiler warnings, ranging from unneeded
|
||||
memory allocations to misusage of API, including fix-its for automatic
|
||||
refactoring."
|
||||
|
||||
[https://gerrit.libreoffice.org/gitweb?p=core.git;a=blob_plain;f=compilerplugins/README;hb=HEAD](https://gerrit.libreoffice.org/gitweb?p=core.git;a=blob_plain;f=compilerplugins/README;hb=HEAD)
|
||||
|
||||
: "LibreOffice uses a Clang plugin infrastructure to check during the build
|
||||
various things, some more, some less specific to the LibreOffice source code.
|
||||
There are currently around 50 such checkers, from flagging C-style casts and
|
||||
uses of reserved identifiers to ensuring that code adheres to lifecycle
|
||||
protocols for certain LibreOffice-specific classes. They may serve as
|
||||
examples for writing RecursiveASTVisitor-based plugins."
|
||||
|
||||
[https://github.com/banach-space/clang-tutor](https://github.com/banach-space/clang-tutor)
|
||||
|
||||
: "A collection of out-of-tree Clang plugins for teaching and learning."
|
||||
|
||||
`<https://github.com/banach-space/clang-tutor>`_
|
||||
"A collection of out-of-tree Clang plugins for teaching and learning."
|
||||
|
|
|
|||
|
|
@ -1,64 +1,59 @@
|
|||
================================
|
||||
Frequently Asked Questions (FAQ)
|
||||
================================
|
||||
# Frequently Asked Questions (FAQ)
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
```{contents}
|
||||
:local: true
|
||||
```
|
||||
|
||||
Driver
|
||||
======
|
||||
## Driver
|
||||
|
||||
I run ``clang -cc1 ...`` and get weird errors about missing headers
|
||||
-------------------------------------------------------------------
|
||||
### I run `clang -cc1 ...` and get weird errors about missing headers
|
||||
|
||||
Given this source file:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("Hello world\n");
|
||||
}
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("Hello world\n");
|
||||
}
|
||||
```
|
||||
|
||||
If you run:
|
||||
|
||||
.. code-block:: console
|
||||
```console
|
||||
$ clang -cc1 hello.c
|
||||
hello.c:1:10: fatal error: 'stdio.h' file not found
|
||||
#include <stdio.h>
|
||||
^
|
||||
1 error generated.
|
||||
```
|
||||
|
||||
$ clang -cc1 hello.c
|
||||
hello.c:1:10: fatal error: 'stdio.h' file not found
|
||||
#include <stdio.h>
|
||||
^
|
||||
1 error generated.
|
||||
`clang -cc1` is the frontend, `clang` is the {doc}`driver
|
||||
<DriverInternals>`. The driver invokes the frontend with options appropriate
|
||||
for your system. To see these options, run:
|
||||
|
||||
``clang -cc1`` is the frontend, ``clang`` is the :doc:`driver
|
||||
<DriverInternals>`. The driver invokes the frontend with options appropriate
|
||||
for your system. To see these options, run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ clang -### -c hello.c
|
||||
```console
|
||||
$ clang -### -c hello.c
|
||||
```
|
||||
|
||||
Some clang command line options are driver-only options, some are frontend-only
|
||||
options. Frontend-only options are intended to be used only by clang developers.
|
||||
Users should not run ``clang -cc1`` directly, because ``-cc1`` options are not
|
||||
options. Frontend-only options are intended to be used only by clang developers.
|
||||
Users should not run `clang -cc1` directly, because `-cc1` options are not
|
||||
guaranteed to be stable.
|
||||
|
||||
If you want to use a frontend-only option ("a ``-cc1`` option"), for example
|
||||
``-ast-dump``, then you need to take the ``clang -cc1`` line generated by the
|
||||
driver and add the option you need. Alternatively, you can run
|
||||
``clang -Xclang <option> ...`` to force the driver pass ``<option>`` to
|
||||
``clang -cc1``.
|
||||
If you want to use a frontend-only option ("a `-cc1` option"), for example
|
||||
`-ast-dump`, then you need to take the `clang -cc1` line generated by the
|
||||
driver and add the option you need. Alternatively, you can run
|
||||
`clang -Xclang <option> ...` to force the driver pass `<option>` to
|
||||
`clang -cc1`.
|
||||
|
||||
I get errors about some headers being missing (``stddef.h``, ``stdarg.h``)
|
||||
--------------------------------------------------------------------------
|
||||
### I get errors about some headers being missing (`stddef.h`, `stdarg.h`)
|
||||
|
||||
Some header files (``stddef.h``, ``stdarg.h``, and others) are shipped with
|
||||
Clang --- these are called builtin includes. Clang searches for them in a
|
||||
directory relative to the location of the ``clang`` binary. If you moved the
|
||||
``clang`` binary, you need to move the builtin headers, too.
|
||||
Some header files (`stddef.h`, `stdarg.h`, and others) are shipped with
|
||||
Clang --- these are called builtin includes. Clang searches for them in a
|
||||
directory relative to the location of the `clang` binary. If you moved the
|
||||
`clang` binary, you need to move the builtin headers, too.
|
||||
|
||||
More information can be found in the :ref:`libtooling_builtin_includes`
|
||||
More information can be found in the {ref}`libtooling_builtin_includes`
|
||||
section.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,17 @@
|
|||
=============================
|
||||
Introduction to the Clang AST
|
||||
=============================
|
||||
# Introduction to the Clang AST
|
||||
|
||||
This document gives a gentle introduction to the mysteries of the Clang
|
||||
AST. It is targeted at developers who either want to contribute to
|
||||
Clang, or use tools that work based on Clang's AST, like the AST
|
||||
matchers.
|
||||
|
||||
.. raw:: html
|
||||
```{raw} html
|
||||
<center><iframe width="560" height="315" src="https://www.youtube.com/embed/VqCkCDFLSsc?vq=hd720" frameborder="0" allowfullscreen></iframe></center>
|
||||
```
|
||||
|
||||
<center><iframe width="560" height="315" src="https://www.youtube.com/embed/VqCkCDFLSsc?vq=hd720" frameborder="0" allowfullscreen></iframe></center>
|
||||
[Slides](https://llvm.org/devmtg/2013-04/klimek-slides.pdf)
|
||||
|
||||
`Slides <https://llvm.org/devmtg/2013-04/klimek-slides.pdf>`_
|
||||
|
||||
Introduction
|
||||
============
|
||||
## Introduction
|
||||
|
||||
Clang's AST is different from ASTs produced by some other compilers in
|
||||
that it closely resembles both the written C++ code and the C++
|
||||
|
|
@ -23,104 +20,102 @@ constants are available in an unreduced form in the AST. This makes
|
|||
Clang's AST a good fit for refactoring tools.
|
||||
|
||||
Documentation for all Clang AST nodes is available via the generated
|
||||
`Doxygen <https://clang.llvm.org/doxygen>`_. The doxygen online
|
||||
[Doxygen](https://clang.llvm.org/doxygen). The doxygen online
|
||||
documentation is also indexed by your favorite search engine, which will
|
||||
make a search for clang and the AST node's class name usually turn up
|
||||
the doxygen of the class you're looking for (for example, search for:
|
||||
clang ParenExpr).
|
||||
|
||||
Examining the AST
|
||||
=================
|
||||
## Examining the AST
|
||||
|
||||
A good way to familiarize yourself with the Clang AST is to actually look
|
||||
at it on some simple example code. Clang has a builtin AST-dump mode,
|
||||
which can be enabled with the flag ``-ast-dump``.
|
||||
which can be enabled with the flag `-ast-dump`.
|
||||
|
||||
Let's look at a simple example AST:
|
||||
|
||||
::
|
||||
```
|
||||
$ cat test.cc
|
||||
int f(int x) {
|
||||
int result = (x / 42);
|
||||
return result;
|
||||
}
|
||||
|
||||
$ cat test.cc
|
||||
int f(int x) {
|
||||
int result = (x / 42);
|
||||
return result;
|
||||
}
|
||||
|
||||
# Clang by default is a frontend for many tools; -Xclang is used to pass
|
||||
# options directly to the C++ frontend.
|
||||
$ clang -Xclang -ast-dump -fsyntax-only test.cc
|
||||
TranslationUnitDecl 0x5aea0d0 <<invalid sloc>>
|
||||
... cutting out internal declarations of clang ...
|
||||
`-FunctionDecl 0x5aeab50 <test.cc:1:1, line:4:1> f 'int (int)'
|
||||
|-ParmVarDecl 0x5aeaa90 <line:1:7, col:11> x 'int'
|
||||
`-CompoundStmt 0x5aead88 <col:14, line:4:1>
|
||||
|-DeclStmt 0x5aead10 <line:2:3, col:24>
|
||||
| `-VarDecl 0x5aeac10 <col:3, col:23> result 'int'
|
||||
| `-ParenExpr 0x5aeacf0 <col:16, col:23> 'int'
|
||||
| `-BinaryOperator 0x5aeacc8 <col:17, col:21> 'int' '/'
|
||||
| |-ImplicitCastExpr 0x5aeacb0 <col:17> 'int' <LValueToRValue>
|
||||
| | `-DeclRefExpr 0x5aeac68 <col:17> 'int' lvalue ParmVar 0x5aeaa90 'x' 'int'
|
||||
| `-IntegerLiteral 0x5aeac90 <col:21> 'int' 42
|
||||
`-ReturnStmt 0x5aead68 <line:3:3, col:10>
|
||||
`-ImplicitCastExpr 0x5aead50 <col:10> 'int' <LValueToRValue>
|
||||
`-DeclRefExpr 0x5aead28 <col:10> 'int' lvalue Var 0x5aeac10 'result' 'int'
|
||||
# Clang by default is a frontend for many tools; -Xclang is used to pass
|
||||
# options directly to the C++ frontend.
|
||||
$ clang -Xclang -ast-dump -fsyntax-only test.cc
|
||||
TranslationUnitDecl 0x5aea0d0 <<invalid sloc>>
|
||||
... cutting out internal declarations of clang ...
|
||||
`-FunctionDecl 0x5aeab50 <test.cc:1:1, line:4:1> f 'int (int)'
|
||||
|-ParmVarDecl 0x5aeaa90 <line:1:7, col:11> x 'int'
|
||||
`-CompoundStmt 0x5aead88 <col:14, line:4:1>
|
||||
|-DeclStmt 0x5aead10 <line:2:3, col:24>
|
||||
| `-VarDecl 0x5aeac10 <col:3, col:23> result 'int'
|
||||
| `-ParenExpr 0x5aeacf0 <col:16, col:23> 'int'
|
||||
| `-BinaryOperator 0x5aeacc8 <col:17, col:21> 'int' '/'
|
||||
| |-ImplicitCastExpr 0x5aeacb0 <col:17> 'int' <LValueToRValue>
|
||||
| | `-DeclRefExpr 0x5aeac68 <col:17> 'int' lvalue ParmVar 0x5aeaa90 'x' 'int'
|
||||
| `-IntegerLiteral 0x5aeac90 <col:21> 'int' 42
|
||||
`-ReturnStmt 0x5aead68 <line:3:3, col:10>
|
||||
`-ImplicitCastExpr 0x5aead50 <col:10> 'int' <LValueToRValue>
|
||||
`-DeclRefExpr 0x5aead28 <col:10> 'int' lvalue Var 0x5aeac10 'result' 'int'
|
||||
```
|
||||
|
||||
The toplevel declaration in
|
||||
a translation unit is always the `translation unit
|
||||
declaration <https://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html>`_.
|
||||
In this example, our first user written declaration is the `function
|
||||
declaration <https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html>`_
|
||||
of "``f``". The body of "``f``" is a `compound
|
||||
statement <https://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html>`_,
|
||||
whose child nodes are a `declaration
|
||||
statement <https://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html>`_
|
||||
that declares our result variable, and the `return
|
||||
statement <https://clang.llvm.org/doxygen/classclang_1_1ReturnStmt.html>`_.
|
||||
a translation unit is always the [translation unit
|
||||
declaration](https://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html).
|
||||
In this example, our first user written declaration is the [function
|
||||
declaration](https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html)
|
||||
of "`f`". The body of "`f`" is a [compound
|
||||
statement](https://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html),
|
||||
whose child nodes are a [declaration
|
||||
statement](https://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html)
|
||||
that declares our result variable, and the [return
|
||||
statement](https://clang.llvm.org/doxygen/classclang_1_1ReturnStmt.html).
|
||||
|
||||
AST Context
|
||||
===========
|
||||
## AST Context
|
||||
|
||||
All information about the AST for a translation unit is bundled up in
|
||||
the class
|
||||
`ASTContext <https://clang.llvm.org/doxygen/classclang_1_1ASTContext.html>`_.
|
||||
[ASTContext](https://clang.llvm.org/doxygen/classclang_1_1ASTContext.html).
|
||||
It allows traversal of the whole translation unit starting from
|
||||
`getTranslationUnitDecl <https://clang.llvm.org/doxygen/classclang_1_1ASTContext.html#abd909fb01ef10cfd0244832a67b1dd64>`_,
|
||||
or to access Clang's `table of
|
||||
identifiers <https://clang.llvm.org/doxygen/classclang_1_1ASTContext.html#a4f95adb9958e22fbe55212ae6482feb4>`_
|
||||
[getTranslationUnitDecl](https://clang.llvm.org/doxygen/classclang_1_1ASTContext.html#abd909fb01ef10cfd0244832a67b1dd64),
|
||||
or to access Clang's [table of
|
||||
identifiers](https://clang.llvm.org/doxygen/classclang_1_1ASTContext.html#a4f95adb9958e22fbe55212ae6482feb4)
|
||||
for the parsed translation unit.
|
||||
|
||||
AST Nodes
|
||||
=========
|
||||
## AST Nodes
|
||||
|
||||
Clang's AST nodes are modeled on a class hierarchy that does not have a
|
||||
common ancestor. Instead, there are multiple larger hierarchies for
|
||||
basic node types like
|
||||
`Decl <https://clang.llvm.org/doxygen/classclang_1_1Decl.html>`_ and
|
||||
`Stmt <https://clang.llvm.org/doxygen/classclang_1_1Stmt.html>`_. Many
|
||||
[Decl](https://clang.llvm.org/doxygen/classclang_1_1Decl.html) and
|
||||
[Stmt](https://clang.llvm.org/doxygen/classclang_1_1Stmt.html). Many
|
||||
important AST nodes derive from
|
||||
`Type <https://clang.llvm.org/doxygen/classclang_1_1Type.html>`_,
|
||||
`Decl <https://clang.llvm.org/doxygen/classclang_1_1Decl.html>`_,
|
||||
`DeclContext <https://clang.llvm.org/doxygen/classclang_1_1DeclContext.html>`_
|
||||
or `Stmt <https://clang.llvm.org/doxygen/classclang_1_1Stmt.html>`_, with
|
||||
[Type](https://clang.llvm.org/doxygen/classclang_1_1Type.html),
|
||||
[Decl](https://clang.llvm.org/doxygen/classclang_1_1Decl.html),
|
||||
[DeclContext](https://clang.llvm.org/doxygen/classclang_1_1DeclContext.html)
|
||||
or [Stmt](https://clang.llvm.org/doxygen/classclang_1_1Stmt.html), with
|
||||
some classes deriving from both Decl and DeclContext.
|
||||
|
||||
There are also a multitude of nodes in the AST that are not part of a
|
||||
larger hierarchy, and are only reachable from specific other nodes, like
|
||||
`CXXBaseSpecifier <https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html>`_.
|
||||
[CXXBaseSpecifier](https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html).
|
||||
|
||||
Thus, to traverse the full AST, one starts from the
|
||||
`TranslationUnitDecl <https://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html>`_
|
||||
[TranslationUnitDecl](https://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html)
|
||||
and then recursively traverses everything that can be reached from that
|
||||
node - this information has to be encoded for each specific node type.
|
||||
This algorithm is encoded in the
|
||||
`RecursiveASTVisitor <https://clang.llvm.org/doxygen/classclang_1_1RecursiveASTVisitor.html>`_.
|
||||
See the `RecursiveASTVisitor
|
||||
tutorial <https://clang.llvm.org/docs/RAVFrontendAction.html>`_.
|
||||
[RecursiveASTVisitor](https://clang.llvm.org/doxygen/classclang_1_1RecursiveASTVisitor.html).
|
||||
See the [RecursiveASTVisitor
|
||||
tutorial](https://clang.llvm.org/docs/RAVFrontendAction.html).
|
||||
|
||||
The two most basic nodes in the Clang AST are statements
|
||||
(`Stmt <https://clang.llvm.org/doxygen/classclang_1_1Stmt.html>`_) and
|
||||
([Stmt](https://clang.llvm.org/doxygen/classclang_1_1Stmt.html)) and
|
||||
declarations
|
||||
(`Decl <https://clang.llvm.org/doxygen/classclang_1_1Decl.html>`_). Note
|
||||
([Decl](https://clang.llvm.org/doxygen/classclang_1_1Decl.html)). Note
|
||||
that expressions
|
||||
(`Expr <https://clang.llvm.org/doxygen/classclang_1_1Expr.html>`_) are
|
||||
([Expr](https://clang.llvm.org/doxygen/classclang_1_1Expr.html)) are
|
||||
also statements in Clang's AST.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,401 +1,383 @@
|
|||
.. role:: raw-html(raw)
|
||||
:format: html
|
||||
# Libclang tutorial
|
||||
|
||||
Libclang tutorial
|
||||
=================
|
||||
The C Interface to Clang provides a relatively small API that exposes facilities for parsing source code into an abstract syntax tree (AST), loading already-parsed ASTs, traversing the AST, associating physical source locations with elements within the AST, and other facilities that support Clang-based development tools.
|
||||
This C interface to Clang will never provide all of the information representation stored in Clang's C++ AST, nor should it: the intent is to maintain an API that is :ref:`relatively stable <Stability>` from one release to the next, providing only the basic functionality needed to support development tools.
|
||||
The entire C interface of libclang is available in the file `Index.h`_
|
||||
This C interface to Clang will never provide all of the information representation stored in Clang's C++ AST, nor should it: the intent is to maintain an API that is {ref}`relatively stable <Stability>` from one release to the next, providing only the basic functionality needed to support development tools.
|
||||
The entire C interface of libclang is available in the file [Index.h]
|
||||
|
||||
Essential types overview
|
||||
-------------------------
|
||||
## Essential types overview
|
||||
|
||||
All types of libclang are prefixed with ``CX``
|
||||
All types of libclang are prefixed with `CX`
|
||||
|
||||
### CXIndex
|
||||
|
||||
CXIndex
|
||||
~~~~~~~
|
||||
An Index that consists of a set of translation units that would typically be linked together into an executable or library.
|
||||
|
||||
CXTranslationUnit
|
||||
~~~~~~~~~~~~~~~~~
|
||||
### CXTranslationUnit
|
||||
|
||||
A single translation unit, which resides in an index.
|
||||
|
||||
CXCursor
|
||||
~~~~~~~~
|
||||
### CXCursor
|
||||
|
||||
A cursor representing a pointer to some element in the abstract syntax tree of a translation unit.
|
||||
|
||||
#### Code example
|
||||
|
||||
Code example
|
||||
""""""""""""
|
||||
```cpp
|
||||
// file.cpp
|
||||
struct foo{
|
||||
int bar;
|
||||
int* bar_pointer;
|
||||
};
|
||||
```
|
||||
|
||||
.. code-block:: cpp
|
||||
```cpp
|
||||
// main.cpp
|
||||
#include <clang-c/Index.h>
|
||||
#include <iostream>
|
||||
|
||||
// file.cpp
|
||||
struct foo{
|
||||
int bar;
|
||||
int* bar_pointer;
|
||||
};
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// main.cpp
|
||||
#include <clang-c/Index.h>
|
||||
#include <iostream>
|
||||
|
||||
int main(){
|
||||
CXIndex index = clang_createIndex(0, 0); //Create index
|
||||
CXTranslationUnit unit = clang_parseTranslationUnit(
|
||||
index,
|
||||
"file.cpp", nullptr, 0,
|
||||
nullptr, 0,
|
||||
CXTranslationUnit_None); //Parse "file.cpp"
|
||||
int main(){
|
||||
CXIndex index = clang_createIndex(0, 0); //Create index
|
||||
CXTranslationUnit unit = clang_parseTranslationUnit(
|
||||
index,
|
||||
"file.cpp", nullptr, 0,
|
||||
nullptr, 0,
|
||||
CXTranslationUnit_None); //Parse "file.cpp"
|
||||
|
||||
|
||||
if (unit == nullptr){
|
||||
std::cerr << "Unable to parse translation unit. Quitting.\n";
|
||||
return 0;
|
||||
}
|
||||
CXCursor cursor = clang_getTranslationUnitCursor(unit); //Obtain a cursor at the root of the translation unit
|
||||
if (unit == nullptr){
|
||||
std::cerr << "Unable to parse translation unit. Quitting.\n";
|
||||
return 0;
|
||||
}
|
||||
CXCursor cursor = clang_getTranslationUnitCursor(unit); //Obtain a cursor at the root of the translation unit
|
||||
}
|
||||
```
|
||||
|
||||
.. code-block:: cmake
|
||||
```cmake
|
||||
# CMakeLists.txt
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(my_clang_tool VERSION 0.1.0)
|
||||
|
||||
# CMakeLists.txt
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(my_clang_tool VERSION 0.1.0)
|
||||
# This will find the default system installation of Clang; if you want to
|
||||
# use a different build of clang, pass -DClang_DIR=/foobar/lib/cmake/clang
|
||||
# to the CMake configure command, where /foobar is the build directory where
|
||||
# you built Clang.
|
||||
find_package(Clang CONFIG REQUIRED)
|
||||
|
||||
# This will find the default system installation of Clang; if you want to
|
||||
# use a different build of clang, pass -DClang_DIR=/foobar/lib/cmake/clang
|
||||
# to the CMake configure command, where /foobar is the build directory where
|
||||
# you built Clang.
|
||||
find_package(Clang CONFIG REQUIRED)
|
||||
add_executable(my_clang_tool main.cpp)
|
||||
target_include_directories(my_clang_tool PRIVATE ${CLANG_INCLUDE_DIRS})
|
||||
target_link_libraries(my_clang_tool PRIVATE libclang)
|
||||
```
|
||||
|
||||
add_executable(my_clang_tool main.cpp)
|
||||
target_include_directories(my_clang_tool PRIVATE ${CLANG_INCLUDE_DIRS})
|
||||
target_link_libraries(my_clang_tool PRIVATE libclang)
|
||||
### Visiting elements of an AST
|
||||
|
||||
Visiting elements of an AST
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The elements of an AST can be recursively visited with pre-order traversal with ``clang_visitChildren``.
|
||||
The elements of an AST can be recursively visited with pre-order traversal with `clang_visitChildren`.
|
||||
|
||||
.. code-block:: cpp
|
||||
```cpp
|
||||
clang_visitChildren(
|
||||
cursor, //Root cursor
|
||||
[](CXCursor current_cursor, CXCursor parent, CXClientData client_data){
|
||||
|
||||
clang_visitChildren(
|
||||
cursor, //Root cursor
|
||||
[](CXCursor current_cursor, CXCursor parent, CXClientData client_data){
|
||||
CXString current_display_name = clang_getCursorDisplayName(current_cursor);
|
||||
//Allocate a CXString representing the name of the current cursor
|
||||
|
||||
CXString current_display_name = clang_getCursorDisplayName(current_cursor);
|
||||
//Allocate a CXString representing the name of the current cursor
|
||||
std::cout << "Visiting element " << clang_getCString(current_display_name) << "\n";
|
||||
//Print the char* value of current_display_name
|
||||
|
||||
std::cout << "Visiting element " << clang_getCString(current_display_name) << "\n";
|
||||
//Print the char* value of current_display_name
|
||||
clang_disposeString(current_display_name);
|
||||
//Since clang_getCursorDisplayName allocates a new CXString, it must be freed. This applies
|
||||
//to all functions returning a CXString
|
||||
|
||||
clang_disposeString(current_display_name);
|
||||
//Since clang_getCursorDisplayName allocates a new CXString, it must be freed. This applies
|
||||
//to all functions returning a CXString
|
||||
|
||||
return CXChildVisit_Recurse;
|
||||
return CXChildVisit_Recurse;
|
||||
|
||||
|
||||
}, //CXCursorVisitor: a function pointer
|
||||
nullptr //client_data
|
||||
);
|
||||
}, //CXCursorVisitor: a function pointer
|
||||
nullptr //client_data
|
||||
);
|
||||
```
|
||||
|
||||
The return value of ``CXCursorVisitor``, the callable argument of ``clang_visitChildren``, can return one of the three:
|
||||
The return value of `CXCursorVisitor`, the callable argument of `clang_visitChildren`, can return one of the three:
|
||||
|
||||
#. ``CXChildVisit_Break``: Terminates the cursor traversal
|
||||
|
||||
#. ``CXChildVisit_Continue``: Continues the cursor traversal with the next sibling of the cursor just visited, without visiting its children.
|
||||
|
||||
#. ``CXChildVisit_Recurse``: Recursively traverse the children of this cursor, using the same visitor and client data
|
||||
1. `CXChildVisit_Break`: Terminates the cursor traversal
|
||||
2. `CXChildVisit_Continue`: Continues the cursor traversal with the next sibling of the cursor just visited, without visiting its children.
|
||||
3. `CXChildVisit_Recurse`: Recursively traverse the children of this cursor, using the same visitor and client data
|
||||
|
||||
The expected output of that program is
|
||||
|
||||
.. code-block::
|
||||
```
|
||||
Visiting element foo
|
||||
Visiting element bar
|
||||
Visiting element bar_pointer
|
||||
```
|
||||
|
||||
Visiting element foo
|
||||
Visiting element bar
|
||||
Visiting element bar_pointer
|
||||
### Extracting information from a Cursor
|
||||
|
||||
% The following functions take a ``CXCursor`` as an argument and return associated information.
|
||||
|
||||
Extracting information from a Cursor
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.. The following functions take a ``CXCursor`` as an argument and return associated information.
|
||||
#### Extracting the Cursor kind
|
||||
|
||||
`CXCursorKind clang_getCursorKind(CXCursor)` Describes the kind of entity that a cursor refers to. Example values:
|
||||
|
||||
- `CXCursor_StructDecl`: A C or C++ struct.
|
||||
- `CXCursor_FieldDecl`: A field in a struct, union, or C++ class.
|
||||
- `CXCursor_CallExpr`: An expression that calls a function.
|
||||
|
||||
Extracting the Cursor kind
|
||||
""""""""""""""""""""""""""
|
||||
#### Extracting the Cursor type
|
||||
|
||||
``CXCursorKind clang_getCursorKind(CXCursor)`` Describes the kind of entity that a cursor refers to. Example values:
|
||||
`CXType clang_getCursorType(CXCursor)`: Retrieve the type of a CXCursor (if any).
|
||||
|
||||
- ``CXCursor_StructDecl``: A C or C++ struct.
|
||||
- ``CXCursor_FieldDecl``: A field in a struct, union, or C++ class.
|
||||
- ``CXCursor_CallExpr``: An expression that calls a function.
|
||||
A `CXType` represents a complete C++ type, including qualifiers and pointers. It has a member field `CXTypeKind kind` and additional opaque data.
|
||||
|
||||
Example values for `CXTypeKind kind`
|
||||
|
||||
Extracting the Cursor type
|
||||
""""""""""""""""""""""""""
|
||||
``CXType clang_getCursorType(CXCursor)``: Retrieve the type of a CXCursor (if any).
|
||||
- `CXType_Invalid`: Represents an invalid type (e.g., where no type is available)
|
||||
- `CXType_Pointer`: A pointer to another type
|
||||
- `CXType_Int`: Regular `int`
|
||||
- `CXType_Elaborated`: Represents a type that was referred to using an elaborated type keyword e.g. struct S, or via a qualified name, e.g., N::M::type, or both.
|
||||
|
||||
A ``CXType`` represents a complete C++ type, including qualifiers and pointers. It has a member field ``CXTypeKind kind`` and additional opaque data.
|
||||
Any `CXTypeKind` can be converted to a `CXString` using `clang_getTypeKindSpelling(CXTypeKind)`.
|
||||
|
||||
Example values for ``CXTypeKind kind``
|
||||
|
||||
- ``CXType_Invalid``: Represents an invalid type (e.g., where no type is available)
|
||||
- ``CXType_Pointer``: A pointer to another type
|
||||
- ``CXType_Int``: Regular ``int``
|
||||
- ``CXType_Elaborated``: Represents a type that was referred to using an elaborated type keyword e.g. struct S, or via a qualified name, e.g., N::M::type, or both.
|
||||
|
||||
Any ``CXTypeKind`` can be converted to a ``CXString`` using ``clang_getTypeKindSpelling(CXTypeKind)``.
|
||||
|
||||
A ``CXType`` holds additional necessary opaque type info, such as:
|
||||
A `CXType` holds additional necessary opaque type info, such as:
|
||||
|
||||
- Which struct was referred to?
|
||||
- What type is the pointer pointing to?
|
||||
- Qualifiers (e.g. ``const``, ``volatile``)?
|
||||
- Qualifiers (e.g. `const`, `volatile`)?
|
||||
|
||||
Qualifiers of a ``CXType`` can be queried with:
|
||||
Qualifiers of a `CXType` can be queried with:
|
||||
|
||||
- ``clang_isConstQualifiedType(CXType)`` to check for ``const``
|
||||
- ``clang_isRestrictQualifiedType(CXType)`` to check for ``restrict``
|
||||
- ``clang_isVolatileQualifiedType(CXType)`` to check for ``volatile``
|
||||
- `clang_isConstQualifiedType(CXType)` to check for `const`
|
||||
- `clang_isRestrictQualifiedType(CXType)` to check for `restrict`
|
||||
- `clang_isVolatileQualifiedType(CXType)` to check for `volatile`
|
||||
|
||||
Code example
|
||||
""""""""""""
|
||||
.. code-block:: cpp
|
||||
#### Code example
|
||||
|
||||
//structs.cpp
|
||||
struct A{
|
||||
int value;
|
||||
};
|
||||
struct B{
|
||||
int value;
|
||||
A struct_value;
|
||||
};
|
||||
```cpp
|
||||
//structs.cpp
|
||||
struct A{
|
||||
int value;
|
||||
};
|
||||
struct B{
|
||||
int value;
|
||||
A struct_value;
|
||||
};
|
||||
```
|
||||
|
||||
.. code-block:: cpp
|
||||
```cpp
|
||||
#include <clang-c/Index.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
#include <iostream>
|
||||
int main(){
|
||||
CXIndex index = clang_createIndex(0, 0); //Create index
|
||||
CXTranslationUnit unit = clang_parseTranslationUnit(
|
||||
index,
|
||||
"structs.cpp", nullptr, 0,
|
||||
nullptr, 0,
|
||||
CXTranslationUnit_None); //Parse "structs.cpp"
|
||||
|
||||
int main(){
|
||||
CXIndex index = clang_createIndex(0, 0); //Create index
|
||||
CXTranslationUnit unit = clang_parseTranslationUnit(
|
||||
index,
|
||||
"structs.cpp", nullptr, 0,
|
||||
nullptr, 0,
|
||||
CXTranslationUnit_None); //Parse "structs.cpp"
|
||||
if (unit == nullptr){
|
||||
std::cerr << "Unable to parse translation unit. Quitting.\n";
|
||||
return 0;
|
||||
}
|
||||
CXCursor cursor = clang_getTranslationUnitCursor(unit); //Obtain a cursor at the root of the translation unit
|
||||
|
||||
if (unit == nullptr){
|
||||
std::cerr << "Unable to parse translation unit. Quitting.\n";
|
||||
return 0;
|
||||
clang_visitChildren(
|
||||
cursor,
|
||||
[](CXCursor current_cursor, CXCursor parent, CXClientData client_data){
|
||||
CXType cursor_type = clang_getCursorType(current_cursor);
|
||||
|
||||
CXString type_kind_spelling = clang_getTypeKindSpelling(cursor_type.kind);
|
||||
std::cout << "Type Kind: " << clang_getCString(type_kind_spelling);
|
||||
clang_disposeString(type_kind_spelling);
|
||||
|
||||
if(cursor_type.kind == CXType_Pointer || // If cursor_type is a pointer
|
||||
cursor_type.kind == CXType_LValueReference || // or an LValue Reference (&)
|
||||
cursor_type.kind == CXType_RValueReference){ // or an RValue Reference (&&),
|
||||
CXType pointed_to_type = clang_getPointeeType(cursor_type);// retrieve the pointed-to type
|
||||
|
||||
CXString pointed_to_type_spelling = clang_getTypeSpelling(pointed_to_type); // Spell out the entire
|
||||
std::cout << "pointing to type: " << clang_getCString(pointed_to_type_spelling);// pointed-to type
|
||||
clang_disposeString(pointed_to_type_spelling);
|
||||
}
|
||||
CXCursor cursor = clang_getTranslationUnitCursor(unit); //Obtain a cursor at the root of the translation unit
|
||||
|
||||
clang_visitChildren(
|
||||
cursor,
|
||||
[](CXCursor current_cursor, CXCursor parent, CXClientData client_data){
|
||||
CXType cursor_type = clang_getCursorType(current_cursor);
|
||||
|
||||
CXString type_kind_spelling = clang_getTypeKindSpelling(cursor_type.kind);
|
||||
std::cout << "Type Kind: " << clang_getCString(type_kind_spelling);
|
||||
clang_disposeString(type_kind_spelling);
|
||||
|
||||
if(cursor_type.kind == CXType_Pointer || // If cursor_type is a pointer
|
||||
cursor_type.kind == CXType_LValueReference || // or an LValue Reference (&)
|
||||
cursor_type.kind == CXType_RValueReference){ // or an RValue Reference (&&),
|
||||
CXType pointed_to_type = clang_getPointeeType(cursor_type);// retrieve the pointed-to type
|
||||
|
||||
CXString pointed_to_type_spelling = clang_getTypeSpelling(pointed_to_type); // Spell out the entire
|
||||
std::cout << "pointing to type: " << clang_getCString(pointed_to_type_spelling);// pointed-to type
|
||||
clang_disposeString(pointed_to_type_spelling);
|
||||
}
|
||||
else if(cursor_type.kind == CXType_Record){
|
||||
CXString type_spelling = clang_getTypeSpelling(cursor_type);
|
||||
std::cout << ", namely " << clang_getCString(type_spelling);
|
||||
clang_disposeString(type_spelling);
|
||||
}
|
||||
std::cout << "\n";
|
||||
return CXChildVisit_Recurse;
|
||||
},
|
||||
nullptr
|
||||
);
|
||||
else if(cursor_type.kind == CXType_Record){
|
||||
CXString type_spelling = clang_getTypeSpelling(cursor_type);
|
||||
std::cout << ", namely " << clang_getCString(type_spelling);
|
||||
clang_disposeString(type_spelling);
|
||||
}
|
||||
std::cout << "\n";
|
||||
return CXChildVisit_Recurse;
|
||||
},
|
||||
nullptr
|
||||
);
|
||||
```
|
||||
|
||||
The expected output of program is:
|
||||
|
||||
.. code-block::
|
||||
```
|
||||
Type Kind: Record, namely A
|
||||
Type Kind: Int
|
||||
Type Kind: Record, namely B
|
||||
Type Kind: Int
|
||||
Type Kind: Record, namely A
|
||||
Type Kind: Record, namely A
|
||||
```
|
||||
|
||||
Type Kind: Record, namely A
|
||||
Type Kind: Int
|
||||
Type Kind: Record, namely B
|
||||
Type Kind: Int
|
||||
Type Kind: Record, namely A
|
||||
Type Kind: Record, namely A
|
||||
Reiterating the difference between `CXType` and `CXTypeKind`: For an example
|
||||
|
||||
```cpp
|
||||
const char* __restrict__ variable;
|
||||
```
|
||||
|
||||
Reiterating the difference between ``CXType`` and ``CXTypeKind``: For an example
|
||||
- Type Kind will be: `CXType_Pointer` spelled `"Pointer"`
|
||||
- Type will be a complex `CXType` structure, spelled `"const char* __restrict__`
|
||||
|
||||
.. code-block:: cpp
|
||||
#### Retrieving source locations
|
||||
|
||||
const char* __restrict__ variable;
|
||||
`CXSourceRange clang_getCursorExtent(CXCursor)` returns a `CXSourceRange`, representing a half-open range in the source code.
|
||||
|
||||
- Type Kind will be: ``CXType_Pointer`` spelled ``"Pointer"``
|
||||
- Type will be a complex ``CXType`` structure, spelled ``"const char* __restrict__``
|
||||
Use `clang_getRangeStart(CXSourceRange)` and `clang_getRangeEnd(CXSourceRange)` to retrieve the starting and end `CXSourceLocation` from a source range, respectively.
|
||||
|
||||
Retrieving source locations
|
||||
"""""""""""""""""""""""""""
|
||||
Given a `CXSourceLocation`, use `clang_getExpansionLocation` to retrieve file, line and column of a source location.
|
||||
|
||||
``CXSourceRange clang_getCursorExtent(CXCursor)`` returns a ``CXSourceRange``, representing a half-open range in the source code.
|
||||
#### Code example
|
||||
|
||||
Use ``clang_getRangeStart(CXSourceRange)`` and ``clang_getRangeEnd(CXSourceRange)`` to retrieve the starting and end ``CXSourceLocation`` from a source range, respectively.
|
||||
```cpp
|
||||
// Again, file.cpp
|
||||
struct foo{
|
||||
int bar;
|
||||
int* bar_pointer;
|
||||
};
|
||||
```
|
||||
|
||||
Given a ``CXSourceLocation``, use ``clang_getExpansionLocation`` to retrieve file, line and column of a source location.
|
||||
```cpp
|
||||
clang_visitChildren(
|
||||
cursor,
|
||||
[](CXCursor current_cursor, CXCursor parent, CXClientData client_data){
|
||||
|
||||
Code example
|
||||
""""""""""""
|
||||
.. code-block:: cpp
|
||||
CXType cursor_type = clang_getCursorType(current_cursor);
|
||||
CXString cursor_spelling = clang_getCursorSpelling(current_cursor);
|
||||
CXSourceRange cursor_range = clang_getCursorExtent(current_cursor);
|
||||
std::cout << "Cursor " << clang_getCString(cursor_spelling);
|
||||
|
||||
// Again, file.cpp
|
||||
struct foo{
|
||||
int bar;
|
||||
int* bar_pointer;
|
||||
};
|
||||
.. code-block:: cpp
|
||||
CXFile file;
|
||||
unsigned start_line, start_column, start_offset;
|
||||
unsigned end_line, end_column, end_offset;
|
||||
|
||||
clang_visitChildren(
|
||||
cursor,
|
||||
[](CXCursor current_cursor, CXCursor parent, CXClientData client_data){
|
||||
clang_getExpansionLocation(clang_getRangeStart(cursor_range), &file, &start_line, &start_column, &start_offset);
|
||||
clang_getExpansionLocation(clang_getRangeEnd (cursor_range), &file, &end_line , &end_column , &end_offset);
|
||||
std::cout << " spanning lines " << start_line << " to " << end_line;
|
||||
clang_disposeString(cursor_spelling);
|
||||
|
||||
CXType cursor_type = clang_getCursorType(current_cursor);
|
||||
CXString cursor_spelling = clang_getCursorSpelling(current_cursor);
|
||||
CXSourceRange cursor_range = clang_getCursorExtent(current_cursor);
|
||||
std::cout << "Cursor " << clang_getCString(cursor_spelling);
|
||||
|
||||
CXFile file;
|
||||
unsigned start_line, start_column, start_offset;
|
||||
unsigned end_line, end_column, end_offset;
|
||||
|
||||
clang_getExpansionLocation(clang_getRangeStart(cursor_range), &file, &start_line, &start_column, &start_offset);
|
||||
clang_getExpansionLocation(clang_getRangeEnd (cursor_range), &file, &end_line , &end_column , &end_offset);
|
||||
std::cout << " spanning lines " << start_line << " to " << end_line;
|
||||
clang_disposeString(cursor_spelling);
|
||||
|
||||
std::cout << "\n";
|
||||
return CXChildVisit_Recurse;
|
||||
},
|
||||
nullptr
|
||||
);
|
||||
std::cout << "\n";
|
||||
return CXChildVisit_Recurse;
|
||||
},
|
||||
nullptr
|
||||
);
|
||||
```
|
||||
|
||||
The expected output of this program is:
|
||||
|
||||
.. code-block::
|
||||
```
|
||||
Cursor foo spanning lines 2 to 5
|
||||
Cursor bar spanning lines 3 to 3
|
||||
Cursor bar_pointer spanning lines 4 to 4
|
||||
```
|
||||
|
||||
Cursor foo spanning lines 2 to 5
|
||||
Cursor bar spanning lines 3 to 3
|
||||
Cursor bar_pointer spanning lines 4 to 4
|
||||
### Complete example code
|
||||
|
||||
Complete example code
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
```cpp
|
||||
// main.cpp
|
||||
#include <clang-c/Index.h>
|
||||
#include <iostream>
|
||||
|
||||
.. code-block:: cpp
|
||||
int main(){
|
||||
CXIndex index = clang_createIndex(0, 0); //Create index
|
||||
CXTranslationUnit unit = clang_parseTranslationUnit(
|
||||
index,
|
||||
"file.cpp", nullptr, 0,
|
||||
nullptr, 0,
|
||||
CXTranslationUnit_None); //Parse "file.cpp"
|
||||
|
||||
// main.cpp
|
||||
#include <clang-c/Index.h>
|
||||
#include <iostream>
|
||||
|
||||
int main(){
|
||||
CXIndex index = clang_createIndex(0, 0); //Create index
|
||||
CXTranslationUnit unit = clang_parseTranslationUnit(
|
||||
index,
|
||||
"file.cpp", nullptr, 0,
|
||||
nullptr, 0,
|
||||
CXTranslationUnit_None); //Parse "file.cpp"
|
||||
|
||||
if (unit == nullptr){
|
||||
std::cerr << "Unable to parse translation unit. Quitting.\n";
|
||||
return 0;
|
||||
}
|
||||
CXCursor cursor = clang_getTranslationUnitCursor(unit); //Obtain a cursor at the root of the translation unit
|
||||
|
||||
|
||||
clang_visitChildren(
|
||||
cursor,
|
||||
[](CXCursor current_cursor, CXCursor parent, CXClientData client_data){
|
||||
CXType cursor_type = clang_getCursorType(current_cursor);
|
||||
|
||||
CXString type_kind_spelling = clang_getTypeKindSpelling(cursor_type.kind);
|
||||
std::cout << "TypeKind: " << clang_getCString(type_kind_spelling);
|
||||
clang_disposeString(type_kind_spelling);
|
||||
|
||||
if(cursor_type.kind == CXType_Pointer || // If cursor_type is a pointer
|
||||
cursor_type.kind == CXType_LValueReference || // or an LValue Reference (&)
|
||||
cursor_type.kind == CXType_RValueReference){ // or an RValue Reference (&&),
|
||||
CXType pointed_to_type = clang_getPointeeType(cursor_type);// retrieve the pointed-to type
|
||||
|
||||
CXString pointed_to_type_spelling = clang_getTypeSpelling(pointed_to_type); // Spell out the entire
|
||||
std::cout << "pointing to type: " << clang_getCString(pointed_to_type_spelling);// pointed-to type
|
||||
clang_disposeString(pointed_to_type_spelling);
|
||||
}
|
||||
else if(cursor_type.kind == CXType_Record){
|
||||
CXString type_spelling = clang_getTypeSpelling(cursor_type);
|
||||
std::cout << ", namely " << clang_getCString(type_spelling);
|
||||
clang_disposeString(type_spelling);
|
||||
}
|
||||
std::cout << "\n";
|
||||
return CXChildVisit_Recurse;
|
||||
},
|
||||
nullptr
|
||||
);
|
||||
|
||||
|
||||
clang_visitChildren(
|
||||
cursor,
|
||||
[](CXCursor current_cursor, CXCursor parent, CXClientData client_data){
|
||||
|
||||
CXType cursor_type = clang_getCursorType(current_cursor);
|
||||
CXString cursor_spelling = clang_getCursorSpelling(current_cursor);
|
||||
CXSourceRange cursor_range = clang_getCursorExtent(current_cursor);
|
||||
std::cout << "Cursor " << clang_getCString(cursor_spelling);
|
||||
|
||||
CXFile file;
|
||||
unsigned start_line, start_column, start_offset;
|
||||
unsigned end_line, end_column, end_offset;
|
||||
|
||||
clang_getExpansionLocation(clang_getRangeStart(cursor_range), &file, &start_line, &start_column, &start_offset);
|
||||
clang_getExpansionLocation(clang_getRangeEnd (cursor_range), &file, &end_line , &end_column , &end_offset);
|
||||
std::cout << " spanning lines " << start_line << " to " << end_line;
|
||||
clang_disposeString(cursor_spelling);
|
||||
|
||||
std::cout << "\n";
|
||||
return CXChildVisit_Recurse;
|
||||
},
|
||||
nullptr
|
||||
);
|
||||
if (unit == nullptr){
|
||||
std::cerr << "Unable to parse translation unit. Quitting.\n";
|
||||
return 0;
|
||||
}
|
||||
CXCursor cursor = clang_getTranslationUnitCursor(unit); //Obtain a cursor at the root of the translation unit
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
# CMakeLists.txt
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(my_clang_tool VERSION 0.1.0)
|
||||
clang_visitChildren(
|
||||
cursor,
|
||||
[](CXCursor current_cursor, CXCursor parent, CXClientData client_data){
|
||||
CXType cursor_type = clang_getCursorType(current_cursor);
|
||||
|
||||
# This will find the default system installation of Clang; if you want to
|
||||
# use a different build of clang, pass -DClang_DIR=/foobar/lib/cmake/clang
|
||||
# to the CMake configure command, where /foobar is the build directory where
|
||||
# you built Clang.
|
||||
find_package(Clang CONFIG REQUIRED)
|
||||
CXString type_kind_spelling = clang_getTypeKindSpelling(cursor_type.kind);
|
||||
std::cout << "TypeKind: " << clang_getCString(type_kind_spelling);
|
||||
clang_disposeString(type_kind_spelling);
|
||||
|
||||
add_executable(my_clang_tool main.cpp)
|
||||
target_include_directories(my_clang_tool PRIVATE ${CLANG_INCLUDE_DIRS})
|
||||
target_link_libraries(my_clang_tool PRIVATE libclang)
|
||||
if(cursor_type.kind == CXType_Pointer || // If cursor_type is a pointer
|
||||
cursor_type.kind == CXType_LValueReference || // or an LValue Reference (&)
|
||||
cursor_type.kind == CXType_RValueReference){ // or an RValue Reference (&&),
|
||||
CXType pointed_to_type = clang_getPointeeType(cursor_type);// retrieve the pointed-to type
|
||||
|
||||
.. _Index.h: https://github.com/llvm/llvm-project/blob/main/clang/include/clang-c/Index.h
|
||||
CXString pointed_to_type_spelling = clang_getTypeSpelling(pointed_to_type); // Spell out the entire
|
||||
std::cout << "pointing to type: " << clang_getCString(pointed_to_type_spelling);// pointed-to type
|
||||
clang_disposeString(pointed_to_type_spelling);
|
||||
}
|
||||
else if(cursor_type.kind == CXType_Record){
|
||||
CXString type_spelling = clang_getTypeSpelling(cursor_type);
|
||||
std::cout << ", namely " << clang_getCString(type_spelling);
|
||||
clang_disposeString(type_spelling);
|
||||
}
|
||||
std::cout << "\n";
|
||||
return CXChildVisit_Recurse;
|
||||
},
|
||||
nullptr
|
||||
);
|
||||
|
||||
.. _Stability:
|
||||
|
||||
ABI and API Stability
|
||||
---------------------
|
||||
clang_visitChildren(
|
||||
cursor,
|
||||
[](CXCursor current_cursor, CXCursor parent, CXClientData client_data){
|
||||
|
||||
CXType cursor_type = clang_getCursorType(current_cursor);
|
||||
CXString cursor_spelling = clang_getCursorSpelling(current_cursor);
|
||||
CXSourceRange cursor_range = clang_getCursorExtent(current_cursor);
|
||||
std::cout << "Cursor " << clang_getCString(cursor_spelling);
|
||||
|
||||
CXFile file;
|
||||
unsigned start_line, start_column, start_offset;
|
||||
unsigned end_line, end_column, end_offset;
|
||||
|
||||
clang_getExpansionLocation(clang_getRangeStart(cursor_range), &file, &start_line, &start_column, &start_offset);
|
||||
clang_getExpansionLocation(clang_getRangeEnd (cursor_range), &file, &end_line , &end_column , &end_offset);
|
||||
std::cout << " spanning lines " << start_line << " to " << end_line;
|
||||
clang_disposeString(cursor_spelling);
|
||||
|
||||
std::cout << "\n";
|
||||
return CXChildVisit_Recurse;
|
||||
},
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```cmake
|
||||
# CMakeLists.txt
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(my_clang_tool VERSION 0.1.0)
|
||||
|
||||
# This will find the default system installation of Clang; if you want to
|
||||
# use a different build of clang, pass -DClang_DIR=/foobar/lib/cmake/clang
|
||||
# to the CMake configure command, where /foobar is the build directory where
|
||||
# you built Clang.
|
||||
find_package(Clang CONFIG REQUIRED)
|
||||
|
||||
add_executable(my_clang_tool main.cpp)
|
||||
target_include_directories(my_clang_tool PRIVATE ${CLANG_INCLUDE_DIRS})
|
||||
target_link_libraries(my_clang_tool PRIVATE libclang)
|
||||
```
|
||||
|
||||
(stability)=
|
||||
|
||||
## ABI and API Stability
|
||||
|
||||
The C interfaces in libclang are intended to be relatively stable. This allows
|
||||
a programmer to use libclang without having to worry as much about Clang
|
||||
|
|
@ -408,38 +390,39 @@ fixed, features get implemented, etc.
|
|||
The library should be ABI and API stable over time, but ABI- and API-breaking
|
||||
changes can happen in the following (non-exhaustive) situations:
|
||||
|
||||
* Adding new enumerator to an enumeration (can be ABI-breaking in C++).
|
||||
* Removing an explicitly deprecated API after a suitably long deprecation
|
||||
- Adding new enumerator to an enumeration (can be ABI-breaking in C++).
|
||||
- Removing an explicitly deprecated API after a suitably long deprecation
|
||||
period.
|
||||
* Using implementation details, such as names or comments that say something
|
||||
- Using implementation details, such as names or comments that say something
|
||||
is "private", "reserved", "internal", etc.
|
||||
* Bug fixes and changes to Clang's internal implementation happen routinely and
|
||||
- Bug fixes and changes to Clang's internal implementation happen routinely and
|
||||
will change the behavior of callers.
|
||||
* Rarely, bug fixes to libclang itself.
|
||||
- Rarely, bug fixes to libclang itself.
|
||||
|
||||
The library has version macros (``CINDEX_VERSION_MAJOR``,
|
||||
``CINDEX_VERSION_MINOR``, and ``CINDEX_VERSION``) which can be used to test for
|
||||
specific library versions at compile time. The ``CINDEX_VERSION_MAJOR`` macro
|
||||
The library has version macros (`CINDEX_VERSION_MAJOR`,
|
||||
`CINDEX_VERSION_MINOR`, and `CINDEX_VERSION`) which can be used to test for
|
||||
specific library versions at compile time. The `CINDEX_VERSION_MAJOR` macro
|
||||
is only incremented if there are major source- or ABI-breaking changes. Except
|
||||
for removing an explicitly deprecated API, the changes listed above are not
|
||||
considered major source- or ABI-breaking changes. Historically, the value this
|
||||
macro expands to has not changed, but may be incremented in the future should
|
||||
the need arise. The ``CINDEX_VERSION_MINOR`` macro is incremented as new APIs
|
||||
are added. The ``CINDEX_VERSION`` macro expands to a value based on the major
|
||||
the need arise. The `CINDEX_VERSION_MINOR` macro is incremented as new APIs
|
||||
are added. The `CINDEX_VERSION` macro expands to a value based on the major
|
||||
and minor version macros.
|
||||
|
||||
In an effort to allow the library to be modified as new needs arise, the
|
||||
following situations are explicitly unsupported:
|
||||
|
||||
* Loading different library versions into the same executable and passing
|
||||
- Loading different library versions into the same executable and passing
|
||||
objects between the libraries; despite general ABI stability, different
|
||||
versions of the library may use different implementation details that are not
|
||||
compatible across library versions.
|
||||
* For the same reason as above, serializing objects from one version of the
|
||||
- For the same reason as above, serializing objects from one version of the
|
||||
library and deserializing with a different version is also not supported.
|
||||
|
||||
Note: because libclang is a wrapper around the compiler frontend, it is not a
|
||||
`security-sensitive component`_ of the LLVM Project. Consider using a sandbox
|
||||
[security-sensitive component] of the LLVM Project. Consider using a sandbox
|
||||
or some other mitigation approach if processing untrusted input.
|
||||
|
||||
.. _security-sensitive component: https://llvm.org/docs/Security.html#what-is-considered-a-security-issue
|
||||
[index.h]: https://github.com/llvm/llvm-project/blob/main/clang/include/clang-c/Index.h
|
||||
[security-sensitive component]: https://llvm.org/docs/Security.html#what-is-considered-a-security-issue
|
||||
|
|
|
|||
|
|
@ -1,78 +1,72 @@
|
|||
=========
|
||||
LibFormat
|
||||
=========
|
||||
# LibFormat
|
||||
|
||||
LibFormat is a library that implements automatic source code formatting based
|
||||
on Clang. This document describes the LibFormat interface and design as well
|
||||
as some basic style discussions.
|
||||
|
||||
If you just want to use `clang-format` as a tool or integrated into an editor,
|
||||
checkout :doc:`ClangFormat`.
|
||||
checkout {doc}`ClangFormat`.
|
||||
|
||||
Design
|
||||
------
|
||||
## Design
|
||||
|
||||
FIXME: Write up design.
|
||||
|
||||
## Interface
|
||||
|
||||
Interface
|
||||
---------
|
||||
The core routine of LibFormat is `reformat()`:
|
||||
|
||||
The core routine of LibFormat is ``reformat()``:
|
||||
```c++
|
||||
tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
|
||||
SourceManager &SourceMgr,
|
||||
std::vector<CharSourceRange> Ranges);
|
||||
```
|
||||
|
||||
.. code-block:: c++
|
||||
This reads a token stream out of the lexer `Lex` and reformats all the code
|
||||
ranges in `Ranges`. The `FormatStyle` controls basic decisions made during
|
||||
formatting. A list of options can be found under {ref}`style-options`.
|
||||
|
||||
tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
|
||||
SourceManager &SourceMgr,
|
||||
std::vector<CharSourceRange> Ranges);
|
||||
The style options are described in {doc}`ClangFormatStyleOptions`.
|
||||
|
||||
This reads a token stream out of the lexer ``Lex`` and reformats all the code
|
||||
ranges in ``Ranges``. The ``FormatStyle`` controls basic decisions made during
|
||||
formatting. A list of options can be found under :ref:`style-options`.
|
||||
(style-options)=
|
||||
|
||||
The style options are described in :doc:`ClangFormatStyleOptions`.
|
||||
|
||||
|
||||
.. _style-options:
|
||||
|
||||
Style Options
|
||||
-------------
|
||||
## Style Options
|
||||
|
||||
The style options describe specific formatting options that can be used in
|
||||
order to make `ClangFormat` comply with different style guides. Currently,
|
||||
several style guides are hard-coded:
|
||||
|
||||
.. code-block:: c++
|
||||
```c++
|
||||
/// Returns a format style complying with the LLVM coding standards:
|
||||
/// https://llvm.org/docs/CodingStandards.html.
|
||||
FormatStyle getLLVMStyle();
|
||||
|
||||
/// Returns a format style complying with the LLVM coding standards:
|
||||
/// https://llvm.org/docs/CodingStandards.html.
|
||||
FormatStyle getLLVMStyle();
|
||||
/// Returns a format style complying with Google's C++ style guide:
|
||||
/// http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml.
|
||||
FormatStyle getGoogleStyle();
|
||||
|
||||
/// Returns a format style complying with Google's C++ style guide:
|
||||
/// http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml.
|
||||
FormatStyle getGoogleStyle();
|
||||
/// Returns a format style complying with Chromium's style guide:
|
||||
/// https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/styleguide.md
|
||||
FormatStyle getChromiumStyle();
|
||||
|
||||
/// Returns a format style complying with Chromium's style guide:
|
||||
/// https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/styleguide.md
|
||||
FormatStyle getChromiumStyle();
|
||||
/// Returns a format style complying with the GNU coding standards:
|
||||
/// https://www.gnu.org/prep/standards/standards.html
|
||||
FormatStyle getGNUStyle();
|
||||
|
||||
/// Returns a format style complying with the GNU coding standards:
|
||||
/// https://www.gnu.org/prep/standards/standards.html
|
||||
FormatStyle getGNUStyle();
|
||||
/// Returns a format style complying with Mozilla's style guide
|
||||
/// https://firefox-source-docs.mozilla.org/code-quality/coding-style/index.html
|
||||
FormatStyle getMozillaStyle();
|
||||
|
||||
/// Returns a format style complying with Mozilla's style guide
|
||||
/// https://firefox-source-docs.mozilla.org/code-quality/coding-style/index.html
|
||||
FormatStyle getMozillaStyle();
|
||||
/// Returns a format style complying with Webkit's style guide:
|
||||
/// https://webkit.org/code-style-guidelines/
|
||||
FormatStyle getWebkitStyle();
|
||||
|
||||
/// Returns a format style complying with Webkit's style guide:
|
||||
/// https://webkit.org/code-style-guidelines/
|
||||
FormatStyle getWebkitStyle();
|
||||
/// Returns a format style complying with Microsoft's style guide:
|
||||
/// https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
|
||||
FormatStyle getMicrosoftStyle();
|
||||
```
|
||||
|
||||
/// Returns a format style complying with Microsoft's style guide:
|
||||
/// https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
|
||||
FormatStyle getMicrosoftStyle();
|
||||
|
||||
These options are also exposed in the :doc:`standalone tools <ClangFormat>`
|
||||
These options are also exposed in the {doc}`standalone tools <ClangFormat>`
|
||||
through the `-style` option.
|
||||
|
||||
In the future, we plan on making this configurable.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,213 +1,200 @@
|
|||
==========
|
||||
LibTooling
|
||||
==========
|
||||
# LibTooling
|
||||
|
||||
LibTooling is a library to support writing standalone tools based on Clang.
|
||||
This document will provide a basic walkthrough of how to write a tool using
|
||||
LibTooling.
|
||||
|
||||
For the information on how to setup Clang Tooling for LLVM see
|
||||
:doc:`HowToSetupToolingForLLVM`
|
||||
{doc}`HowToSetupToolingForLLVM`
|
||||
|
||||
Introduction
|
||||
------------
|
||||
## Introduction
|
||||
|
||||
Tools built with LibTooling, like Clang Plugins, run ``FrontendActions`` over
|
||||
Tools built with LibTooling, like Clang Plugins, run `FrontendActions` over
|
||||
code.
|
||||
|
||||
.. See FIXME for a tutorial on how to write FrontendActions.
|
||||
% See FIXME for a tutorial on how to write FrontendActions.
|
||||
|
||||
In this tutorial, we'll demonstrate the different ways of running Clang's
|
||||
``SyntaxOnlyAction``, which runs a quick syntax check, over a bunch of code.
|
||||
`SyntaxOnlyAction`, which runs a quick syntax check, over a bunch of code.
|
||||
|
||||
Parsing a code snippet in memory
|
||||
--------------------------------
|
||||
## Parsing a code snippet in memory
|
||||
|
||||
If you ever wanted to run a ``FrontendAction`` over some sample code, for
|
||||
example to unit test parts of the Clang AST, ``runToolOnCode`` is what you
|
||||
looked for. Let me give you an example:
|
||||
If you ever wanted to run a `FrontendAction` over some sample code, for
|
||||
example to unit test parts of the Clang AST, `runToolOnCode` is what you
|
||||
looked for. Let me give you an example:
|
||||
|
||||
.. code-block:: c++
|
||||
```c++
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
TEST(runToolOnCode, CanSyntaxCheckCode) {
|
||||
// runToolOnCode returns whether the action was correctly run over the
|
||||
// given code.
|
||||
EXPECT_TRUE(runToolOnCode(std::make_unique<clang::SyntaxOnlyAction>(), "class X {};"));
|
||||
}
|
||||
```
|
||||
|
||||
TEST(runToolOnCode, CanSyntaxCheckCode) {
|
||||
// runToolOnCode returns whether the action was correctly run over the
|
||||
// given code.
|
||||
EXPECT_TRUE(runToolOnCode(std::make_unique<clang::SyntaxOnlyAction>(), "class X {};"));
|
||||
}
|
||||
## Writing a standalone tool
|
||||
|
||||
Writing a standalone tool
|
||||
-------------------------
|
||||
|
||||
Once you unit tested your ``FrontendAction`` to the point where it cannot
|
||||
possibly break, it's time to create a standalone tool. For a standalone tool
|
||||
Once you unit tested your `FrontendAction` to the point where it cannot
|
||||
possibly break, it's time to create a standalone tool. For a standalone tool
|
||||
to run clang, it first needs to figure out what command line arguments to use
|
||||
for a specified file. To that end we create a ``CompilationDatabase``. There
|
||||
for a specified file. To that end we create a `CompilationDatabase`. There
|
||||
are different ways to create a compilation database, and we need to support all
|
||||
of them depending on command-line options. There's the ``CommonOptionsParser``
|
||||
of them depending on command-line options. There's the `CommonOptionsParser`
|
||||
class that takes the responsibility to parse command-line parameters related to
|
||||
compilation databases and inputs, so that all tools share the implementation.
|
||||
|
||||
Parsing common tools options
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
### Parsing common tools options
|
||||
|
||||
``CompilationDatabase`` can be read from a build directory or the command line.
|
||||
Using ``CommonOptionsParser`` allows for explicit specification of a compile
|
||||
command line, specification of build path using the ``-p`` command-line option,
|
||||
`CompilationDatabase` can be read from a build directory or the command line.
|
||||
Using `CommonOptionsParser` allows for explicit specification of a compile
|
||||
command line, specification of build path using the `-p` command-line option,
|
||||
and automatic location of the compilation database using source files paths.
|
||||
|
||||
.. code-block:: c++
|
||||
```c++
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
using namespace clang::tooling;
|
||||
using namespace llvm;
|
||||
|
||||
using namespace clang::tooling;
|
||||
using namespace llvm;
|
||||
// Apply a custom category to all command-line options so that they are the
|
||||
// only ones displayed.
|
||||
static cl::OptionCategory MyToolCategory("my-tool options");
|
||||
|
||||
// Apply a custom category to all command-line options so that they are the
|
||||
// only ones displayed.
|
||||
static cl::OptionCategory MyToolCategory("my-tool options");
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
// CommonOptionsParser::create will parse arguments and create a
|
||||
// CompilationDatabase.
|
||||
auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory);
|
||||
if (!ExpectedParser) {
|
||||
// Fail gracefully for unsupported options.
|
||||
llvm::errs() << toString(ExpectedParser.takeError());
|
||||
return 1;
|
||||
}
|
||||
CommonOptionsParser& OptionsParser = ExpectedParser.get();
|
||||
|
||||
// Use OptionsParser.getCompilations() and OptionsParser.getSourcePathList()
|
||||
// to retrieve CompilationDatabase and the list of input file paths.
|
||||
int main(int argc, const char **argv) {
|
||||
// CommonOptionsParser::create will parse arguments and create a
|
||||
// CompilationDatabase.
|
||||
auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory);
|
||||
if (!ExpectedParser) {
|
||||
// Fail gracefully for unsupported options.
|
||||
llvm::errs() << toString(ExpectedParser.takeError());
|
||||
return 1;
|
||||
}
|
||||
CommonOptionsParser& OptionsParser = ExpectedParser.get();
|
||||
|
||||
Creating and running a ClangTool
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// Use OptionsParser.getCompilations() and OptionsParser.getSourcePathList()
|
||||
// to retrieve CompilationDatabase and the list of input file paths.
|
||||
}
|
||||
```
|
||||
|
||||
Once we have a ``CompilationDatabase``, we can create a ``ClangTool`` and run
|
||||
our ``FrontendAction`` over some code. For example, to run the
|
||||
``SyntaxOnlyAction`` over the files "a.cc" and "b.cc" one would write:
|
||||
### Creating and running a ClangTool
|
||||
|
||||
.. code-block:: c++
|
||||
Once we have a `CompilationDatabase`, we can create a `ClangTool` and run
|
||||
our `FrontendAction` over some code. For example, to run the
|
||||
`SyntaxOnlyAction` over the files "a.cc" and "b.cc" one would write:
|
||||
|
||||
// A clang tool can run over a number of sources in the same process...
|
||||
std::vector<std::string> Sources;
|
||||
Sources.push_back("a.cc");
|
||||
Sources.push_back("b.cc");
|
||||
```c++
|
||||
// A clang tool can run over a number of sources in the same process...
|
||||
std::vector<std::string> Sources;
|
||||
Sources.push_back("a.cc");
|
||||
Sources.push_back("b.cc");
|
||||
|
||||
// We hand the CompilationDatabase we created and the sources to run over into
|
||||
// the tool constructor.
|
||||
ClangTool Tool(OptionsParser.getCompilations(), Sources);
|
||||
// We hand the CompilationDatabase we created and the sources to run over into
|
||||
// the tool constructor.
|
||||
ClangTool Tool(OptionsParser.getCompilations(), Sources);
|
||||
|
||||
// The ClangTool needs a new FrontendAction for each translation unit we run
|
||||
// on. Thus, it takes a FrontendActionFactory as parameter. To create a
|
||||
// FrontendActionFactory from a given FrontendAction type, we call
|
||||
// newFrontendActionFactory<clang::SyntaxOnlyAction>().
|
||||
int result = Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>().get());
|
||||
// The ClangTool needs a new FrontendAction for each translation unit we run
|
||||
// on. Thus, it takes a FrontendActionFactory as parameter. To create a
|
||||
// FrontendActionFactory from a given FrontendAction type, we call
|
||||
// newFrontendActionFactory<clang::SyntaxOnlyAction>().
|
||||
int result = Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>().get());
|
||||
```
|
||||
|
||||
Putting it together --- the first tool
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
### Putting it together --- the first tool
|
||||
|
||||
Now we combine the two previous steps into our first real tool. A more advanced
|
||||
Now we combine the two previous steps into our first real tool. A more advanced
|
||||
version of this example tool is also checked into the clang tree at
|
||||
``tools/clang-check/ClangCheck.cpp``.
|
||||
`tools/clang-check/ClangCheck.cpp`.
|
||||
|
||||
.. code-block:: c++
|
||||
```c++
|
||||
// Declares clang::SyntaxOnlyAction.
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
// Declares llvm::cl::extrahelp.
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
// Declares clang::SyntaxOnlyAction.
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
// Declares llvm::cl::extrahelp.
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
using namespace clang::tooling;
|
||||
using namespace llvm;
|
||||
|
||||
using namespace clang::tooling;
|
||||
using namespace llvm;
|
||||
// Apply a custom category to all command-line options so that they are the
|
||||
// only ones displayed.
|
||||
static cl::OptionCategory MyToolCategory("my-tool options");
|
||||
|
||||
// Apply a custom category to all command-line options so that they are the
|
||||
// only ones displayed.
|
||||
static cl::OptionCategory MyToolCategory("my-tool options");
|
||||
// CommonOptionsParser declares HelpMessage with a description of the common
|
||||
// command-line options related to the compilation database and input files.
|
||||
// It's nice to have this help message in all tools.
|
||||
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
|
||||
|
||||
// CommonOptionsParser declares HelpMessage with a description of the common
|
||||
// command-line options related to the compilation database and input files.
|
||||
// It's nice to have this help message in all tools.
|
||||
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
|
||||
// A help message for this specific tool can be added afterwards.
|
||||
static cl::extrahelp MoreHelp("\nMore help text...\n");
|
||||
|
||||
// A help message for this specific tool can be added afterwards.
|
||||
static cl::extrahelp MoreHelp("\nMore help text...\n");
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory);
|
||||
if (!ExpectedParser) {
|
||||
llvm::errs() << toString(ExpectedParser.takeError());
|
||||
return 1;
|
||||
}
|
||||
CommonOptionsParser& OptionsParser = ExpectedParser.get();
|
||||
ClangTool Tool(OptionsParser.getCompilations(),
|
||||
OptionsParser.getSourcePathList());
|
||||
return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>().get());
|
||||
int main(int argc, const char **argv) {
|
||||
auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory);
|
||||
if (!ExpectedParser) {
|
||||
llvm::errs() << toString(ExpectedParser.takeError());
|
||||
return 1;
|
||||
}
|
||||
CommonOptionsParser& OptionsParser = ExpectedParser.get();
|
||||
ClangTool Tool(OptionsParser.getCompilations(),
|
||||
OptionsParser.getSourcePathList());
|
||||
return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>().get());
|
||||
}
|
||||
```
|
||||
|
||||
Running the tool on some code
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
### Running the tool on some code
|
||||
|
||||
When you check out and build clang, clang-check is already built and available
|
||||
to you in bin/clang-check inside your build directory.
|
||||
|
||||
You can run clang-check on a file in the llvm repository by specifying all the
|
||||
needed parameters after a "``--``" separator:
|
||||
needed parameters after a "`--`" separator:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd /path/to/source/llvm
|
||||
$ export BD=/path/to/build/llvm
|
||||
$ $BD/bin/clang-check tools/clang/tools/clang-check/ClangCheck.cpp -- \
|
||||
clang++ -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS \
|
||||
-Itools/clang/include -I$BD/include -Iinclude \
|
||||
-Itools/clang/lib/Headers -c
|
||||
```bash
|
||||
$ cd /path/to/source/llvm
|
||||
$ export BD=/path/to/build/llvm
|
||||
$ $BD/bin/clang-check tools/clang/tools/clang-check/ClangCheck.cpp -- \
|
||||
clang++ -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS \
|
||||
-Itools/clang/include -I$BD/include -Iinclude \
|
||||
-Itools/clang/lib/Headers -c
|
||||
```
|
||||
|
||||
As an alternative, you can also configure cmake to output a compile command
|
||||
database into its build directory:
|
||||
|
||||
.. code-block:: bash
|
||||
```bash
|
||||
# Alternatively to calling cmake, use ccmake, toggle to advanced mode and
|
||||
# set the parameter CMAKE_EXPORT_COMPILE_COMMANDS from the UI.
|
||||
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
|
||||
```
|
||||
|
||||
# Alternatively to calling cmake, use ccmake, toggle to advanced mode and
|
||||
# set the parameter CMAKE_EXPORT_COMPILE_COMMANDS from the UI.
|
||||
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
|
||||
|
||||
This creates a file called ``compile_commands.json`` in the build directory.
|
||||
Now you can run :program:`clang-check` over files in the project by specifying
|
||||
This creates a file called `compile_commands.json` in the build directory.
|
||||
Now you can run {program}`clang-check` over files in the project by specifying
|
||||
the build path as first argument and some source files as further positional
|
||||
arguments:
|
||||
|
||||
.. code-block:: bash
|
||||
```bash
|
||||
$ cd /path/to/source/llvm
|
||||
$ export BD=/path/to/build/llvm
|
||||
$ $BD/bin/clang-check -p $BD tools/clang/tools/clang-check/ClangCheck.cpp
|
||||
```
|
||||
|
||||
$ cd /path/to/source/llvm
|
||||
$ export BD=/path/to/build/llvm
|
||||
$ $BD/bin/clang-check -p $BD tools/clang/tools/clang-check/ClangCheck.cpp
|
||||
(libtooling_builtin_includes)=
|
||||
|
||||
|
||||
.. _libtooling_builtin_includes:
|
||||
|
||||
Builtin includes
|
||||
^^^^^^^^^^^^^^^^
|
||||
### Builtin includes
|
||||
|
||||
Clang tools need their builtin headers and search for them the same way Clang
|
||||
does. Thus, the default location to look for builtin headers is in a path
|
||||
``$(dirname /path/to/tool)/../lib/clang/3.3/include`` relative to the tool
|
||||
binary. This works out-of-the-box for tools running from llvm's toplevel
|
||||
does. Thus, the default location to look for builtin headers is in a path
|
||||
`$(dirname /path/to/tool)/../lib/clang/3.3/include` relative to the tool
|
||||
binary. This works out-of-the-box for tools running from llvm's toplevel
|
||||
binary directory after building clang-resource-headers, or if the tool is
|
||||
running from the binary directory of a clang install next to the clang binary.
|
||||
|
||||
Tips: if your tool fails to find ``stddef.h`` or similar headers, call the tool
|
||||
with ``-v`` and look at the search paths it looks through.
|
||||
Tips: if your tool fails to find `stddef.h` or similar headers, call the tool
|
||||
with `-v` and look at the search paths it looks through.
|
||||
|
||||
Linking
|
||||
^^^^^^^
|
||||
### Linking
|
||||
|
||||
For a list of libraries to link, look at one of the tools' CMake files (for
|
||||
example `clang-check/CMakeList.txt
|
||||
<https://github.com/llvm/llvm-project/blob/main/clang/tools/clang-check/CMakeLists.txt>`_).
|
||||
example [clang-check/CMakeList.txt](https://github.com/llvm/llvm-project/blob/main/clang/tools/clang-check/CMakeLists.txt)).
|
||||
|
|
|
|||
|
|
@ -1,34 +1,33 @@
|
|||
==============
|
||||
RISC-V Support
|
||||
==============
|
||||
# RISC-V Support
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
```{contents}
|
||||
:local: true
|
||||
```
|
||||
|
||||
Intrinsic Detection Macros
|
||||
===========================
|
||||
## Intrinsic Detection Macros
|
||||
|
||||
Clang provides macros to detect which RISC-V intrinsics are supported by the
|
||||
toolchain. This is only available if intrinsics are ratified, in other word,
|
||||
experimental intrinsics do not have macro defined.
|
||||
Note: This is independent from assembler support.
|
||||
|
||||
Intrinsic Detection
|
||||
---------------------------
|
||||
### Intrinsic Detection
|
||||
|
||||
Macros of the form ``__riscv_intrinsic_<extension>`` indicate that the toolchain
|
||||
Macros of the form `__riscv_intrinsic_<extension>` indicate that the toolchain
|
||||
supports intrinsics for a given extension:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#if defined(__riscv_intrinsic_zbb)
|
||||
// Toolchain supports Zbb scalar intrinsics like __riscv_orc_b_*
|
||||
// These can be used with target attributes even if -march doesn't include Zbb
|
||||
__attribute__((target("arch=+zbb")))
|
||||
unsigned long process_with_zbb(unsigned long x) {
|
||||
return __riscv_orc_b_64(x);
|
||||
}
|
||||
#endif
|
||||
```c
|
||||
#if defined(__riscv_intrinsic_zbb)
|
||||
// Toolchain supports Zbb scalar intrinsics like __riscv_orc_b_*
|
||||
// These can be used with target attributes even if -march doesn't include Zbb
|
||||
__attribute__((target("arch=+zbb")))
|
||||
unsigned long process_with_zbb(unsigned long x) {
|
||||
return __riscv_orc_b_64(x);
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
Composite extensions are also defined when all their sub-extensions are available, e.g.
|
||||
``__riscv_intrinsic_zkn`` - zbkb + zbkc + zbkx + zkne + zknd + zknh
|
||||
|
||||
: `__riscv_intrinsic_zkn` - zbkb + zbkc + zbkx + zkne + zknd + zknh
|
||||
|
||||
|
|
|
|||
|
|
@ -1,97 +1,92 @@
|
|||
=================================================
|
||||
Choosing the Right Interface for Your Application
|
||||
=================================================
|
||||
# Choosing the Right Interface for Your Application
|
||||
|
||||
Clang provides infrastructure to write tools that need syntactic and semantic
|
||||
information about a program. This document will give a short introduction of
|
||||
information about a program. This document will give a short introduction of
|
||||
the different ways to write clang tools, and their pros and cons.
|
||||
|
||||
LibClang
|
||||
--------
|
||||
## LibClang
|
||||
|
||||
`LibClang <https://clang.llvm.org/doxygen/group__CINDEX.html>`_ is a stable high
|
||||
level C interface to clang. When in doubt LibClang is probably the interface
|
||||
you want to use. Consider the other interfaces only when you have a good
|
||||
[LibClang](https://clang.llvm.org/doxygen/group__CINDEX.html) is a stable high
|
||||
level C interface to clang. When in doubt LibClang is probably the interface
|
||||
you want to use. Consider the other interfaces only when you have a good
|
||||
reason not to use LibClang.
|
||||
|
||||
Canonical examples of when to use LibClang:
|
||||
|
||||
* Xcode
|
||||
* Clang Python Bindings
|
||||
- Xcode
|
||||
- Clang Python Bindings
|
||||
|
||||
Use LibClang when you...:
|
||||
|
||||
* want to interface with clang from other languages than C++
|
||||
* need a stable interface that takes care to be backwards compatible
|
||||
* want powerful high-level abstractions, like iterating through an AST with a
|
||||
- want to interface with clang from other languages than C++
|
||||
- need a stable interface that takes care to be backwards compatible
|
||||
- want powerful high-level abstractions, like iterating through an AST with a
|
||||
cursor, and don't want to learn all the nitty gritty details of Clang's AST.
|
||||
|
||||
Do not use LibClang when you...:
|
||||
|
||||
* want full control over the Clang AST
|
||||
- want full control over the Clang AST
|
||||
|
||||
Clang Plugins
|
||||
-------------
|
||||
## Clang Plugins
|
||||
|
||||
:doc:`Clang Plugins <ClangPlugins>` allow you to run additional actions on the
|
||||
AST as part of a compilation. Plugins are dynamic libraries that are loaded at
|
||||
{doc}`Clang Plugins <ClangPlugins>` allow you to run additional actions on the
|
||||
AST as part of a compilation. Plugins are dynamic libraries that are loaded at
|
||||
runtime by the compiler, and they're easy to integrate into your build
|
||||
environment.
|
||||
|
||||
Canonical examples of when to use Clang Plugins:
|
||||
|
||||
* special lint-style warnings or errors for your project
|
||||
* creating additional build artifacts from a single compile step
|
||||
- special lint-style warnings or errors for your project
|
||||
- creating additional build artifacts from a single compile step
|
||||
|
||||
Use Clang Plugins when you...:
|
||||
|
||||
* need your tool to rerun if any of the dependencies change
|
||||
* want your tool to make or break a build
|
||||
* need full control over the Clang AST
|
||||
- need your tool to rerun if any of the dependencies change
|
||||
- want your tool to make or break a build
|
||||
- need full control over the Clang AST
|
||||
|
||||
Do not use Clang Plugins when you...:
|
||||
|
||||
* want to run tools outside of your build environment
|
||||
* want full control on how Clang is set up, including mapping of in-memory
|
||||
- want to run tools outside of your build environment
|
||||
- want full control on how Clang is set up, including mapping of in-memory
|
||||
virtual files
|
||||
* need to run over a specific subset of files in your project which is not
|
||||
- need to run over a specific subset of files in your project which is not
|
||||
necessarily related to any changes which would trigger rebuilds
|
||||
|
||||
LibTooling
|
||||
----------
|
||||
## LibTooling
|
||||
|
||||
:doc:`LibTooling <LibTooling>` is a C++ interface aimed at writing standalone
|
||||
tools, as well as integrating into services that run clang tools. Canonical
|
||||
{doc}`LibTooling <LibTooling>` is a C++ interface aimed at writing standalone
|
||||
tools, as well as integrating into services that run clang tools. Canonical
|
||||
examples of when to use LibTooling:
|
||||
|
||||
* a simple syntax checker
|
||||
* refactoring tools
|
||||
- a simple syntax checker
|
||||
- refactoring tools
|
||||
|
||||
Use LibTooling when you...:
|
||||
|
||||
* want to run tools over a single file, or a specific subset of files,
|
||||
- want to run tools over a single file, or a specific subset of files,
|
||||
independently of the build system
|
||||
* want full control over the Clang AST
|
||||
* want to share code with Clang Plugins
|
||||
- want full control over the Clang AST
|
||||
- want to share code with Clang Plugins
|
||||
|
||||
Do not use LibTooling when you...:
|
||||
|
||||
* want to run as part of the build triggered by dependency changes
|
||||
* want a stable interface so you don't need to change your code when the AST API
|
||||
- want to run as part of the build triggered by dependency changes
|
||||
- want a stable interface so you don't need to change your code when the AST API
|
||||
changes
|
||||
* want high level abstractions like cursors and code completion out of the box
|
||||
* do not want to write your tools in C++
|
||||
- want high level abstractions like cursors and code completion out of the box
|
||||
- do not want to write your tools in C++
|
||||
|
||||
:doc:`Clang tools <ClangTools>` are a collection of specific developer tools
|
||||
{doc}`Clang tools <ClangTools>` are a collection of specific developer tools
|
||||
built on top of the LibTooling infrastructure as part of the Clang project.
|
||||
They are targeted at automating and improving core development activities of
|
||||
C/C++ developers.
|
||||
|
||||
Examples of tools we are building or planning as part of the Clang project:
|
||||
|
||||
* Syntax checking (:program:`clang-check`)
|
||||
* Automatic fixing of compile errors (:program:`clang-fixit`)
|
||||
* Automatic code formatting (:program:`clang-format`)
|
||||
* Migration tools for new features in new language standards
|
||||
* Core refactoring tools
|
||||
- Syntax checking ({program}`clang-check`)
|
||||
- Automatic fixing of compile errors ({program}`clang-fixit`)
|
||||
- Automatic code formatting ({program}`clang-format`)
|
||||
- Migration tools for new features in new language standards
|
||||
- Core refactoring tools
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue