Skip to content

Tracking Issue for btf_type_tag and btf_decl_tag #165422

Open

Description

@yonghong-song

This is a tracking issue for #![feature(btf_tags)].

The clang frontend implements two attributes, btf_decl_tag("foo") and
btf_type_tag("bar"). They are used mostly by the Linux kernel and BPF
programs. The BPF verifier reads them to check memory accesses, because plain
C types can't express some facts the verifier needs, such as "this pointer
points to user memory", "this pointer is RCU-protected", or "this argument of
a global subprogram is a context pointer".

Each attribute attaches a free-form string to a declaration or a type. Clang
carries that string into DWARF, and from there it goes into BTF, either
through the BPF backend or through pahole for the kernel. The attributes were
first added in these commits:

1b194ef1ab3b [Clang] add btf_tag attribute (later renamed to btf_decl_tag)
737e4216c537 [Attr] support btf_type_tag attribute

Later commits added more improvements and fixes.

Clang accepts both attributes on every target, not only BPF. This lets the
kernel and other code that shares headers with BPF programs use them on any
architecture, even though BPF is the main user.

Rust can also target BPF, so it will need equivalent support for
btf_decl_tag and btf_type_tag. Without it, Rust BPF programs can't give
the verifier the same information C programs can.

Public API

The following is an example.

#![feature(btf_tags)]

#[btf_decl_tag("s_tag")]
pub struct S {
    #[btf_decl_tag("f_tag")]
    pub a: u32,
    #[btf_type_tag("user")]
    #[btf_type_tag("rcu")]
    pub p: *const u64,
    pub plain: *const u64,
}

For a BPF target, this gives the following BTF (bpftool btf dump file,
unrelated entries removed):

[11] STRUCT 'S' size=24 vlen=3
        'p' type_id=15 bits_offset=0
        'plain' type_id=17 bits_offset=64
        'a' type_id=3 bits_offset=128
[12] DECL_TAG 's_tag' type_id=11 component_idx=-1
[13] TYPE_TAG 'user' type_id=16
[14] TYPE_TAG 'rcu' type_id=13
[15] PTR '(anon)' type_id=14
[16] INT 'u64' size=8 bits_offset=0 nr_bits=64 encoding=(none)
[17] PTR '(anon)' type_id=16
[18] DECL_TAG 'f_tag' type_id=11 component_idx=2

The tags have the same structure as the equivalent C code compiled by Clang.
component_idx is the member's index in the emitted layout. Without
#[repr(C)], rustc may reorder fields (here a moved last), so structs shared
with the kernel or with C should use #[repr(C)].

Both attributes take a single string literal and can be repeated. As in
Clang, stacked type tags are kept in source order, and exact duplicate decl
tags are emitted once. Both attributes are accepted on every target and
produce DW_TAG_LLVM_annotation in DWARF; the BPF backend turns them into BTF.

Like Clang, the attributes can be used on several kinds of declarations.

btf_decl_tag tags a declaration:

Rust BTF Clang equivalent
static DECL_TAG on the VAR, component_idx=-1 global variable
fn, inherent method, trait-impl method, trait method with a body DECL_TAG on the FUNC, component_idx=-1 function definition
function parameter DECL_TAG on the FUNC, component_idx=<argument index> parameter
struct, union DECL_TAG on the STRUCT/UNION, component_idx=-1 struct, union
struct or union field DECL_TAG on the STRUCT/UNION, component_idx=<member index> field
foreign static accepted, no effect Clang also drops decl tags on extern variables

Enums and enum variant fields are rejected; Clang doesn't allow enums either.

btf_type_tag tags the pointee of the declared pointer type:

Rust BTF Clang equivalent
static VAR -> PTR -> TYPE_TAG -> T global variable
struct or union field member type PTR -> TYPE_TAG -> T field
function parameter FUNC_PROTO parameter PTR -> TYPE_TAG -> T parameter
fn or method with a body FUNC_PROTO return type PTR -> TYPE_TAG -> T T __tag *f(...)
foreign static accepted, no effect yet extern variable

On a function, btf_type_tag applies to the returned pointer. This mirrors
the other declarations: btf_decl_tag tags the declaration itself, and
btf_type_tag tags the pointer type that the declaration introduces.

#![feature(btf_tags)]

#[btf_decl_tag("func_tag")]
#[btf_type_tag("arena")]
#[no_mangle]
pub fn f(
    #[btf_decl_tag("arg_tag")]
    #[btf_type_tag("user")]
    p: *mut u32,
) -> *mut u32 {
    p
}
[1] TYPE_TAG 'user' type_id=3
[2] PTR '(anon)' type_id=1
[3] INT 'u32' size=4 bits_offset=0 nr_bits=32 encoding=(none)
[4] FUNC_PROTO '(anon)' ret_type_id=6 vlen=1
        'p' type_id=2
[5] TYPE_TAG 'arena' type_id=3
[6] PTR '(anon)' type_id=5
[7] FUNC 'f' type_id=4 linkage=global
[8] DECL_TAG 'arg_tag' type_id=7 component_idx=0
[9] DECL_TAG 'func_tag' type_id=7 component_idx=-1

A type tag only takes effect on the outermost thin pointer (*const T,
*mut T, &T, &mut T). On any other type, including NonNull<T>,
Option<&T>, Box<T> and wide pointers, it is silently ignored, as Clang
ignores type tags that aren't on a pointer's pointee.

Steps

Unresolved Questions

None so far.

Implementation history

None so far.

Activity

  1. added
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    on Nov 3, 2026
  2. yonghong-song commented on Nov 3, 2026

    @yonghong-song
    Author

    @rustbot label +T-compiler +A-debuginfo +S-tracking-unimplemented

  3. added
    A-debuginfoArea: Debugging information in compiled programs (DWARF, PDB, etc.)
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-debuginfoArea: Debugging information in compiled programs (DWARF, PDB, etc.)C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCS-tracking-unimplementedStatus: The feature has not been implemented.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions