1use crate::{
10 btf::{
11 Array, Const, DataSec, DeclTag, Enum, Enum64, Error as BTFError, ErrorKind as BTFErrorKind,
12 FileHeader, Float, Func, FuncProto, Fwd, Header, Int, Kind, Offset, Ptr, Readable,
13 Restrict, Result as BTFResult, Struct, TypeTag, Typedef, Union, Var, Volatile,
14 },
15 generate_constructor_dispatcher,
16 utils::Reader,
17};
18
19use std::{collections::BTreeMap, ops::Add};
20
21#[cfg(feature = "caching")]
22use std::{collections::HashMap, sync::RwLock};
23
24#[derive(Debug, Clone)]
26pub enum TypeVariant {
27 Void,
29
30 Int(Int),
32
33 Typedef(Typedef),
35
36 Enum(Enum),
38
39 Ptr(Ptr),
41
42 Const(Const),
44
45 Volatile(Volatile),
47
48 Array(Array),
50
51 FuncProto(FuncProto),
53
54 Struct(Struct),
56
57 Union(Union),
59
60 Fwd(Fwd),
62
63 Var(Var),
65
66 Enum64(Enum64),
68
69 Func(Func),
71
72 Float(Float),
74
75 Restrict(Restrict),
77
78 DataSec(DataSec),
80
81 TypeTag(TypeTag),
83
84 DeclTag(DeclTag),
86}
87
88fn get_type_enum_value_name(type_var: &TypeVariant) -> Option<String> {
90 match type_var {
91 TypeVariant::Void => Some("void".to_string()),
92 TypeVariant::Int(int) => int.name().clone(),
93 TypeVariant::Typedef(typedef) => typedef.name().clone(),
94 TypeVariant::Enum(r#enum) => r#enum.name().clone(),
95 TypeVariant::Struct(r#struct) => r#struct.name().clone(),
96 TypeVariant::Union(r#union) => r#union.name().clone(),
97 TypeVariant::Fwd(fwd) => fwd.name().clone(),
98 TypeVariant::Var(var) => var.name().clone(),
99 TypeVariant::Enum64(enum64) => enum64.name().clone(),
100 TypeVariant::Func(func) => func.name().clone(),
101 TypeVariant::Float(float) => float.name().clone(),
102 TypeVariant::DataSec(data_sec) => data_sec.name().clone(),
103 TypeVariant::TypeTag(type_tag) => type_tag.name().clone(),
104 TypeVariant::DeclTag(decl_tag) => decl_tag.name().clone(),
105
106 TypeVariant::Ptr(_)
107 | TypeVariant::Const(_)
108 | TypeVariant::Volatile(_)
109 | TypeVariant::Array(_)
110 | TypeVariant::FuncProto(_)
111 | TypeVariant::Restrict(_) => None,
112 }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
117pub enum TypePathComponent<'a> {
118 Index(usize),
120
121 Name(&'a str),
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
127enum TypePathParserState {
128 Start,
130
131 InsideName,
133
134 InsideIndex,
136
137 AfterIndex,
139
140 ExpectingName,
142
143 Error,
145
146 Done,
148}
149
150#[derive(Debug, Clone)]
152struct TypePathComponentIter<'a> {
153 path: &'a str,
154 position: usize,
155 state: TypePathParserState,
156}
157
158impl<'a> TypePathComponentIter<'a> {
159 fn new(path: &'a str) -> Self {
160 Self {
161 path,
162 position: 0,
163 state: TypePathParserState::Start,
164 }
165 }
166}
167
168impl<'a> Iterator for TypePathComponentIter<'a> {
169 type Item = BTFResult<TypePathComponent<'a>>;
170
171 fn next(&mut self) -> Option<Self::Item> {
172 if self.state == TypePathParserState::Done || self.state == TypePathParserState::Error {
173 return None;
174 }
175
176 let bytes = self.path.as_bytes();
177
178 if self.position >= bytes.len() {
180 self.state = TypePathParserState::Done;
181 return None;
182 }
183
184 match self.state {
185 TypePathParserState::Start => {
186 let c = bytes[self.position] as char;
187 if c == '[' {
188 self.position += 1;
189 self.state = TypePathParserState::InsideIndex;
190 self.parse_index()
191 } else if c.is_alphabetic() || c == '_' {
192 self.state = TypePathParserState::InsideName;
193 self.parse_name()
194 } else {
195 self.state = TypePathParserState::Error;
196 Some(Err(BTFError::new(
197 BTFErrorKind::InvalidTypePath,
198 &format!("Invalid character at index {}", self.position),
199 )))
200 }
201 }
202
203 TypePathParserState::InsideName => self.parse_name(),
204
205 TypePathParserState::InsideIndex => self.parse_index(),
206
207 TypePathParserState::AfterIndex => {
208 let c = bytes[self.position] as char;
209 if c == '[' {
210 self.position += 1;
211 self.state = TypePathParserState::InsideIndex;
212 self.parse_index()
213 } else if c == '.' {
214 self.position += 1;
215 self.state = TypePathParserState::ExpectingName;
216 self.next()
217 } else {
218 self.state = TypePathParserState::Error;
219 Some(Err(BTFError::new(
220 BTFErrorKind::InvalidTypePath,
221 &format!("Invalid character at index {}", self.position),
222 )))
223 }
224 }
225
226 TypePathParserState::ExpectingName => {
227 if self.position >= bytes.len() {
228 self.state = TypePathParserState::Error;
229 return Some(Err(BTFError::new(
230 BTFErrorKind::InvalidTypePath,
231 "Expected name after '.'",
232 )));
233 }
234 let c = bytes[self.position] as char;
235 if c.is_alphabetic() || c == '_' {
236 self.state = TypePathParserState::InsideName;
237 self.parse_name()
238 } else {
239 self.state = TypePathParserState::Error;
240 Some(Err(BTFError::new(
241 BTFErrorKind::InvalidTypePath,
242 &format!("Invalid character at index {}", self.position),
243 )))
244 }
245 }
246
247 TypePathParserState::Done | TypePathParserState::Error => None,
248 }
249 }
250}
251
252impl<'a> TypePathComponentIter<'a> {
253 fn parse_name(&mut self) -> Option<BTFResult<TypePathComponent<'a>>> {
254 let start = self.position;
255 let bytes = self.path.as_bytes();
256
257 while self.position < bytes.len() {
258 let c = bytes[self.position] as char;
259 if c.is_alphanumeric() || c == '_' {
260 self.position += 1;
261 } else if c == '[' || c == '.' {
262 break;
263 } else {
264 self.state = TypePathParserState::Error;
265 return Some(Err(BTFError::new(
266 BTFErrorKind::InvalidTypePath,
267 &format!("Invalid character at index {}", self.position),
268 )));
269 }
270 }
271
272 let name = &self.path[start..self.position];
273
274 if self.position >= bytes.len() {
276 self.state = TypePathParserState::Done;
277 } else {
278 let c = bytes[self.position] as char;
279 if c == '[' {
280 self.position += 1;
281 self.state = TypePathParserState::InsideIndex;
282 } else if c == '.' {
283 self.position += 1;
284 self.state = TypePathParserState::ExpectingName;
285 }
286 }
287
288 Some(Ok(TypePathComponent::Name(name)))
289 }
290
291 fn parse_index(&mut self) -> Option<BTFResult<TypePathComponent<'a>>> {
292 let start = self.position;
293 let bytes = self.path.as_bytes();
294
295 while self.position < bytes.len() {
296 let c = bytes[self.position] as char;
297 if c.is_numeric() {
298 self.position += 1;
299 } else if c == ']' {
300 break;
301 } else {
302 self.state = TypePathParserState::Error;
303 return Some(Err(BTFError::new(
304 BTFErrorKind::InvalidTypePath,
305 &format!("Invalid character at index {}", self.position),
306 )));
307 }
308 }
309
310 if self.position >= bytes.len() || bytes[self.position] as char != ']' {
311 self.state = TypePathParserState::Error;
312 return Some(Err(BTFError::new(
313 BTFErrorKind::InvalidTypePath,
314 "Unclosed index bracket",
315 )));
316 }
317
318 let index_str = &self.path[start..self.position];
319 if index_str.is_empty() {
320 self.state = TypePathParserState::Error;
321 return Some(Err(BTFError::new(
322 BTFErrorKind::InvalidTypePath,
323 "Empty index",
324 )));
325 }
326
327 let index = match index_str.parse::<usize>() {
328 Ok(i) => i,
329 Err(error) => {
330 self.state = TypePathParserState::Error;
331 return Some(Err(BTFError::new(
332 BTFErrorKind::InvalidTypePath,
333 &format!("Invalid index value: {error:?}"),
334 )));
335 }
336 };
337
338 self.position += 1;
340 self.state = TypePathParserState::AfterIndex;
341
342 Some(Ok(TypePathComponent::Index(index)))
343 }
344}
345
346pub struct TypeInformation {
348 id_to_type_map: BTreeMap<u32, TypeVariant>,
350
351 name_to_id_map: BTreeMap<String, u32>,
353
354 id_to_name_map: BTreeMap<u32, String>,
356
357 #[cfg(feature = "caching")]
359 offset_cache: RwLock<HashMap<(u32, String), (u32, Offset)>>,
360}
361
362generate_constructor_dispatcher!(
364 Int, Typedef, Enum, Ptr, Const, Volatile, Array, FuncProto, Struct, Union, Fwd, Var, Enum64,
365 Func, Float, Restrict, DataSec, TypeTag, DeclTag
366);
367
368#[derive(Debug)]
371enum OffsetError<'a> {
372 InvalidTypeId,
373 VoidDereference,
374 IndexOutOfBounds {
375 index: usize,
376 array_size: u32,
377 },
378 ArrayOffsetOverflow,
379 PtrNotIndexable,
380 TypeNotIndexable,
381 NotStructOrUnion,
382 MemberNotFound {
383 name: &'a str,
384 },
385 Btf(BTFError),
387}
388
389impl From<BTFError> for OffsetError<'_> {
390 fn from(e: BTFError) -> Self {
391 OffsetError::Btf(e)
392 }
393}
394
395impl From<OffsetError<'_>> for BTFError {
396 fn from(e: OffsetError<'_>) -> Self {
397 match e {
398 OffsetError::InvalidTypeId => {
399 BTFError::new(BTFErrorKind::InvalidTypeID, "Invalid type id")
400 }
401 OffsetError::VoidDereference => BTFError::new(
402 BTFErrorKind::InvalidTypePath,
403 "The void type can't be dereferenced with a path",
404 ),
405 OffsetError::IndexOutOfBounds { index, array_size } => BTFError::new(
406 BTFErrorKind::InvalidTypePath,
407 &format!("Index {index} is out of bounds for array of size {array_size}"),
408 ),
409 OffsetError::ArrayOffsetOverflow => BTFError::new(
410 BTFErrorKind::InvalidTypePath,
411 "Array element offset overflow",
412 ),
413 OffsetError::PtrNotIndexable => BTFError::new(
414 BTFErrorKind::InvalidTypePath,
415 "Type is a ptr, and dereferencing it would require a read operation",
416 ),
417 OffsetError::TypeNotIndexable => {
418 BTFError::new(BTFErrorKind::InvalidTypePath, "Type is not indexable")
419 }
420 OffsetError::NotStructOrUnion => BTFError::new(
421 BTFErrorKind::InvalidTypePath,
422 "Type is not a struct or union",
423 ),
424 OffsetError::MemberNotFound { name } => BTFError::new(
425 BTFErrorKind::InvalidTypePath,
426 &format!("Member '{}' not found", name),
427 ),
428 OffsetError::Btf(e) => e,
429 }
430 }
431}
432
433impl TypeInformation {
434 pub fn new(readable: &dyn Readable) -> BTFResult<Self> {
436 let mut reader = Reader::new(readable);
437
438 let file_header = FileHeader::new(&mut reader)?;
439 let type_section_start = (file_header
440 .hdr_len()
441 .checked_add(file_header.type_off())
442 .ok_or_else(|| {
443 BTFError::new(
444 BTFErrorKind::InvalidTypeSectionOffset,
445 "Type section start offset overflow",
446 )
447 })?) as usize;
448
449 let type_section_end = type_section_start
450 .checked_add(file_header.type_len() as usize)
451 .ok_or_else(|| {
452 BTFError::new(
453 BTFErrorKind::InvalidTypeSectionOffset,
454 "Type section end offset overflow",
455 )
456 })?;
457
458 reader.set_offset(type_section_start);
459
460 let mut tid_generator: u32 = 1;
461
462 let mut id_to_type_map = BTreeMap::<u32, TypeVariant>::new();
463 let mut name_to_id_map = BTreeMap::<String, u32>::new();
464 let mut id_to_name_map = BTreeMap::<u32, String>::new();
465
466 while reader.offset() < type_section_end {
467 let type_header = Header::new(&mut reader, &file_header)?;
468 let btf_type = parse_type(type_header.kind(), &mut reader, &file_header, type_header)?;
469
470 let tid = tid_generator;
471 tid_generator += 1;
472
473 if let Some(name) = get_type_enum_value_name(&btf_type) {
474 name_to_id_map.insert(name.to_string(), tid);
475 id_to_name_map.insert(tid, name.to_string());
476 }
477
478 id_to_type_map.insert(tid, btf_type);
479 }
480
481 Ok(Self {
482 id_to_type_map,
483 name_to_id_map,
484 id_to_name_map,
485 #[cfg(feature = "caching")]
486 offset_cache: RwLock::new(HashMap::new()),
487 })
488 }
489
490 pub fn get(&self) -> &BTreeMap<u32, TypeVariant> {
492 &self.id_to_type_map
493 }
494
495 pub fn id_of(&self, type_name: &str) -> Option<u32> {
497 if type_name == "void" {
498 return Some(0);
499 }
500
501 self.name_to_id_map.get(type_name).copied()
502 }
503
504 pub fn from_id(&self, tid: u32) -> Option<TypeVariant> {
506 if tid == 0 {
507 return Some(TypeVariant::Void);
508 }
509
510 self.id_to_type_map.get(&tid).cloned()
511 }
512
513 pub fn name_of(&self, tid: u32) -> Option<String> {
515 if tid == 0 {
516 return Some("void".to_string());
517 }
518
519 self.id_to_name_map.get(&tid).cloned()
520 }
521
522 pub fn pointee_tid(&self, tid: u32) -> BTFResult<u32> {
524 match self.from_id(tid) {
525 None => Err(BTFError::new(
526 BTFErrorKind::InvalidTypeID,
527 "Invalid type id",
528 )),
529
530 Some(type_variant) => match type_variant {
531 TypeVariant::Typedef(typedef) => self.pointee_tid(*typedef.tid()),
532 TypeVariant::Const(cnst) => self.pointee_tid(*cnst.tid()),
533 TypeVariant::Volatile(volatile) => self.pointee_tid(*volatile.tid()),
534 TypeVariant::Restrict(restrict) => self.pointee_tid(*restrict.tid()),
535
536 TypeVariant::Ptr(ptr) => Ok(*ptr.tid()),
537
538 _ => Err(BTFError::new(
539 BTFErrorKind::InvalidTypeID,
540 "Type is not a pointer",
541 )),
542 },
543 }
544 }
545
546 pub fn size_of(&self, tid: u32) -> BTFResult<usize> {
548 let type_variant = self.from_id(tid).ok_or(BTFError::new(
549 BTFErrorKind::InvalidTypeID,
550 "Invalid type id",
551 ))?;
552
553 match type_variant {
554 TypeVariant::Ptr(_) => {
555 let list_head_tid = self.id_of("list_head").ok_or(BTFError::new(
556 BTFErrorKind::InvalidTypeID,
557 "The `struct list_head` type, used to extract the pointer size, was not found",
558 ))?;
559
560 let list_head_type_var = self.from_id(list_head_tid).ok_or(
561 BTFError::new(BTFErrorKind::InvalidTypeID, "The extracted `struct list_head` type ID, used to extract the pointer size, was invalid"),
562 )?;
563
564 let list_head_type_size = match list_head_type_var {
565 TypeVariant::Struct(str) => Ok(*str.size()),
566
567 _ => Err(BTFError::new(
568 BTFErrorKind::InvalidTypeID,
569 "The extracted `struct list_head` type ID, used to extract the pointer size, is not a struct type",
570 )),
571 }?;
572
573 Ok(list_head_type_size / 2)
574 }
575
576 TypeVariant::Array(array) => {
577 let tid = *array.element_tid();
578 let element_size = self.size_of(tid)?;
579 let element_count = *array.element_count() as usize;
580
581 Ok(element_size * element_count)
582 }
583
584 TypeVariant::Float(float) => Ok(*float.size()),
585 TypeVariant::Int(int) => Ok(*int.size()),
586 TypeVariant::Enum(enm) => Ok(*enm.size()),
587 TypeVariant::Enum64(enm) => Ok(*enm.size()),
588 TypeVariant::Struct(str) => Ok(*str.size()),
589 TypeVariant::Union(union) => Ok(*union.size()),
590 TypeVariant::DataSec(data_sec) => Ok(*data_sec.size()),
591
592 TypeVariant::Var(var) => self.size_of(*var.tid()),
593 TypeVariant::Typedef(typedef) => self.size_of(*typedef.tid()),
594 TypeVariant::Const(cnst) => self.size_of(*cnst.tid()),
595 TypeVariant::Volatile(volatile) => self.size_of(*volatile.tid()),
596 TypeVariant::Restrict(restrict) => self.size_of(*restrict.tid()),
597 TypeVariant::TypeTag(type_tag) => self.size_of(*type_tag.tid()),
598
599 _ => Err(BTFError::new(
600 BTFErrorKind::NotSized,
601 &format!("Type {type_variant:?} has no size"),
602 )),
603 }
604 }
605
606 pub fn offset_of(&self, tid: u32, path: &str) -> BTFResult<(u32, Offset)> {
608 #[cfg(feature = "caching")]
609 {
610 let cache_key = (tid, path.to_string());
612 if let Ok(cache) = self.offset_cache.read()
613 && let Some(&cached) = cache.get(&cache_key)
614 {
615 return Ok(cached);
616 }
617
618 let result = self.offset_of_uncached(tid, path)?;
620
621 if let Ok(mut cache) = self.offset_cache.write() {
623 cache.insert(cache_key, result);
624 }
625
626 Ok(result)
627 }
628
629 #[cfg(not(feature = "caching"))]
630 self.offset_of_uncached(tid, path)
631 }
632
633 fn offset_of_uncached(&self, tid: u32, path: &str) -> BTFResult<(u32, Offset)> {
635 let mut path_iter = TypePathComponentIter::new(path);
636 self.offset_of_impl(Offset::ByteOffset(0), tid, &mut path_iter)
637 .map_err(Into::into)
638 }
639
640 fn offset_of_impl<'a>(
645 &self,
646 mut offset: Offset,
647 mut tid: u32,
648 path: &mut TypePathComponentIter<'a>,
649 ) -> Result<(u32, Offset), OffsetError<'a>> {
650 loop {
651 let path_for_anon = path.clone();
653
654 let component = match path.next() {
656 None => return Ok((tid, offset)),
657 Some(result) => result?,
658 };
659
660 let type_var = loop {
662 let type_var = self.from_id(tid).ok_or(OffsetError::InvalidTypeId)?;
663
664 match &type_var {
665 TypeVariant::Fwd(fwd) => {
666 tid = *fwd.tid();
667 }
668 TypeVariant::Typedef(typedef) => {
669 tid = *typedef.tid();
670 }
671 TypeVariant::Const(cnst) => {
672 tid = *cnst.tid();
673 }
674 TypeVariant::Volatile(volatile) => {
675 tid = *volatile.tid();
676 }
677 TypeVariant::Restrict(restrict) => {
678 tid = *restrict.tid();
679 }
680 _ => break type_var,
681 }
682 };
683
684 if matches!(type_var, TypeVariant::Void) {
686 return Err(OffsetError::VoidDereference);
687 }
688
689 match component {
690 TypePathComponent::Index(index) => match &type_var {
691 TypeVariant::Array(array) => {
692 let element_count = *array.element_count() as usize;
693 if index >= element_count {
694 return Err(OffsetError::IndexOutOfBounds {
695 index,
696 array_size: *array.element_count(),
697 });
698 }
699
700 let element_tid = *array.element_tid();
701 let element_type_size = self.size_of(element_tid)?;
702
703 let index_size = (index as u64)
704 .checked_mul(element_type_size as u64)
705 .and_then(|v| u32::try_from(v).ok())
706 .ok_or(OffsetError::ArrayOffsetOverflow)?;
707
708 offset = offset.add(index_size)?;
709 tid = element_tid;
710 }
711
712 TypeVariant::Ptr(_) => {
713 return Err(OffsetError::PtrNotIndexable);
714 }
715
716 _ => {
717 return Err(OffsetError::TypeNotIndexable);
718 }
719 },
720
721 TypePathComponent::Name(name) => {
722 let member_list: &[_] = match &type_var {
723 TypeVariant::Struct(s) => s.member_list(),
724 TypeVariant::Union(u) => u.member_list(),
725 _ => {
726 return Err(OffsetError::NotStructOrUnion);
727 }
728 };
729
730 for member in member_list.iter().filter(|m| m.name().is_none()) {
732 let mut anon_path = path_for_anon.clone();
733 match self.offset_of_impl(
734 member.offset().add(offset)?,
735 member.tid(),
736 &mut anon_path,
737 ) {
738 Ok((result_tid, result_offset)) => {
739 return Ok((result_tid, result_offset));
740 }
741 Err(_) => continue,
742 }
743 }
744
745 match member_list
747 .iter()
748 .find(|member| member.name().as_deref() == Some(name))
749 {
750 Some(member) => {
751 tid = member.tid();
752 offset = offset.add(member.offset())?;
753 }
754 None => {
755 return Err(OffsetError::MemberNotFound { name });
756 }
757 }
758 }
759 }
760 }
761 }
762}
763
764#[cfg(test)]
765mod tests {
766 use std::vec;
767
768 use super::*;
769
770 use crate::btf::{
771 LinkageType,
772 data_sec::Variable as DataSecVariable,
773 r#enum::{Integer32Value as IntegerValue32, NamedValue32},
774 enum64::{Integer64Value as IntegerValue64, NamedValue64},
775 struct_union::Member as StructMember,
776 };
777 use crate::utils::ReadableBuffer;
778 #[cfg(feature = "caching")]
779 use std::{collections::HashMap, sync::RwLock};
780
781 fn collect_path_components(path: &str) -> BTFResult<Vec<TypePathComponent<'_>>> {
783 TypePathComponentIter::new(path).collect()
784 }
785
786 #[test]
787 fn test_path_component_iter() {
788 let type_path = collect_path_components("").unwrap();
789 assert!(type_path.is_empty());
790
791 let type_path = collect_path_components("[1]").unwrap();
792 assert_eq!(type_path.len(), 1);
793 assert_eq!(type_path[0], TypePathComponent::Index(1));
794
795 let type_path = collect_path_components("[1][2]").unwrap();
796 assert_eq!(type_path.len(), 2);
797 assert_eq!(type_path[0], TypePathComponent::Index(1));
798 assert_eq!(type_path[1], TypePathComponent::Index(2));
799
800 let type_path = collect_path_components("test").unwrap();
801 assert_eq!(type_path.len(), 1);
802 assert_eq!(type_path[0], TypePathComponent::Name("test"));
803
804 let type_path = collect_path_components("array[10]").unwrap();
805 assert_eq!(type_path.len(), 2);
806 assert_eq!(type_path[0], TypePathComponent::Name("array"));
807 assert_eq!(type_path[1], TypePathComponent::Index(10));
808
809 let type_path = collect_path_components("array[10].array2[11]").unwrap();
810 assert_eq!(type_path.len(), 4);
811 assert_eq!(type_path[0], TypePathComponent::Name("array"));
812 assert_eq!(type_path[1], TypePathComponent::Index(10));
813 assert_eq!(type_path[2], TypePathComponent::Name("array2"));
814 assert_eq!(type_path[3], TypePathComponent::Index(11));
815
816 let type_path = collect_path_components("_test").unwrap();
818 assert_eq!(type_path.len(), 1);
819 assert_eq!(type_path[0], TypePathComponent::Name("_test"));
820
821 let type_path = collect_path_components("test_field").unwrap();
822 assert_eq!(type_path.len(), 1);
823 assert_eq!(type_path[0], TypePathComponent::Name("test_field"));
824
825 assert!(collect_path_components(".value").is_err());
826 assert!(collect_path_components(".[10]").is_err());
827 assert!(collect_path_components("[value").is_err());
828 assert!(collect_path_components("]value").is_err());
829 assert!(collect_path_components("1").is_err());
830 assert!(collect_path_components("array[10]value").is_err());
831 assert!(collect_path_components("array[]").is_err());
832 assert!(collect_path_components("[]").is_err());
833 }
834
835 fn get_test_type_info() -> TypeInformation {
836 let mut type_info = TypeInformation {
837 id_to_type_map: BTreeMap::<u32, TypeVariant>::new(),
838 name_to_id_map: BTreeMap::<String, u32>::new(),
839 id_to_name_map: BTreeMap::<u32, String>::new(),
840 #[cfg(feature = "caching")]
841 offset_cache: RwLock::new(HashMap::new()),
842 };
843
844 type_info.id_to_type_map.insert(
846 1,
847 TypeVariant::Int(Int::create(
848 Header::create(Kind::Int, 1, 0, false, 4),
849 Some(String::from("unsigned int")),
850 4,
851 false,
852 false,
853 false,
854 0,
855 32,
856 )),
857 );
858
859 type_info
860 .name_to_id_map
861 .insert(String::from("unsigned int"), 1);
862
863 type_info
864 .id_to_name_map
865 .insert(1, String::from("unsigned int"));
866
867 type_info.id_to_type_map.insert(
870 2,
871 TypeVariant::Ptr(Ptr::create(Header::create(Kind::Ptr, 0, 0, false, 6), 6)),
872 );
873
874 type_info.id_to_type_map.insert(
876 3,
877 TypeVariant::Array(Array::create(
878 Header::create(Kind::Array, 0, 0, false, 0),
879 1,
880 1,
881 10,
882 )),
883 );
884
885 type_info.id_to_type_map.insert(
891 4,
892 TypeVariant::Struct(Struct::create(
893 Header::create(Kind::Struct, 0, 2, false, 8),
894 None,
895 8,
896 vec![
897 StructMember::create(
898 1,
899 Some(String::from("anon_struct_value1")),
900 1,
901 Offset::ByteOffset(0),
902 ),
903 StructMember::create(
904 1,
905 Some(String::from("anon_struct_value2")),
906 1,
907 Offset::ByteOffset(32),
908 ),
909 ],
910 )),
911 );
912
913 type_info.id_to_type_map.insert(
915 5,
916 TypeVariant::Union(Union::create(
917 Header::create(Kind::Union, 0, 2, true, 8),
918 None,
919 8,
920 vec![
921 StructMember::create(
922 1,
923 Some(String::from("anon_union_value1")),
924 1,
925 Offset::ByteOffset(0),
926 ),
927 StructMember::create(
928 1,
929 Some(String::from("anon_union_value2")),
930 2,
931 Offset::ByteOffset(0),
932 ),
933 ],
934 )),
935 );
936
937 type_info.id_to_type_map.insert(
939 6,
940 TypeVariant::Struct(Struct::create(
941 Header::create(Kind::Struct, 1, 4, false, 28),
942 Some(String::from("Struct")),
943 28,
944 vec![
945 StructMember::create(0, None, 4, Offset::ByteOffset(0)),
946 StructMember::create(0, None, 5, Offset::ByteOffset(64)),
947 StructMember::create(
948 1,
949 Some(String::from("int_value")),
950 1,
951 Offset::ByteOffset(128),
952 ),
953 StructMember::create(
954 1,
955 Some(String::from("ptr_value")),
956 2,
957 Offset::ByteOffset(160),
958 ),
959 ],
960 )),
961 );
962
963 type_info.name_to_id_map.insert(String::from("Struct"), 6);
964 type_info.id_to_name_map.insert(6, String::from("Struct"));
965
966 type_info.id_to_type_map.insert(
968 7,
969 TypeVariant::Struct(Struct::create(
970 Header::create(Kind::Struct, 1, 2, false, 16),
971 Some(String::from("list_head")),
972 16,
973 vec![
974 StructMember::create(1, Some(String::from("next")), 2, Offset::ByteOffset(0)),
975 StructMember::create(1, Some(String::from("prev")), 2, Offset::ByteOffset(64)),
976 ],
977 )),
978 );
979
980 type_info
981 .name_to_id_map
982 .insert(String::from("list_head"), 7);
983
984 type_info
985 .id_to_name_map
986 .insert(7, String::from("list_head"));
987
988 type_info.id_to_type_map.insert(
990 8,
991 TypeVariant::Enum(Enum::create(
992 Header::create(Kind::Enum, 1, 2, false, 4),
993 Some(String::from("Enum32")),
994 4,
995 vec![NamedValue32 {
996 name: String::from("Enum32Value1"),
997 value: IntegerValue32::Unsigned(0),
998 }],
999 false,
1000 )),
1001 );
1002
1003 type_info.name_to_id_map.insert(String::from("Enum32"), 8);
1004 type_info.id_to_name_map.insert(8, String::from("Enum32"));
1005
1006 type_info.id_to_type_map.insert(
1008 9,
1009 TypeVariant::Enum64(Enum64::create(
1010 Header::create(Kind::Enum64, 1, 2, false, 8),
1011 Some(String::from("Enum64")),
1012 8,
1013 vec![NamedValue64 {
1014 name: String::from("Enum64Value1"),
1015 value: IntegerValue64::Unsigned(0),
1016 }],
1017 false,
1018 )),
1019 );
1020
1021 type_info.name_to_id_map.insert(String::from("Enum64"), 9);
1022 type_info.id_to_name_map.insert(9, String::from("Enum64"));
1023
1024 type_info.id_to_type_map.insert(
1026 10,
1027 TypeVariant::Fwd(Fwd::create(
1028 Header::create(Kind::Fwd, 1, 0, false, 6),
1029 Some(String::from("Fwd")),
1030 6,
1031 )),
1032 );
1033
1034 type_info
1035 .name_to_id_map
1036 .insert(String::from("StructForwardDecl"), 10);
1037 type_info
1038 .id_to_name_map
1039 .insert(10, String::from("StructForwardDecl"));
1040
1041 type_info.id_to_type_map.insert(
1043 11,
1044 TypeVariant::Typedef(Typedef::create(
1045 Header::create(Kind::Typedef, 1, 2, false, 6),
1046 6,
1047 Some(String::from("StructAlias")),
1048 )),
1049 );
1050
1051 type_info
1052 .name_to_id_map
1053 .insert(String::from("StructAlias"), 11);
1054
1055 type_info
1056 .id_to_name_map
1057 .insert(11, String::from("StructAlias"));
1058
1059 type_info.id_to_type_map.insert(
1061 12,
1062 TypeVariant::Volatile(Volatile::create(
1063 Header::create(Kind::Volatile, 0, 0, false, 6),
1064 6,
1065 )),
1066 );
1067
1068 type_info.id_to_type_map.insert(
1070 13,
1071 TypeVariant::Const(Const::create(
1072 Header::create(Kind::Const, 0, 0, false, 6),
1073 6,
1074 )),
1075 );
1076
1077 type_info.id_to_type_map.insert(
1079 14,
1080 TypeVariant::Restrict(Restrict::create(
1081 Header::create(Kind::Restrict, 0, 0, false, 6),
1082 6,
1083 )),
1084 );
1085
1086 type_info.id_to_type_map.insert(
1088 15,
1089 TypeVariant::Func(Func::create(
1090 Header::create(Kind::Func, 1, 0, false, 16),
1091 Some(String::from("func")),
1092 16,
1093 )),
1094 );
1095
1096 type_info.name_to_id_map.insert(String::from("func"), 15);
1097 type_info.id_to_name_map.insert(15, String::from("func"));
1098
1099 type_info.id_to_type_map.insert(
1101 16,
1102 TypeVariant::FuncProto(FuncProto::create(
1103 Header::create(Kind::FuncProto, 0, 0, false, 1),
1104 1,
1105 vec![],
1106 )),
1107 );
1108
1109 type_info.id_to_type_map.insert(
1111 17,
1112 TypeVariant::Var(Var::create(
1113 Header::create(Kind::Var, 1, 0, false, 1),
1114 Some(String::from("var")),
1115 1,
1116 0,
1117 LinkageType::Global,
1118 )),
1119 );
1120
1121 type_info.name_to_id_map.insert(String::from("var"), 17);
1122 type_info.id_to_name_map.insert(17, String::from("var"));
1123
1124 type_info.id_to_type_map.insert(
1126 18,
1127 TypeVariant::DataSec(DataSec::create(
1128 Header::create(Kind::DataSec, 1, 3, false, 12),
1129 Some(String::from(".data")),
1130 12,
1131 vec![
1132 DataSecVariable {
1133 var_decl_id: 17,
1134 offset: 0,
1135 var_size: 4,
1136 },
1137 DataSecVariable {
1138 var_decl_id: 17,
1139 offset: 4,
1140 var_size: 4,
1141 },
1142 DataSecVariable {
1143 var_decl_id: 17,
1144 offset: 8,
1145 var_size: 4,
1146 },
1147 ],
1148 )),
1149 );
1150
1151 type_info.name_to_id_map.insert(String::from(".data"), 18);
1152 type_info.id_to_name_map.insert(18, String::from(".data"));
1153
1154 type_info.id_to_type_map.insert(
1156 19,
1157 TypeVariant::Float(Float::create(
1158 Header::create(Kind::Float, 1, 0, false, 8),
1159 Some(String::from("double")),
1160 8,
1161 )),
1162 );
1163
1164 type_info.name_to_id_map.insert(String::from("double"), 19);
1165 type_info.id_to_name_map.insert(19, String::from("double"));
1166
1167 type_info.id_to_type_map.insert(
1169 20,
1170 TypeVariant::DeclTag(DeclTag::create(
1171 Header::create(Kind::DeclTag, 1, 0, false, 6),
1172 Some(String::from("decl_tag")),
1173 6,
1174 0,
1175 )),
1176 );
1177
1178 type_info
1179 .name_to_id_map
1180 .insert(String::from("decl_tag"), 20);
1181
1182 type_info
1183 .id_to_name_map
1184 .insert(20, String::from("decl_tag"));
1185
1186 type_info.id_to_type_map.insert(
1188 21,
1189 TypeVariant::TypeTag(TypeTag::create(
1190 Header::create(Kind::TypeTag, 1, 0, false, 11),
1191 Some(String::from("type_tag")),
1192 11,
1193 )),
1194 );
1195
1196 type_info
1197 .name_to_id_map
1198 .insert(String::from("type_tag"), 21);
1199
1200 type_info
1201 .id_to_name_map
1202 .insert(21, String::from("type_tag"));
1203
1204 type_info.id_to_type_map.insert(
1226 100,
1227 TypeVariant::Int(Int::create(
1228 Header::create(Kind::Int, 1, 0, false, 8),
1229 Some(String::from("unsigned long int")),
1230 8,
1231 false,
1232 false,
1233 false,
1234 0,
1235 64,
1236 )),
1237 );
1238
1239 type_info.id_to_type_map.insert(
1240 101,
1241 TypeVariant::Struct(Struct::create(
1242 Header::create(Kind::Struct, 0, 2, false, 8),
1243 None,
1244 8,
1245 vec![
1246 StructMember::create(1, Some(String::from("hash")), 1, Offset::ByteOffset(0)),
1247 StructMember::create(1, Some(String::from("len")), 1, Offset::ByteOffset(4)),
1248 ],
1249 )),
1250 );
1251
1252 type_info.id_to_type_map.insert(
1253 102,
1254 TypeVariant::Union(Union::create(
1255 Header::create(Kind::Union, 0, 2, false, 8),
1256 None,
1257 8,
1258 vec![
1259 StructMember::create(0, None, 101, Offset::ByteOffset(0)),
1260 StructMember::create(
1261 1,
1262 Some(String::from("hash_len")),
1263 100,
1264 Offset::ByteOffset(0),
1265 ),
1266 ],
1267 )),
1268 );
1269
1270 type_info.id_to_type_map.insert(
1271 103,
1272 TypeVariant::Struct(Struct::create(
1273 Header::create(Kind::Struct, 1, 2, false, 8),
1274 Some(String::from("qstr")),
1275 8,
1276 vec![
1277 StructMember::create(0, None, 102, Offset::ByteOffset(0)),
1278 StructMember::create(1, Some(String::from("name")), 100, Offset::ByteOffset(8)),
1279 ],
1280 )),
1281 );
1282
1283 type_info.id_to_type_map.insert(
1284 104,
1285 TypeVariant::Struct(Struct::create(
1286 Header::create(Kind::Struct, 1, 3, false, 16),
1287 Some(String::from("dentry")),
1288 8,
1289 vec![
1290 StructMember::create(1, Some(String::from("test1")), 1, Offset::ByteOffset(0)),
1291 StructMember::create(
1292 1,
1293 Some(String::from("d_name")),
1294 103,
1295 Offset::ByteOffset(32),
1296 ),
1297 StructMember::create(
1298 1,
1299 Some(String::from("test2")),
1300 1,
1301 Offset::ByteOffset(256),
1302 ),
1303 ],
1304 )),
1305 );
1306
1307 type_info
1308 }
1309
1310 #[test]
1311 fn test_size_of() {
1312 let type_info = get_test_type_info();
1313
1314 assert_eq!(type_info.name_of(0).unwrap(), "void");
1316 assert!(type_info.size_of(0).unwrap_err().kind() == BTFErrorKind::NotSized);
1317
1318 assert_eq!(type_info.size_of(1).unwrap(), 4);
1320
1321 assert_eq!(type_info.size_of(2).unwrap(), 8);
1323
1324 assert_eq!(type_info.size_of(3).unwrap(), 40);
1326
1327 assert_eq!(type_info.size_of(4).unwrap(), 8);
1329
1330 assert_eq!(type_info.size_of(5).unwrap(), 8);
1332
1333 assert_eq!(type_info.size_of(6).unwrap(), 28);
1335
1336 assert_eq!(type_info.size_of(7).unwrap(), 16);
1338
1339 assert_eq!(type_info.size_of(8).unwrap(), 4);
1341
1342 assert_eq!(type_info.size_of(9).unwrap(), 8);
1344
1345 assert_eq!(type_info.name_of(10).unwrap(), "StructForwardDecl");
1347 assert!(type_info.size_of(10).unwrap_err().kind() == BTFErrorKind::NotSized);
1348
1349 assert_eq!(type_info.size_of(11).unwrap(), 28);
1351
1352 assert_eq!(type_info.size_of(12).unwrap(), 28);
1354
1355 assert_eq!(type_info.size_of(13).unwrap(), 28);
1357
1358 assert_eq!(type_info.size_of(14).unwrap(), 28);
1360
1361 assert_eq!(type_info.name_of(15).unwrap(), "func");
1363 assert!(type_info.size_of(15).unwrap_err().kind() == BTFErrorKind::NotSized);
1364
1365 assert!(type_info.size_of(16).unwrap_err().kind() == BTFErrorKind::NotSized);
1367
1368 assert_eq!(type_info.size_of(17).unwrap(), 4);
1370
1371 assert_eq!(type_info.size_of(18).unwrap(), 12);
1373
1374 assert_eq!(type_info.size_of(19).unwrap(), 8);
1376
1377 assert!(type_info.size_of(20).unwrap_err().kind() == BTFErrorKind::NotSized);
1379
1380 assert_eq!(type_info.size_of(21).unwrap(), 28);
1382 }
1383
1384 #[test]
1385 fn pointee_tid() {
1386 let type_info = get_test_type_info();
1387 assert_eq!(type_info.pointee_tid(2).unwrap(), 6);
1388 }
1389
1390 #[test]
1391 fn test_offset_of() {
1392 let type_info = get_test_type_info();
1393
1394 let no_deref_tid_list1 = [0, 1, 2, 8, 9, 10, 19];
1396
1397 let no_deref_tid_list2 = [15, 16, 17, 18, 20, 21];
1399
1400 for tid in no_deref_tid_list1.iter().chain(no_deref_tid_list2.iter()) {
1401 assert_eq!(
1402 type_info.offset_of(*tid, "test").unwrap_err().kind(),
1403 BTFErrorKind::InvalidTypePath
1404 );
1405
1406 assert_eq!(
1407 type_info.offset_of(*tid, "[0]").unwrap_err().kind(),
1408 BTFErrorKind::InvalidTypePath
1409 );
1410 }
1411
1412 assert_eq!(
1414 type_info
1415 .offset_of(3, "[10000000000000000000000000000]")
1416 .unwrap_err()
1417 .kind(),
1418 BTFErrorKind::InvalidTypePath
1419 );
1420
1421 assert_eq!(
1422 type_info.offset_of(3, "[test]").unwrap_err().kind(),
1423 BTFErrorKind::InvalidTypePath
1424 );
1425
1426 assert_eq!(
1427 type_info.offset_of(3, "test").unwrap_err().kind(),
1428 BTFErrorKind::InvalidTypePath
1429 );
1430
1431 assert_eq!(
1433 type_info.offset_of(3, "[0]").unwrap(),
1434 (1, Offset::ByteOffset(0))
1435 );
1436
1437 assert_eq!(
1438 type_info.offset_of(3, "[1]").unwrap(),
1439 (1, Offset::ByteOffset(4))
1440 );
1441
1442 assert_eq!(
1443 type_info.offset_of(3, "[2]").unwrap(),
1444 (1, Offset::ByteOffset(8))
1445 );
1446
1447 assert_eq!(
1448 type_info.offset_of(3, "[3]").unwrap(),
1449 (1, Offset::ByteOffset(12))
1450 );
1451
1452 assert_eq!(
1453 type_info.offset_of(3, "[4]").unwrap(),
1454 (1, Offset::ByteOffset(16))
1455 );
1456
1457 assert_eq!(
1458 type_info.offset_of(3, "[5]").unwrap(),
1459 (1, Offset::ByteOffset(20))
1460 );
1461
1462 assert_eq!(
1463 type_info.offset_of(3, "[6]").unwrap(),
1464 (1, Offset::ByteOffset(24))
1465 );
1466
1467 assert_eq!(
1468 type_info.offset_of(3, "[7]").unwrap(),
1469 (1, Offset::ByteOffset(28))
1470 );
1471
1472 assert_eq!(
1473 type_info.offset_of(3, "[8]").unwrap(),
1474 (1, Offset::ByteOffset(32))
1475 );
1476
1477 assert_eq!(
1478 type_info.offset_of(3, "[9]").unwrap(),
1479 (1, Offset::ByteOffset(36))
1480 );
1481
1482 assert_eq!(
1483 type_info.offset_of(3, "[10]").unwrap_err().kind(),
1484 BTFErrorKind::InvalidTypePath
1485 );
1486
1487 for struct_tid in [6, 11, 12, 13, 14] {
1489 let int_value_offset = type_info.offset_of(struct_tid, "int_value").unwrap();
1490 assert_eq!(int_value_offset, (1, Offset::ByteOffset(16 * 8)));
1491
1492 let ptr_value_offset = type_info.offset_of(struct_tid, "ptr_value").unwrap();
1493
1494 assert_eq!(ptr_value_offset, (2, Offset::ByteOffset(20 * 8)));
1495
1496 let anon_struct_value1_offset = type_info
1497 .offset_of(struct_tid, "anon_struct_value1")
1498 .unwrap();
1499
1500 assert_eq!(anon_struct_value1_offset, (1, Offset::ByteOffset(0)));
1501
1502 let anon_struct_value2_offset = type_info
1503 .offset_of(struct_tid, "anon_struct_value2")
1504 .unwrap();
1505
1506 assert_eq!(anon_struct_value2_offset, (1, Offset::ByteOffset(4 * 8)));
1507
1508 let anon_union_value1_offset = type_info
1509 .offset_of(struct_tid, "anon_union_value1")
1510 .unwrap();
1511
1512 assert_eq!(anon_union_value1_offset, (1, Offset::ByteOffset(8 * 8)));
1513
1514 let anon_union_value2_offset = type_info
1515 .offset_of(struct_tid, "anon_union_value2")
1516 .unwrap();
1517
1518 assert_eq!(anon_union_value2_offset, (2, Offset::ByteOffset(8 * 8)));
1519 }
1520
1521 assert_eq!(
1522 type_info.offset_of(104, "test1").unwrap(),
1523 (1, Offset::ByteOffset(0))
1524 );
1525
1526 assert_eq!(
1527 type_info.offset_of(104, "d_name").unwrap(),
1528 (103, Offset::ByteOffset(32))
1529 );
1530
1531 assert_eq!(
1532 type_info.offset_of(104, "test2").unwrap(),
1533 (1, Offset::ByteOffset(256))
1534 );
1535
1536 assert_eq!(
1537 type_info.offset_of(104, "d_name.hash").unwrap(),
1538 (1, Offset::ByteOffset(32))
1539 );
1540
1541 assert_eq!(
1542 type_info.offset_of(104, "d_name.len").unwrap(),
1543 (1, Offset::ByteOffset(36))
1544 );
1545
1546 assert_eq!(
1547 type_info.offset_of(104, "d_name.hash_len").unwrap(),
1548 (100, Offset::ByteOffset(32))
1549 );
1550
1551 assert_eq!(
1552 type_info.offset_of(104, "d_name.name").unwrap(),
1553 (100, Offset::ByteOffset(40))
1554 );
1555 }
1556
1557 #[test]
1558 fn test_type_section_offset_overflow() {
1559 let readable_buffer = ReadableBuffer::new(&[
1561 0x9F, 0xEB, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, ]);
1573
1574 let result = TypeInformation::new(&readable_buffer);
1575 assert!(result.is_err());
1576 if let Err(err) = result {
1577 assert_eq!(err.kind(), BTFErrorKind::InvalidTypeSectionOffset);
1578 }
1579 }
1580
1581 #[test]
1582 fn test_type_section_end_overflow() {
1583 let readable_buffer = ReadableBuffer::new(&[
1585 0x9F, 0xEB, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, ]);
1597
1598 let result = TypeInformation::new(&readable_buffer);
1599 assert!(result.is_err());
1600 if let Err(err) = result {
1601 assert_eq!(err.kind(), BTFErrorKind::InvalidTypeSectionOffset);
1602 }
1603 }
1604
1605 #[test]
1606 fn test_array_element_offset_overflow() {
1607 let mut type_info = get_test_type_info();
1610
1611 type_info.id_to_type_map.insert(
1613 200,
1614 TypeVariant::Int(Int::create(
1615 Header::create(Kind::Int, 1, 0, false, 0x10000000),
1616 Some(String::from("huge_int")),
1617 0x10000000,
1618 false,
1619 false,
1620 false,
1621 0,
1622 32,
1623 )),
1624 );
1625
1626 type_info.id_to_type_map.insert(
1628 201,
1629 TypeVariant::Array(Array::create(
1630 Header::create(Kind::Array, 0, 0, false, 0),
1631 200, 200, 100, )),
1635 );
1636
1637 let result = type_info.offset_of(201, "[20]");
1638 assert!(result.is_err());
1639 assert_eq!(result.unwrap_err().kind(), BTFErrorKind::InvalidTypePath);
1640
1641 let result = type_info.offset_of(201, "[0]");
1642 assert!(result.is_ok());
1643 }
1644}