1 //! Wrappers representing concrete btf types. 2 3 use std::ffi::OsStr; 4 use std::fmt; 5 use std::fmt::Display; 6 use std::ops::Deref; 7 8 use super::BtfKind; 9 use super::BtfType; 10 use super::HasSize; 11 use super::ReferencesType; 12 use super::TypeId; 13 14 // Generate a btf type that doesn't have any fields, i.e. there is no data after the BtfType 15 // pointer. 16 macro_rules! gen_fieldless_concrete_type { 17 ( 18 $(#[$docs:meta])* 19 $name:ident $(with $trait:ident)? 20 ) => { 21 $(#[$docs])* 22 #[derive(Clone, Copy, Debug)] 23 pub struct $name<'btf> { 24 source: BtfType<'btf>, 25 } 26 27 impl<'btf> TryFrom<BtfType<'btf>> for $name<'btf> { 28 type Error = BtfType<'btf>; 29 30 fn try_from(t: BtfType<'btf>) -> ::core::result::Result<Self, Self::Error> { 31 if t.kind() == BtfKind::$name { 32 Ok($name { source: t }) 33 } else { 34 Err(t) 35 } 36 } 37 } 38 39 impl<'btf> ::std::ops::Deref for $name<'btf> { 40 type Target = BtfType<'btf>; 41 fn deref(&self) -> &Self::Target { 42 &self.source 43 } 44 } 45 46 $( 47 impl super::sealed::Sealed for $name<'_> {} 48 unsafe impl<'btf> $trait<'btf> for $name<'btf> {} 49 )* 50 }; 51 } 52 53 // Generate a btf type that has at least one field, and as such, there is data following the 54 // btf_type pointer. 55 macro_rules! gen_concrete_type { 56 ( 57 $(#[$docs:meta])* 58 $libbpf_ty:ident as $name:ident $(with $trait:ident)? 59 ) => { 60 $(#[$docs])* 61 #[derive(Clone, Copy, Debug)] 62 pub struct $name<'btf> { 63 source: BtfType<'btf>, 64 ptr: &'btf libbpf_sys::$libbpf_ty, 65 } 66 67 impl<'btf> TryFrom<BtfType<'btf>> for $name<'btf> { 68 type Error = BtfType<'btf>; 69 70 fn try_from(t: BtfType<'btf>) -> ::core::result::Result<Self, Self::Error> { 71 if t.kind() == BtfKind::$name { 72 let ptr = unsafe { 73 // SAFETY: 74 // 75 // It's in bounds to access the memory following this btf_type 76 // because we've checked the type 77 (t.ty as *const libbpf_sys::btf_type).offset(1) 78 }; 79 let ptr = ptr.cast::<libbpf_sys::$libbpf_ty>(); 80 Ok($name { 81 source: t, 82 // SAFETY: 83 // 84 // This pointer is aligned. 85 // all fields of all struct have size and 86 // alignment of u32, if t.ty was aligned, then this must be as well 87 // 88 // It's initialized 89 // libbpf guarantees this since we've checked the type 90 // 91 // The lifetime will match the lifetime of the original t.ty reference. 92 ptr: unsafe { &*ptr }, 93 }) 94 } else { 95 Err(t) 96 } 97 } 98 } 99 100 impl<'btf> ::std::ops::Deref for $name<'btf> { 101 type Target = BtfType<'btf>; 102 fn deref(&self) -> &Self::Target { 103 &self.source 104 } 105 } 106 107 $( 108 impl super::sealed::Sealed for $name<'_> {} 109 unsafe impl<'btf> $trait<'btf> for $name<'btf> {} 110 )* 111 }; 112 } 113 114 macro_rules! gen_collection_members_concrete_type { 115 ( 116 $libbpf_ty:ident as $name:ident $(with $trait:ident)?; 117 118 $(#[$docs:meta])* 119 struct $member_name:ident $(<$lt:lifetime>)? { 120 $( 121 $(#[$field_docs:meta])* 122 pub $field:ident : $type:ty 123 ),* $(,)? 124 } 125 126 |$btf:ident, $member:ident $(, $kind_flag:ident)?| $convert:expr 127 ) => { 128 impl<'btf> ::std::ops::Deref for $name<'btf> { 129 type Target = BtfType<'btf>; 130 fn deref(&self) -> &Self::Target { 131 &self.source 132 } 133 } 134 135 impl<'btf> $name<'btf> { 136 /// Whether this type has no members 137 #[inline] 138 pub fn is_empty(&self) -> bool { 139 self.members.is_empty() 140 } 141 142 #[doc = ::core::concat!("How many members this [`", ::core::stringify!($name), "`] has")] 143 #[inline] 144 pub fn len(&self) -> usize { 145 self.members.len() 146 } 147 148 #[doc = ::core::concat!("Get a [`", ::core::stringify!($member_name), "`] at a given index")] 149 /// # Errors 150 /// 151 /// This function returns [`None`] when the index is out of bounds. 152 pub fn get(&self, index: usize) -> Option<$member_name$(<$lt>)*> { 153 self.members.get(index).map(|m| self.c_to_rust_member(m)) 154 } 155 156 #[doc = ::core::concat!("Returns an iterator over the [`", ::core::stringify!($member_name), "`]'s of the [`", ::core::stringify!($name), "`]")] 157 pub fn iter(&'btf self) -> impl ExactSizeIterator<Item = $member_name$(<$lt>)*> + 'btf { 158 self.members.iter().map(|m| self.c_to_rust_member(m)) 159 } 160 161 fn c_to_rust_member(&self, member: &libbpf_sys::$libbpf_ty) -> $member_name$(<$lt>)* { 162 let $btf = self.source.source; 163 let $member = member; 164 $(let $kind_flag = self.source.kind_flag();)* 165 $convert 166 } 167 } 168 169 $(#[$docs])* 170 #[derive(Clone, Copy, Debug)] 171 pub struct $member_name $(<$lt>)? { 172 $( 173 $(#[$field_docs])* 174 pub $field: $type 175 ),* 176 } 177 178 $( 179 impl $crate::btf::sealed::Sealed for $name<'_> {} 180 unsafe impl<'btf> $trait<'btf> for $name<'btf> {} 181 )* 182 }; 183 } 184 185 macro_rules! gen_collection_concrete_type { 186 ( 187 $(#[$docs:meta])* 188 $libbpf_ty:ident as $name:ident $(with $trait:ident)?; 189 190 $($rest:tt)+ 191 ) => { 192 $(#[$docs])* 193 #[derive(Clone, Copy, Debug)] 194 pub struct $name<'btf> { 195 source: BtfType<'btf>, 196 members: &'btf [libbpf_sys::$libbpf_ty], 197 } 198 199 impl<'btf> TryFrom<BtfType<'btf>> for $name<'btf> { 200 type Error = BtfType<'btf>; 201 202 fn try_from(t: BtfType<'btf>) -> ::core::result::Result<Self, Self::Error> { 203 if t.kind() == BtfKind::$name { 204 let base_ptr = unsafe { 205 // SAFETY: 206 // 207 // It's in bounds to access the memory following this btf_type 208 // because we've checked the type 209 (t.ty as *const libbpf_sys::btf_type).offset(1) 210 }; 211 let members = unsafe { 212 // SAFETY: 213 // 214 // This pointer is aligned. 215 // all fields of all struct have size and 216 // alignment of u32, if t.ty was aligned, then this must be as well 217 // 218 // It's initialized 219 // libbpf guarantees this since we've checked the type 220 // 221 // The lifetime will match the lifetime of the original t.ty reference. 222 // 223 // The docs specify the length of the array is stored in vlen. 224 std::slice::from_raw_parts(base_ptr.cast(), t.vlen() as usize) 225 }; 226 Ok(Self { source: t, members }) 227 } else { 228 Err(t) 229 } 230 } 231 } 232 233 gen_collection_members_concrete_type!{ 234 $libbpf_ty as $name $(with $trait)?; 235 $($rest)* 236 } 237 }; 238 } 239 240 /// The attributes of a member. 241 #[derive(Clone, Copy, Debug)] 242 pub enum MemberAttr { 243 /// Member is a normal field. 244 Normal { 245 /// The offset of this member in the struct/union. 246 offset: u32, 247 }, 248 /// Member is a bitfield. 249 BitField { 250 /// The size of the bitfield. 251 size: u8, 252 /// The offset of the bitfield. 253 offset: u32, 254 }, 255 } 256 257 impl MemberAttr { 258 #[inline] new(kflag: bool, offset: u32) -> Self259 fn new(kflag: bool, offset: u32) -> Self { 260 if kflag { 261 let size = (offset >> 24) as u8; 262 if size != 0 { 263 Self::BitField { 264 size, 265 offset: offset & 0x00_ff_ff_ff, 266 } 267 } else { 268 Self::Normal { offset } 269 } 270 } else { 271 Self::Normal { offset } 272 } 273 } 274 } 275 276 /// The kind of linkage a variable of function can have. 277 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 278 #[repr(u32)] 279 pub enum Linkage { 280 /// Static linkage 281 Static = 0, 282 /// Global linkage 283 Global, 284 /// External linkage 285 Extern, 286 /// Unknown 287 Unknown, 288 } 289 290 impl From<u32> for Linkage { from(value: u32) -> Self291 fn from(value: u32) -> Self { 292 use Linkage::*; 293 294 match value { 295 x if x == Static as u32 => Static, 296 x if x == Global as u32 => Global, 297 x if x == Extern as u32 => Extern, 298 _ => Unknown, 299 } 300 } 301 } 302 303 impl From<Linkage> for u32 { from(value: Linkage) -> Self304 fn from(value: Linkage) -> Self { 305 value as u32 306 } 307 } 308 309 impl Display for Linkage { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result310 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 311 write!( 312 f, 313 "{}", 314 match self { 315 Linkage::Static => "static", 316 Linkage::Global => "global", 317 Linkage::Extern => "extern", 318 Linkage::Unknown => "(unknown)", 319 } 320 ) 321 } 322 } 323 324 // Void 325 gen_fieldless_concrete_type! { 326 /// The representation of the c_void type. 327 Void 328 } 329 330 // Int 331 332 /// An integer. 333 /// 334 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-int) 335 #[derive(Clone, Copy, Debug)] 336 pub struct Int<'btf> { 337 source: BtfType<'btf>, 338 /// The encoding of the number. 339 pub encoding: IntEncoding, 340 /// The offset in bits where the value of this integer starts. Mostly usefull for bitfields in 341 /// structs. 342 pub offset: u8, 343 /// The number of bits in the int. (For example, an u8 has 8 bits). 344 pub bits: u8, 345 } 346 347 /// The kinds of ways a btf [Int] can be encoded. 348 #[derive(Clone, Copy, Debug)] 349 pub enum IntEncoding { 350 /// No encoding. 351 None, 352 /// Signed. 353 Signed, 354 /// It's a c_char. 355 Char, 356 /// It's a bool. 357 Bool, 358 } 359 360 impl<'btf> TryFrom<BtfType<'btf>> for Int<'btf> { 361 type Error = BtfType<'btf>; 362 try_from(t: BtfType<'btf>) -> Result<Self, Self::Error>363 fn try_from(t: BtfType<'btf>) -> Result<Self, Self::Error> { 364 if t.kind() == BtfKind::Int { 365 let int = { 366 let base_ptr = t.ty as *const libbpf_sys::btf_type; 367 let u32_ptr = unsafe { 368 // SAFETY: 369 // 370 // It's in bounds to access the memory following this btf_type 371 // because we've checked the type 372 base_ptr.offset(1).cast::<u32>() 373 }; 374 unsafe { 375 // SAFETY: 376 // 377 // This pointer is aligned. 378 // all fields of all struct have size and 379 // alignment of u32, if t.ty was aligned, then this must be as well 380 // 381 // It's initialized 382 // libbpf guarantees this since we've checked the type 383 // 384 // The lifetime will match the lifetime of the original t.ty reference. 385 *u32_ptr 386 } 387 }; 388 let encoding = match (int & 0x0f_00_00_00) >> 24 { 389 0b1 => IntEncoding::Signed, 390 0b10 => IntEncoding::Char, 391 0b100 => IntEncoding::Bool, 392 _ => IntEncoding::None, 393 }; 394 Ok(Self { 395 source: t, 396 encoding, 397 offset: ((int & 0x00_ff_00_00) >> 24) as u8, 398 bits: (int & 0x00_00_00_ff) as u8, 399 }) 400 } else { 401 Err(t) 402 } 403 } 404 } 405 406 impl<'btf> Deref for Int<'btf> { 407 type Target = BtfType<'btf>; deref(&self) -> &Self::Target408 fn deref(&self) -> &Self::Target { 409 &self.source 410 } 411 } 412 413 // SAFETY: Int has the .size field set. 414 impl super::sealed::Sealed for Int<'_> {} 415 unsafe impl<'btf> HasSize<'btf> for Int<'btf> {} 416 417 // Ptr 418 gen_fieldless_concrete_type! { 419 /// A pointer. 420 /// 421 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-ptr) 422 Ptr with ReferencesType 423 } 424 425 // Array 426 gen_concrete_type! { 427 /// An array. 428 /// 429 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-array) 430 btf_array as Array 431 } 432 433 impl<'s> Array<'s> { 434 /// The type id of the stored type. 435 #[inline] ty(&self) -> TypeId436 pub fn ty(&self) -> TypeId { 437 self.ptr.type_.into() 438 } 439 440 /// The type of index used. 441 #[inline] index_ty(&self) -> TypeId442 pub fn index_ty(&self) -> TypeId { 443 self.ptr.index_type.into() 444 } 445 446 /// The capacity of the array. 447 #[inline] capacity(&self) -> usize448 pub fn capacity(&self) -> usize { 449 self.ptr.nelems as usize 450 } 451 452 /// The type contained in this array. 453 #[inline] contained_type(&self) -> BtfType<'s>454 pub fn contained_type(&self) -> BtfType<'s> { 455 self.source 456 .source 457 .type_by_id(self.ty()) 458 .expect("arrays should always reference an existing type") 459 } 460 } 461 462 // Struct 463 gen_collection_concrete_type! { 464 /// A struct. 465 /// 466 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-struct) 467 btf_member as Struct with HasSize; 468 469 /// A member of a [Struct] 470 struct StructMember<'btf> { 471 /// The member's name 472 pub name: Option<&'btf OsStr>, 473 /// The member's type 474 pub ty: TypeId, 475 /// The attributes of this member. 476 pub attr: MemberAttr, 477 } 478 479 |btf, member, kflag| StructMember { 480 name: btf.name_at(member.name_off), 481 ty: member.type_.into(), 482 attr: MemberAttr::new(kflag, member.offset), 483 } 484 } 485 486 // Union 487 gen_collection_concrete_type! { 488 /// A Union. 489 /// 490 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-union) 491 btf_member as Union with HasSize; 492 493 /// A member of an [Union] 494 struct UnionMember<'btf> { 495 /// The member's name 496 pub name: Option<&'btf OsStr>, 497 /// The member's type 498 pub ty: TypeId, 499 /// The attributes of this member. 500 pub attr: MemberAttr, 501 } 502 503 |btf, member, kflag| UnionMember { 504 name: btf.name_at(member.name_off), 505 ty: member.type_.into(), 506 attr: MemberAttr::new(kflag, member.offset), 507 } 508 } 509 510 /// A Composite type, which can be one of a [`Struct`] or a [`Union`]. 511 /// 512 /// Sometimes it's not useful to distinguish them, in that case, one can use this 513 /// type to inspect any of them. 514 #[derive(Clone, Copy, Debug)] 515 pub struct Composite<'btf> { 516 source: BtfType<'btf>, 517 /// Whether this type is a struct. 518 pub is_struct: bool, 519 members: &'btf [libbpf_sys::btf_member], 520 } 521 522 impl<'btf> From<Struct<'btf>> for Composite<'btf> { from(s: Struct<'btf>) -> Self523 fn from(s: Struct<'btf>) -> Self { 524 Self { 525 source: s.source, 526 is_struct: true, 527 members: s.members, 528 } 529 } 530 } 531 532 impl<'btf> From<Union<'btf>> for Composite<'btf> { from(s: Union<'btf>) -> Self533 fn from(s: Union<'btf>) -> Self { 534 Self { 535 source: s.source, 536 is_struct: false, 537 members: s.members, 538 } 539 } 540 } 541 542 impl<'btf> TryFrom<BtfType<'btf>> for Composite<'btf> { 543 type Error = BtfType<'btf>; 544 try_from(t: BtfType<'btf>) -> Result<Self, Self::Error>545 fn try_from(t: BtfType<'btf>) -> Result<Self, Self::Error> { 546 Struct::try_from(t) 547 .map(Self::from) 548 .or_else(|_| Union::try_from(t).map(Self::from)) 549 } 550 } 551 552 impl<'btf> TryFrom<Composite<'btf>> for Struct<'btf> { 553 type Error = Composite<'btf>; 554 try_from(value: Composite<'btf>) -> Result<Self, Self::Error>555 fn try_from(value: Composite<'btf>) -> Result<Self, Self::Error> { 556 if value.is_struct { 557 Ok(Self { 558 source: value.source, 559 members: value.members, 560 }) 561 } else { 562 Err(value) 563 } 564 } 565 } 566 567 impl<'btf> TryFrom<Composite<'btf>> for Union<'btf> { 568 type Error = Composite<'btf>; 569 try_from(value: Composite<'btf>) -> Result<Self, Self::Error>570 fn try_from(value: Composite<'btf>) -> Result<Self, Self::Error> { 571 if !value.is_struct { 572 Ok(Self { 573 source: value.source, 574 members: value.members, 575 }) 576 } else { 577 Err(value) 578 } 579 } 580 } 581 582 // Composite 583 gen_collection_members_concrete_type! { 584 btf_member as Composite with HasSize; 585 586 /// A member of a [Struct] 587 struct CompositeMember<'btf> { 588 /// The member's name 589 pub name: Option<&'btf OsStr>, 590 /// The member's type 591 pub ty: TypeId, 592 /// If this member is a bifield, these are it's attributes. 593 pub attr: MemberAttr 594 } 595 596 |btf, member, kflag| CompositeMember { 597 name: btf.name_at(member.name_off), 598 ty: member.type_.into(), 599 attr: MemberAttr::new(kflag, member.offset), 600 } 601 } 602 603 // Enum 604 gen_collection_concrete_type! { 605 /// An Enum of at most 32 bits. 606 /// 607 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-enum) 608 btf_enum as Enum with HasSize; 609 610 /// A member of an [Enum] 611 struct EnumMember<'btf> { 612 /// The name of this enum variant. 613 pub name: Option<&'btf OsStr>, 614 /// The numeric value of this enum variant. 615 pub value: i32, 616 } 617 618 |btf, member| EnumMember { 619 name: btf.name_at(member.name_off), 620 value: member.val, 621 } 622 } 623 624 // Fwd 625 gen_fieldless_concrete_type! { 626 /// A forward declared C type. 627 /// 628 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-fwd) 629 Fwd 630 } 631 632 impl Fwd<'_> { 633 /// The kind of C type that is forwardly declared. kind(&self) -> FwdKind634 pub fn kind(&self) -> FwdKind { 635 if self.source.kind_flag() { 636 FwdKind::Union 637 } else { 638 FwdKind::Struct 639 } 640 } 641 } 642 643 /// The kinds of types that can be forward declared. 644 #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] 645 pub enum FwdKind { 646 /// A struct. 647 Struct, 648 /// A union. 649 Union, 650 } 651 652 // Typedef 653 gen_fieldless_concrete_type! { 654 /// A C typedef. 655 /// 656 /// References the original type. 657 /// 658 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-typedef) 659 Typedef with ReferencesType 660 } 661 662 // Volatile 663 gen_fieldless_concrete_type! { 664 /// The volatile modifier. 665 /// 666 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-volatile) 667 Volatile with ReferencesType 668 } 669 670 // Const 671 gen_fieldless_concrete_type! { 672 /// The const modifier. 673 /// 674 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-const) 675 Const with ReferencesType 676 } 677 678 // Restrict 679 gen_fieldless_concrete_type! { 680 /// The restrict modifier. 681 /// 682 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-restrict) 683 Restrict with ReferencesType 684 } 685 686 // Func 687 gen_fieldless_concrete_type! { 688 /// A function. 689 /// 690 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-func) 691 Func with ReferencesType 692 } 693 694 impl Func<'_> { 695 /// This function's linkage. 696 #[inline] linkage(&self) -> Linkage697 pub fn linkage(&self) -> Linkage { 698 self.source.vlen().into() 699 } 700 } 701 702 // FuncProto 703 gen_collection_concrete_type! { 704 /// A function prototype. 705 /// 706 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-func-proto) 707 btf_param as FuncProto with ReferencesType; 708 709 /// A parameter of a [FuncProto]. 710 struct FuncProtoParam<'btf> { 711 /// The parameter's name 712 pub name: Option<&'btf OsStr>, 713 /// The parameter's type 714 pub ty: TypeId, 715 } 716 717 |btf, member| FuncProtoParam { 718 name: btf.name_at(member.name_off), 719 ty: member.type_.into() 720 } 721 } 722 723 // Var 724 gen_concrete_type! { 725 /// A global variable. 726 /// 727 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-var) 728 btf_var as Var with ReferencesType 729 } 730 731 impl Var<'_> { 732 /// The kind of linkage this variable has. 733 #[inline] linkage(&self) -> Linkage734 pub fn linkage(&self) -> Linkage { 735 self.ptr.linkage.into() 736 } 737 } 738 739 // DataSec 740 gen_collection_concrete_type! { 741 /// An ELF's data section, such as `.data`, `.bss` or `.rodata`. 742 /// 743 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-datasec) 744 btf_var_secinfo as DataSec with HasSize; 745 746 /// Describes the btf var in a section. 747 /// 748 /// See [`DataSec`]. 749 struct VarSecInfo { 750 /// The type id of the var 751 pub ty: TypeId, 752 /// The offset in the section 753 pub offset: u32, 754 /// The size of the type. 755 pub size: usize, 756 } 757 758 |_btf, member| VarSecInfo { 759 ty: member.type_.into(), 760 offset: member.offset, 761 size: member.size as usize 762 } 763 } 764 765 // Float 766 gen_fieldless_concrete_type! { 767 /// A floating point number. 768 /// 769 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-float) 770 Float with HasSize 771 } 772 773 // DeclTag 774 gen_concrete_type! { 775 /// A declaration tag. 776 /// 777 /// A custom tag the programmer can attach to a symbol. 778 /// 779 /// See the [clang docs](https://clang.llvm.org/docs/AttributeReference.html#btf-decl-tag) on 780 /// it. 781 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-decl-tag) 782 btf_decl_tag as DeclTag with ReferencesType 783 } 784 785 impl DeclTag<'_> { 786 /// The component index is present only when the tag points to a struct/union member or a 787 /// function argument. 788 /// And component_idx indicates which member or argument, this decl tag refers to. 789 #[inline] component_index(&self) -> Option<u32>790 pub fn component_index(&self) -> Option<u32> { 791 self.ptr.component_idx.try_into().ok() 792 } 793 } 794 795 // TypeTag 796 gen_fieldless_concrete_type! { 797 /// A type tag. 798 /// 799 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-type-tag) 800 TypeTag with ReferencesType 801 } 802 803 // Enum64 804 gen_collection_concrete_type! { 805 /// An Enum of 64 bits. 806 /// 807 /// See also [libbpf docs](https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-enum64) 808 btf_enum64 as Enum64 with HasSize; 809 810 /// A member of an [Enum64]. 811 struct Enum64Member<'btf> { 812 /// The name of this enum variant. 813 pub name: Option<&'btf OsStr>, 814 /// The numeric value of this enum variant. 815 pub value: u64, 816 } 817 818 |btf, member| Enum64Member { 819 name: btf.name_at(member.name_off), 820 value: { 821 let hi: u64 = member.val_hi32.into(); 822 let lo: u64 = member.val_lo32.into(); 823 hi << 32 | lo 824 }, 825 } 826 } 827 828 /// A macro that allows matching on the type of a [`BtfType`] as if it was an enum. 829 /// 830 /// Each pattern can be of two types. 831 /// 832 /// ```no_run 833 /// use libbpf_rs::btf::BtfType; 834 /// use libbpf_rs::btf_type_match; 835 /// 836 /// # fn do_something_with_an_int(i: libbpf_rs::btf::types::Int) -> &'static str { "" } 837 /// let ty: BtfType; 838 /// # ty = todo!(); 839 /// btf_type_match!(match ty { 840 /// BtfKind::Int(i) => do_something_with_an_int(i), 841 /// BtfKind::Struct => "it's a struct", 842 /// BtfKind::Union => { 843 /// "it's a union" 844 /// }, 845 /// _ => "default", 846 /// }); 847 /// ``` 848 /// 849 /// Variable Binding. 850 /// 851 /// ```compile_fail 852 /// BtfKind::Int(i) => { 853 /// // we can use i here and it will be an `Int` 854 /// } 855 /// ``` 856 /// 857 /// NonBinding. 858 /// 859 /// ```compile_fail 860 /// BtfKind::Int => { 861 /// // we don't have access to the variable, but we know the scrutinee is an Int 862 /// } 863 /// ``` 864 /// 865 /// Multiple Variants 866 /// ```compile_fail 867 /// BtfKind::Struct | BtfKind::Union => { 868 /// // we don't have access to the variable, 869 /// // but we know the scrutinee is either a Struct or a Union 870 /// } 871 /// ``` 872 /// 873 /// Special case for [`Struct`] and [`Union`]: [`Composite`] 874 /// ```compile_fail 875 /// BtfKind::Composite(c) => { 876 /// // we can use `c` as an instance of `Composite`. 877 /// // this branch will match if the type is either a Struct or a Union. 878 /// } 879 /// ``` 880 // $(BtfKind::$name:ident $(($var:ident))? => $action:expr $(,)?)+ 881 #[macro_export] 882 macro_rules! btf_type_match { 883 // base rule 884 ( 885 match $ty:ident { 886 $($pattern:tt)+ 887 } 888 ) => {{ 889 let ty: $crate::btf::BtfType<'_> = $ty; 890 $crate::__btf_type_match!(match ty.kind() { } $($pattern)*) 891 }}; 892 } 893 894 #[doc(hidden)] 895 #[macro_export] 896 macro_rules! __btf_type_match { 897 /* 898 * Composite special case 899 * 900 * This is similar to simple-match but it's hardcoded for composite which matches both structs 901 * and unions. 902 */ 903 ( 904 match $ty:ident.kind() { $($p:pat => $a:expr),* } 905 BtfKind::Composite $( ($var:ident) )? => $action:expr, 906 $($rest:tt)* 907 ) => { 908 $crate::__btf_type_match!(match $ty.kind() { $($p => $a,)* } 909 BtfKind::Composite $( ($var) )* => { $action } 910 $($rest)* 911 ) 912 }; 913 ( 914 match $ty:ident.kind() { $($p:pat => $a:expr),* } 915 BtfKind::Composite $(($var:ident))? => $action:block 916 $($rest:tt)* 917 ) => { 918 $crate::__btf_type_match!(match $ty.kind() { 919 $($p => $a,)* 920 $crate::btf::BtfKind::Struct | $crate::btf::BtfKind::Union => { 921 $(let $var = $crate::btf::types::Composite::try_from($ty).unwrap();)* 922 $action 923 } 924 } 925 $($rest)* 926 ) 927 }; 928 // simple-match: match on simple patterns that use an expression followed by a comma 929 ( 930 match $ty:ident.kind() { $($p:pat => $a:expr),* } 931 BtfKind::$name:ident $(($var:ident))? => $action:expr, 932 $($rest:tt)* 933 ) => { 934 $crate::__btf_type_match!( 935 match $ty.kind() { $($p => $a),* } 936 BtfKind::$name $(($var))? => { $action } 937 $($rest)* 938 ) 939 }; 940 // simple-match: match on simple patterns that use a block without a comma 941 ( 942 match $ty:ident.kind() { $($p:pat => $a:expr),* } 943 BtfKind::$name:ident $(($var:ident))? => $action:block 944 $($rest:tt)* 945 ) => { 946 $crate::__btf_type_match!(match $ty.kind() { 947 $($p => $a,)* 948 $crate::btf::BtfKind::$name => { 949 $(let $var = $crate::btf::types::$name::try_from($ty).unwrap();)* 950 $action 951 } 952 } 953 $($rest)* 954 ) 955 }; 956 // or-pattern: match on one or more variants without capturing a variable and using an 957 // expression followed by a comma. 958 ( 959 match $ty:ident.kind() { $($p:pat => $a:expr),* } 960 $(BtfKind::$name:ident)|+ => $action:expr, 961 $($rest:tt)* 962 ) => { 963 $crate::__btf_type_match!( 964 match $ty.kind() { $($p => $a),* } 965 $(BtfKind::$name)|* => { $action } 966 $($rest)* 967 ) 968 }; 969 ( 970 match $ty:ident.kind() { $($p:pat => $a:expr),* } 971 $(BtfKind::$name:ident)|+ => $action:block 972 $($rest:tt)* 973 ) => { 974 $crate::__btf_type_match!(match $ty.kind() { 975 $($p => $a,)* 976 $($crate::btf::BtfKind::$name)|* => { 977 $action 978 } 979 } 980 $($rest)* 981 ) 982 }; 983 // default match case 984 // 985 // we only need the expression case here because this case is not followed by a $rest:tt like 986 // the others, which let's us use the $(,)? pattern. 987 ( 988 match $ty:ident.kind() { $($p:pat => $a:expr),* } 989 _ => $action:expr $(,)? 990 ) => { 991 $crate::__btf_type_match!(match $ty.kind() { 992 $($p => $a,)* 993 _ => { $action } 994 } 995 996 ) 997 }; 998 // stop case, where the code is actually generated 999 (match $ty:ident.kind() { $($p:pat => $a:expr),* } ) => { 1000 match $ty.kind() { 1001 $($p => $a),* 1002 } 1003 } 1004 } 1005 1006 #[cfg(test)] 1007 mod test { 1008 use super::*; 1009 1010 // creates a dummy btftype, not it's not safe to use this type, but it is safe to match on it, 1011 // which is all we need for these tests. 1012 macro_rules! dummy_type { 1013 ($ty:ident) => { 1014 let btf = $crate::Btf { 1015 ptr: std::ptr::NonNull::dangling(), 1016 drop_policy: $crate::btf::DropPolicy::Nothing, 1017 _marker: std::marker::PhantomData, 1018 }; 1019 let $ty = BtfType { 1020 type_id: $crate::btf::TypeId::from(1), 1021 name: None, 1022 source: &btf, 1023 ty: &libbpf_sys::btf_type::default(), 1024 }; 1025 }; 1026 } 1027 foo(_: super::Int<'_>) -> &'static str1028 fn foo(_: super::Int<'_>) -> &'static str { 1029 "int" 1030 } 1031 1032 #[test] full_switch_case()1033 fn full_switch_case() { 1034 dummy_type!(ty); 1035 btf_type_match!(match ty { 1036 BtfKind::Int(i) => foo(i), 1037 BtfKind::Struct => "it's a struct", 1038 BtfKind::Void => "", 1039 BtfKind::Ptr => "", 1040 BtfKind::Array => "", 1041 BtfKind::Union => "", 1042 BtfKind::Enum => "", 1043 BtfKind::Fwd => "", 1044 BtfKind::Typedef => "", 1045 BtfKind::Volatile => "", 1046 BtfKind::Const => "", 1047 BtfKind::Restrict => "", 1048 BtfKind::Func => "", 1049 BtfKind::FuncProto => "", 1050 BtfKind::Var => "", 1051 BtfKind::DataSec => "", 1052 BtfKind::Float => "", 1053 BtfKind::DeclTag => "", 1054 BtfKind::TypeTag => "", 1055 BtfKind::Enum64 => "", 1056 }); 1057 } 1058 1059 #[test] partial_match()1060 fn partial_match() { 1061 dummy_type!(ty); 1062 btf_type_match!(match ty { 1063 BtfKind::Int => "int", 1064 _ => "default", 1065 }); 1066 } 1067 1068 #[test] or_pattern_match()1069 fn or_pattern_match() { 1070 dummy_type!(ty); 1071 // we ask rustfmt to not format this block so that we can keep the trailing `,` in the 1072 // const | restrict branch. 1073 #[rustfmt::skip] 1074 btf_type_match!(match ty { 1075 BtfKind::Int => "int", 1076 BtfKind::Struct | BtfKind::Union => "composite", 1077 BtfKind::Typedef | BtfKind::Volatile => { 1078 "qualifier" 1079 } 1080 BtfKind::Const | BtfKind::Restrict => { 1081 "const or restrict" 1082 }, 1083 _ => "default", 1084 }); 1085 } 1086 1087 #[test] match_arm_with_brackets()1088 fn match_arm_with_brackets() { 1089 dummy_type!(ty); 1090 // we ask rustfmt to not format this block so that we can keep the trailing `,` in the int 1091 // branch. 1092 #[rustfmt::skip] 1093 btf_type_match!(match ty { 1094 BtfKind::Void => { 1095 "void" 1096 } 1097 BtfKind::Int => { 1098 "int" 1099 }, 1100 BtfKind::Struct => "struct", 1101 _ => "default", 1102 }); 1103 } 1104 1105 #[test] match_on_composite()1106 fn match_on_composite() { 1107 dummy_type!(ty); 1108 btf_type_match!(match ty { 1109 BtfKind::Composite(c) => c.is_struct, 1110 _ => false, 1111 }); 1112 btf_type_match!(match ty { 1113 BtfKind::Composite(c) => { 1114 c.is_struct 1115 } 1116 _ => false, 1117 }); 1118 // we ask rustfmt to not format this block so that we can keep the trailing `,` in the 1119 // composite branch. 1120 #[rustfmt::skip] 1121 btf_type_match!(match ty { 1122 BtfKind::Composite(c) => { 1123 c.is_struct 1124 }, 1125 _ => false, 1126 }); 1127 } 1128 1129 #[test] match_arm_with_multiple_statements()1130 fn match_arm_with_multiple_statements() { 1131 dummy_type!(ty); 1132 1133 btf_type_match!(match ty { 1134 BtfKind::Int(i) => { 1135 let _ = i; 1136 "int" 1137 } 1138 _ => { 1139 let _ = 1; 1140 "default" 1141 } 1142 }); 1143 } 1144 1145 #[test] non_expression_guards()1146 fn non_expression_guards() { 1147 dummy_type!(ty); 1148 1149 btf_type_match!(match ty { 1150 BtfKind::Int => { 1151 let _ = 1; 1152 "int" 1153 } 1154 BtfKind::Typedef | BtfKind::Const => { 1155 let _ = 1; 1156 "qualifier" 1157 } 1158 _ => { 1159 let _ = 1; 1160 "default" 1161 } 1162 }); 1163 1164 btf_type_match!(match ty { 1165 BtfKind::Int => { 1166 let _ = 1; 1167 } 1168 BtfKind::Typedef | BtfKind::Const => { 1169 let _ = 1; 1170 } 1171 _ => { 1172 let _ = 1; 1173 } 1174 }); 1175 } 1176 1177 #[test] linkage_type()1178 fn linkage_type() { 1179 use std::mem::discriminant; 1180 use Linkage::*; 1181 1182 for t in [Static, Global, Extern, Unknown] { 1183 // check if discriminants match after a roundtrip conversion 1184 assert_eq!(discriminant(&t), discriminant(&Linkage::from(t as u32))); 1185 } 1186 } 1187 } 1188