> For the complete documentation index, see [llms.txt](https://docs.hex-rays.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hex-rays.com/core/types/how-tos/creating-type-libraries/clang.md).

# Clang

## Overview

The clang parser is the most powerful and complete parser shipped with IDA Pro. It is based on the clang compiler and can handle a wide variety of C/C++/Obj-C header files, including those with complex preprocessor directives and macros. It is meant as a replacement for IDAClang.

Note that `cfg/idaclang.cfg` is used as the config file for the clang parser as well, so that the new parser automatically picks up the settings you may have already configured for IDAClang.

### LLVM

It is based on the LLVM project (21.1.5) and uses the clang compiler to parse header files and extract type information.

### Motivation

#### Legacy parser

The built-in legacy parser is a simple yet efficient parser that can handle C header files. However, it is not very good at handling C++ header files.

#### IDAClang parser

The IDAClang parser can handle C++ header files, but it is purely based on the clang compiler and does not handle IDA-specific keywords, such as `_BYTE` or `_QWORD`.

#### clang parser

The official clang parser bridges the gap between the legacy parser and IDAClang, being able to handle both C and C++ header files, while also supporting IDA-specific keywords. On top of that, it adds support for Objective-C and Objective-C++ header files. You can enable the clang parser by going to **Options → Compiler** and setting the **Source parser** to clang.

There are three ways of importing types using the clang parser:

1. Using the **Add type** option in **Local Types** window.
2. Using the **File → Load file → Parse C header file...** option in the menu bar.
3. Scripting the parsing process using IDAPython.

### Examples

### VTables

```cpp
class C
{
  virtual void func(void);
};
```

The following types will be generated in the database:

```
00000000 struct __cppobj C // sizeof=0x4
00000000 {
00000000     C_vtbl *__vftable;
00000004 };

00000000 struct C_vtbl_layout // sizeof=0xC
00000000 {
00000000     __int32 thisOffset;                 // offset_to_top (0)
00000004     void *rtti;                         // C
00000008     void (*func)(C *__hidden this);
0000000C };

00000000 struct /*VFT*/ C_vtbl // sizeof=0x4
00000000 {
00000000     void (*func)(C *__hidden this);
00000004 };
```

### IDA-specific keywords

The following code will be correctly parsed by the clang parser:

```cpp
struct foo
{
    _DWORD bar;
    __usercall void do_something();
};
```

It will be added to the database as:

```
00000000 struct foo // sizeof=0x4
00000000 {
00000000     _DWORD bar;
00000004 };
```

### C++ templates

```cpp
template <typename T, typename V> struct S
{
  T x;
  V y;
};

typedef S<int, void *> instance_t;
```

To parse this code:

1. Go to **Options → Compiler → Parser** specific options and mark "No IDA specific extensions".
2. Put it in an include file and select **File → Load file → Parse C header file...** from the menu bar.

The parsed result will be:

```
00000000 struct __cppobj S<int, void *> // sizeof=0x8
00000000 {                                       // XREF: instance_t/r
00000000     int x;
00000004     void *y;
00000008 };

00000008 typedef S<int, void *> instance_t;
```

### C++20

In order to parse C++20 code, make sure your **Include directories** and **Arguments** options are set up correctly. For example, You can use the following commands to figure out the correct include paths and arguments for your system:

```sh
xcrun --show-sdk-path  # get the SDK path (-isysroot)
xcrun clang++ -std=c++20 -v -E -x c++ /dev/null  # get the include paths and arguments for C++20
```

The *Arguments* option should include the `-std=c++20` flag:

```
-x c++ -std=c++20 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
```

Here's an example of C++20 code that can be parsed by the clang parser:

```cpp
#include <concepts>
#include <compare>
#include <cstdint>
#include <span>
#include <string_view>

template <typename T>
concept Addable = requires(T a, T b) {
  { a + b } -> std::same_as<T>;
};

struct Record {
  std::uint32_t id;
  std::string_view name;

  auto operator <=> (const Record &) const = default;
};
```

Final result:

```
00000000 struct __cppobj Record // sizeof=0x18
00000000 {
00000000     uint32_t id;
00000004     // padding byte
00000005     // padding byte
00000006     // padding byte
00000007     // padding byte
00000008     std::string_view name;
00000018 };
```

### Objective-C

```objective-c
#import <Foundation/Foundation.h>

@interface MyClass : NSObject
{
    int _counter;
    NSString *_name;
}

@property(nonatomic, strong) NSString *title;
@property(nonatomic, assign) NSInteger value;

- (instancetype)init;
- (void)reset;
- (int)add:(int)a to:(int)b;

+ (BOOL)isValid:(NSString *)string;
+ (MyClass *)sharedInstance;

@end
```

Before parsing, make sure to set the right language in **Options → Compiler → Parser specific options** (Objective-C or Objective-C++), and to have the right include paths set in **Options → Compiler → Include directories**.

To see what these are, for example on a macOS system, you can run the following command in the terminal:

```
xcrun clang -v -E -x objective-c /dev/null
```

You might also have to include the proper presets, for example:

```
-target arm64-apple-darwin -framework Foundation -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
```

In the end, the parsed result looks like this:

```
00000000 __objc_interface __cppobj MyClass : NSObject // sizeof=0x18
00000000 {
00000004     int _counter;
00000008     NSString *_name;
0000000C     NSString *_title;
00000010     NSInteger _value;
00000018 };
```

All the dependent types, such as `NSString` and `NSInteger`, will also be added to the database.

### Fixed structs

Fixed layout structures can be created or edited directly in Local Types using the C-syntax editor. Make sure that **IDA specific extensions** are not disabled in **Options → Compiler → Parser specific options**. By default they are enabled, so you should be good to go.

```cpp
struct __fixed(0x48) x64_prologue_frame
{
  __at(0x0000) void *return_addr;
  __at(0x0008) void *saved_rbp;
  __at(0x0010) void *saved_rbx;
  __at(0x0038) int local_var1;
  __at(0x003C) int local_var2;
};
```

## The parser UI

### Enabling the clang parser

Make sure to select `clang` as the **Source parser** in the **Options → Compiler** dialog:

<figure><img src="/files/izV9A1ofL9Foi2RCL0uM" alt="Compiler Options"><figcaption></figcaption></figure>

The parser can be fine-tuned using the **Parser specific options** button.

<figure><img src="/files/a0kEXKh1CntymoV8OePF" alt="Parser Specific Options"><figcaption></figcaption></figure>

#### Apply tinfo to demangled names

If enabled, the parser will look for mangled names in the database as types are being parsed, and automatically apply the type info to the address where the name was found.

For example, if this type is parsed:

```cpp
class MyService : public IOService
{
public:
  virtual IOService *probe(IOService *provider, SInt32 *score) APPLE_KEXT_OVERRIDE;
};
```

And the function `MyService::probe()` is present in the database, a more precise prototype will automatically be applied to the function:

```
; =============== S U B R O U T I N E =======================================
; IOService *__cdecl MyService::probe(MyService *__hidden this, IOService *provider, SInt32 *score)
                public __ZN7MyClass5probeEP9IOServicePi
__ZN7MyClass5probeEP9IOServicePi proc near
```

#### No IDA specific extensions

If enabled, the parser will not recognize IDA-specific keywords, such as `_BYTE` or `_QWORD`. This is useful if you want to parse code that uses these keywords for other purposes, such as Windows driver code.

#### Smart pointers

A semicolon-separated list of smart pointer template names. The parser will simplify instances of such templates to simple pointers when they are encountered in the input source.

For example, consider the `OSSharedPtr` template class from the XNU kernel source code:

```cpp
template <typename T>
class __attribute__((trivial_abi)) OSSharedPtr: public libkern::intrusive_shared_ptr<T, intrusive_osobject_retainer> {
  using libkern::intrusive_shared_ptr<T, intrusive_osobject_retainer>::intrusive_shared_ptr;
};
```

Now let's say idaclang finds an instance of this template class in the input source:

```cpp
typedef OSSharedPtr<OSString> OSStringPtr;
```

Previously, to describe this type, the parser had to create 4 different types:

```cpp
typedef OSSharedPtr<OSString> OSStringPtr;`
struct __cppobj OSSharedPtr<OSString> : libkern::intrusive_shared_ptr<OSString, intrusive_osobject_retainer> {};
struct __cppobj libkern::intrusive_shared_ptr<OSString, intrusive_osobject_retainer>
{
  libkern::intrusive_shared_ptr<OSString, intrusive_osobject_retainer>::pointer ptr_;
};
typedef OSString *libkern::intrusive_shared_ptr<OSString, intrusive_osobject_retainer>::pointer;
```

To avoid all that noise, you can add `OSSharedPtr` to the **Smart pointers** list, which will instruct the parser to reduce the template instances to simple pointers, simplifying the analysis:

```cpp
typedef OSString *OSStringPtr;
```

For example, this is the configuration we use when generating the type libraries for `xnu_7195_x64.til`: `OSPtr;OSSharedPtr;OSTaggedPtr;OSTaggedSharedPtr`

#### Language

The language to use for parsing. This can be set to C, C++, Objective-C, or Objective-C++. Make sure to set the right flags in the **Options → Compiler → Arguments** field as well, for example `-std=c++20` for C++20 code.

#### Print/Dump AST

If enabled, the parser will print the abstract syntax tree (AST) of the parsed code in the output window. This is useful for debugging purposes. Slows down the parsing process significantly.

### Adding types

Go to **Local Types** window, right-click and select **Add type**. Paste the code you want to parse in the editor and click OK.

<figure><img src="/files/cmQFvs8URoXgIVNWCLrN" alt="Add type"><figcaption></figcaption></figure>

Alternatively, you can use the **File → Load file → Parse C header file...** option in the menu bar to parse an entire header file. Using the parser in this way is generally faster and more robust than using the **Add type** option, which is meant for quick parsing of small code snippets.

## The parser API

It is possible to invoke the parser from IDAPython. You may want to take a look at the `ida_srclang` package.

Here's a simple example of how one can use the API to parse an Objective-C header file:

```python
import ida_srclang
import idaapi
 
ida_srclang.set_parser_argv(
    "clang",
    "-x objective-c -target arm64-apple-darwin -framework Foundation -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -ILibrary/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include"
)

idaapi.parse_decls(
    None,
    "/path/to/header.h",
    None,
    idaapi.HTI_FIL | idaapi.HTI_NWR | idaapi.HTI_LOWER | idaapi.HTI_NDC
)
```

## Building type libraries with tilib

TILIB is a utility to create custom type libraries for IDA Pro. You can find it in the `tools` folder within the main IDA installation directory. For an overview just run `tilib`.

### Basic examples

Important flags:

* `-TC` - enables the clang parser
* `-P` - enables C++ mode
* `-I` - is used to specify include directories
* `-CT` - is used to specify additional clang arguments, for example `-std=c++20` for C++20 code
* `-v` - you'll see `CLANG command line:` printed, which is the easiest way to debug your configuration

#### C++

```
tilib -ch/path/to/header.hpp -TC -P -CT-std=c++20 -I/path/to/includes out.til
```

#### Objective-C

```
tilib -ch/path/to/header.h -TC -CT-xobjective-c -I/path/to/SDK/usr/include out.til
```

#### Objective-C++

```
tilib -ch/path/to/header.mm -TC -CT-xobjective-c++ -I/path/to/SDK/usr/include out.til
```

### Complex type libraries

#### Qt

This example will be given using macOS and Qt 6.

To install Qt, one can use Homebrew:

```
brew install qt
```

For convenience, you can set some environment variables. These may vary based on your system and Qt installation.

```sh
export QTDIR=/opt/homebrew/opt/qt@6
export SDK=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
export CLANG_HDRS=/Library/Developer/CommandLineTools/usr/lib/clang/17/include
```

Create an umbrella header (qt.h):

```cpp
#include <QtCore>
#include <QtGui>
#include <QtWidgets>
#include <QtPrintSupport>
#include <QtNetwork>
#include <QtConcurrent>
#include <QtDBus>
#include <QtHelp>
#include <QtOpenGL>
#include <QtSql>
#include <QtTest>
#include <QtUiTools>
#include <QtXml>
```

Create the type library:

```
tilib -c -TC -P \
  -t"Qt 6 headers for arm64 macOS" \
  -CT--target=arm64-apple-darwin \
  -CT-xobjective-c++ \
  -CT-std=c++20 \
  -CT-stdlib=libc++ \
  -CT-isysroot -CT$SDK \
  -CT-idirafter -CT$CLANG_HDRS \
  -CT-F$QTDIR/lib \
  -CT-Wno-nullability-completeness \
  -I$QTDIR/lib/QtCore.framework/Headers \
  -I$QTDIR/lib/QtGui.framework/Headers \
  -I$QTDIR/lib/QtWidgets.framework/Headers \
  -I$QTDIR/lib/QtPrintSupport.framework/Headers \
  -I$QTDIR/lib/QtNetwork.framework/Headers \
  -I$QTDIR/lib/QtConcurrent.framework/Headers \
  -I$QTDIR/lib/QtDBus.framework/Headers \
  -I$QTDIR/lib/QtHelp.framework/Headers \
  -I$QTDIR/lib/QtOpenGL.framework/Headers \
  -I$QTDIR/lib/QtSql.framework/Headers \
  -I$QTDIR/lib/QtTest.framework/Headers \
  -I$QTDIR/lib/QtUiTools.framework/Headers \
  -I$QTDIR/lib/QtXml.framework/Headers \
  -hqt.h qt_mac_arm64.til
```

Note that sometimes there may be inconsistencies between IDA's clang and the system's clang, which may cause parsing errors. For example, if Apple's clang header files use some features that are not supported by the LLVM clang, you may need to add some additional flags to the command line to work around the issue. You can use `-v` to see the exact command line used for parsing and debug the problem. However, if that doesn't work and the parser gets in your way, you can also pass `-e` in order to ignore potential parsing errors and get as much of the type information as possible. Most likely there will still be a good amount of useful information extracted.

To verify what has been parsed into the type library, dump the information using `tilib -lc qt_mac_arm64.til > qt_mac_arm64.txt`.

#### XNU Kernel

If you're on a macOS system, this is pretty straightforward, since you can use the system's SDK and clang headers.

```
export SDK=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
```

Create `xnu.h` and include your headers of interest:

```cpp
#include <IOKit/IOTypes.h>
#include <IOKit/IOConditionLock.h>
#include <IOKit/IONVRAM.h>
#include <IOKit/IOEventSource.h>
#include <IOKit/IOUserClient.h>
#include <IOKit/IOMemoryCursor.h>
#include <IOKit/IONotifier.h>
#include <IOKit/IOServicePM.h>
#include <IOKit/IOKitDebug.h>
#include <IOKit/IODMACommand.h>
#include <IOKit/IOMapTypes.h>
#include <IOKit/IOBSD.h>
#include <IOKit/IOService.h>
#include <IOKit/IORegistryEntry.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IOMapper.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOReturn.h>
#include <IOKit/IOSubMemoryDescriptor.h>
#include <IOKit/IOReportTypes.h>
#include <IOKit/IOServiceStateNotificationEventSource.h>
#include <IOKit/IODataQueue.h>
#include <IOKit/IOCommandGate.h>
#include <IOKit/IODataQueueShared.h>
#include <IOKit/PassthruInterruptController.h>
#include <IOKit/IOCommand.h>
#include <IOKit/IOCatalogue.h>
#include <IOKit/IODMAController.h>
#include <IOKit/IOInterruptEventSource.h>
#include <IOKit/IOReportMacros.h>
#include <IOKit/IOInterleavedMemoryDescriptor.h>
#include <IOKit/IOKernelReportStructs.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOSharedLock.h>
#include <IOKit/IOUserServer.h>
#include <IOKit/IOTimeStamp.h>
#include <IOKit/IOSharedDataQueue.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IORPC.h>
#include <IOKit/IODeviceMemory.h>
#include <IOKit/IORangeAllocator.h>
#include <IOKit/IOLocks.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOMemoryDescriptor.h>
#include <IOKit/IOKitServer.h>
#include <IOKit/IOGuardPageMemoryDescriptor.h>
#include <IOKit/IOCommandPool.h>
#include <IOKit/IOInterrupts.h>
#include <IOKit/IOInterruptController.h>
#include <IOKit/IOTimerEventSource.h>
```

You can check your OS version and the corresponding SDK version using `sw_vers`.

```
ProductName:		macOS
ProductVersion:		26.3.1
ProductVersionExtra:	(a)
BuildVersion:		25D771280a
```

Creating the type library for Darwin Kernel headers of macOS 26.3:

```
tilib -c -TC -P \
  -t"Darwin Kernel headers for arm64 macOS" \
  -CT--target=arm64-apple-macos26.3 \
  -CT-isysroot -CT$SDK \
  -CT-nostdinc \
  -CT-std=gnu++1z \
  -CT-stdlib=libc++ \
  -CT-mkernel \
  -DKERNEL \
  -DAPPLE \
  -DNeXT \
  -I$SDK/System/Library/Frameworks/Kernel.framework/Headers \
  -hxnu.h xnu_mac_arm64.til
```

#### macOS/iOS SDK

The same process can be applied to create type libraries for macOS or iOS SDKs. Just make sure to set the right target and include paths.

```
export SDK=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
export CLANG_INC=$(ls -1d /Library/Developer/CommandLineTools/usr/lib/clang/*/include | sort -V | tail -1)
```

An umbrella header (macos\_sdk.h) can be found here:

{% file src="/files/JGTnzVDkJvy9DtaEzzuT" %}

.

Here's a recipe of how to generate the umbrella header on your system:

```sh
SDK=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
for f in $SDK/System/Library/Frameworks/*.framework; do
  mm="$f/Modules/module.modulemap"
  [ -f "$mm" ] || continue
  uh=$(awk '/umbrella header/{gsub(/"/,"",$3); print $3; exit}' "$mm")
  fw=$(basename "$f" .framework)
  case "$fw" in _*) continue;; esac
  [ -n "$uh" ] || continue
  hdr="$f/Headers/$uh"
  grep -lq "UIKit/UIKit.h" "$hdr" 2>/dev/null && continue
  echo "#include <$fw/$uh>"
done > macos_sdk.h
```

Generate the type library for macOS:

```
tilib -c -TC \
  -t"macOS SDK headers for arm64" \
  -CT--target=arm64-apple-darwin \
  -CT-x -CTobjective-c++ \
  -CT-isysroot -CT$SDK \
  -CT-isystem -CT$CLANG_INC \
  -CT-ferror-limit=0 \
  -CT-Wno-nullability-completeness \
  -D__ARM_NEON_H \
  -hmacos_sdk.h macos_sdk_arm64.til
```

For iOS, change the SDK path and the target:

```
export SDK=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk
```

Example tilib command:

```
$TILIB -c -TC \
  -t"iPhoneOS SDK headers for arm64" \
  -CT--target=arm64-apple-ios \
  -CT-x -CTobjective-c++ \
  -CT-isysroot -CT$SDK \
  -CT-isystem -CT$CLANG_INC \
  -CT-ferror-limit=0 \
  -CT-Wno-nullability-completeness \
  -D__ARM_NEON_H \
  -hios_sdk.h ios_sdk_arm64.til
```

Use `-v` (verbose) or `-e` (ignore errors) if you run into issues.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.hex-rays.com/core/types/how-tos/creating-type-libraries/clang.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
