1 //===-- SourcePrinter.cpp - source interleaving utilities ----------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/BTF/BTFContext.h"
10 #include "llvm/ObjectYAML/YAML.h"
11 #include "llvm/ObjectYAML/yaml2obj.h"
12 #include "llvm/Support/SwapByteOrder.h"
13 #include "llvm/Testing/Support/Error.h"
16 using namespace llvm::object
;
18 #define LC(Line, Col) ((Line << 10u) | Col)
19 #define ASSERT_SUCCEEDED(E) ASSERT_THAT_ERROR((E), Succeeded())
21 const char BTFEndOfData
[] =
22 "error while reading .BTF section: unexpected end of data";
23 const char BTFExtEndOfData
[] =
24 "error while reading .BTF.ext section: unexpected end of data";
26 static raw_ostream
&operator<<(raw_ostream
&OS
, const yaml::BinaryRef
&Ref
) {
32 static yaml::BinaryRef
makeBinRef(const T
*Ptr
, size_t Size
= sizeof(T
)) {
33 return yaml::BinaryRef(ArrayRef
<uint8_t>((const uint8_t *)Ptr
, Size
));
37 // This is a mockup for an ELF file containing .BTF and .BTF.ext sections.
38 // Binary content of these sections corresponds to the value of
39 // MockData1::BTF and MockData1::Ext fields.
41 // The yaml::yaml2ObjectFile() is used to generate actual ELF,
42 // see MockData1::makeObj().
44 // The `BTF` and `Ext` fields are initialized with correct values
45 // valid for a small example with a few sections, fields could be
46 // modified before a call to `makeObj()` to test parser with invalid
50 // Use "pragma pack" to model .BTF & .BTF.ext sections content using
51 // 'struct' objects. This pragma is supported by CLANG, GCC & MSVC,
52 // which matters for LLVM CI.
55 BTF::Header Header
= {};
61 char Line1
[11] = "first line";
62 char Line2
[12] = "second line";
63 char File1
[4] = "a.c";
64 char File2
[4] = "b.c";
68 Header
.Magic
= BTF::MAGIC
;
70 Header
.HdrLen
= sizeof(Header
);
71 Header
.StrOff
= offsetof(B
, Strings
) - sizeof(Header
);
72 Header
.StrLen
= sizeof(Strings
);
77 BTF::ExtHeader Header
= {};
80 uint32_t LineRecSize
= sizeof(BTF::BPFLineInfo
);
82 BTF::SecLineInfo Sec
= {offsetof(B::S
, Foo
), 2};
83 BTF::BPFLineInfo Lines
[2] = {
84 {16, offsetof(B::S
, File1
), offsetof(B::S
, Line1
), LC(7, 1)},
85 {32, offsetof(B::S
, File1
), offsetof(B::S
, Line2
), LC(14, 5)},
89 BTF::SecLineInfo Sec
= {offsetof(B::S
, Bar
), 1};
90 BTF::BPFLineInfo Lines
[1] = {
91 {0, offsetof(B::S
, File2
), offsetof(B::S
, Line1
), LC(42, 4)},
97 Header
.Magic
= BTF::MAGIC
;
99 Header
.HdrLen
= sizeof(Header
);
100 Header
.LineInfoOff
= offsetof(E
, Lines
) - sizeof(Header
);
101 Header
.LineInfoLen
= sizeof(Lines
);
106 int BTFSectionLen
= sizeof(BTF
);
107 int ExtSectionLen
= sizeof(Ext
);
109 SmallString
<0> Storage
;
110 std::unique_ptr
<ObjectFile
> Obj
;
112 ObjectFile
&makeObj() {
114 raw_string_ostream
Yaml(Buffer
);
119 if (sys::IsBigEndianHost
)
120 Yaml
<< "\n Data: ELFDATA2MSB";
122 Yaml
<< "\n Data: ELFDATA2LSB";
134 if (BTFSectionLen
>= 0)
139 << makeBinRef(&BTF
, BTFSectionLen
);
141 if (ExtSectionLen
>= 0)
146 << makeBinRef(&Ext
, ExtSectionLen
);
148 Obj
= yaml::yaml2ObjectFile(Storage
, Buffer
,
149 [](const Twine
&Err
) { errs() << Err
; });
154 TEST(BTFParserTest
, simpleCorrectInput
) {
157 Error Err
= BTF
.parse(Mock
.makeObj());
160 EXPECT_EQ(BTF
.findString(offsetof(MockData1::B::S
, Foo
)), "foo");
161 EXPECT_EQ(BTF
.findString(offsetof(MockData1::B::S
, Bar
)), "bar");
162 EXPECT_EQ(BTF
.findString(offsetof(MockData1::B::S
, Line1
)), "first line");
163 EXPECT_EQ(BTF
.findString(offsetof(MockData1::B::S
, Line2
)), "second line");
164 EXPECT_EQ(BTF
.findString(offsetof(MockData1::B::S
, File1
)), "a.c");
165 EXPECT_EQ(BTF
.findString(offsetof(MockData1::B::S
, File2
)), "b.c");
168 EXPECT_EQ(BTF
.findString(sizeof(MockData1::B::S
)), StringRef());
170 const BTF::BPFLineInfo
*I1
= BTF
.findLineInfo({16, 1});
172 EXPECT_EQ(I1
->getLine(), 7u);
173 EXPECT_EQ(I1
->getCol(), 1u);
174 EXPECT_EQ(BTF
.findString(I1
->FileNameOff
), "a.c");
175 EXPECT_EQ(BTF
.findString(I1
->LineOff
), "first line");
177 const BTF::BPFLineInfo
*I2
= BTF
.findLineInfo({32, 1});
179 EXPECT_EQ(I2
->getLine(), 14u);
180 EXPECT_EQ(I2
->getCol(), 5u);
181 EXPECT_EQ(BTF
.findString(I2
->FileNameOff
), "a.c");
182 EXPECT_EQ(BTF
.findString(I2
->LineOff
), "second line");
184 const BTF::BPFLineInfo
*I3
= BTF
.findLineInfo({0, 2});
186 EXPECT_EQ(I3
->getLine(), 42u);
187 EXPECT_EQ(I3
->getCol(), 4u);
188 EXPECT_EQ(BTF
.findString(I3
->FileNameOff
), "b.c");
189 EXPECT_EQ(BTF
.findString(I3
->LineOff
), "first line");
191 // No info for insn address.
192 EXPECT_FALSE(BTF
.findLineInfo({24, 1}));
193 EXPECT_FALSE(BTF
.findLineInfo({8, 2}));
194 // No info for section number.
195 EXPECT_FALSE(BTF
.findLineInfo({16, 3}));
198 TEST(BTFParserTest
, badSectionNameOffset
) {
201 // "foo" is section #1, corrupting it's name offset will make impossible
202 // to match section name with section index when BTF is parsed.
203 Mock
.Ext
.Lines
.Foo
.Sec
.SecNameOff
= 100500;
204 Error Err
= BTF
.parse(Mock
.makeObj());
206 // "foo" line info should be corrupted.
207 EXPECT_FALSE(BTF
.findLineInfo({16, 1}));
208 // "bar" line info should be ok.
209 EXPECT_TRUE(BTF
.findLineInfo({0, 2}));
212 // Keep this as macro to preserve line number info.
213 #define EXPECT_PARSE_ERROR(Mock, Message) \
216 EXPECT_THAT_ERROR(BTF.parse((Mock).makeObj()), \
217 FailedWithMessage(testing::HasSubstr(Message))); \
220 TEST(BTFParserTest
, badBTFMagic
) {
222 Mock
.BTF
.Header
.Magic
= 42;
223 EXPECT_PARSE_ERROR(Mock
, "invalid .BTF magic: 2a");
226 TEST(BTFParserTest
, badBTFVersion
) {
228 Mock
.BTF
.Header
.Version
= 42;
229 EXPECT_PARSE_ERROR(Mock
, "unsupported .BTF version: 42");
232 TEST(BTFParserTest
, badBTFHdrLen
) {
234 Mock
.BTF
.Header
.HdrLen
= 5;
235 EXPECT_PARSE_ERROR(Mock
, "unexpected .BTF header length: 5");
238 TEST(BTFParserTest
, badBTFSectionLen
) {
239 MockData1 Mock1
, Mock2
;
241 // Cut-off string section by one byte.
242 Mock1
.BTFSectionLen
=
243 offsetof(MockData1::B
, Strings
) + sizeof(MockData1::B::S
) - 1;
244 EXPECT_PARSE_ERROR(Mock1
, "invalid .BTF section size");
247 Mock2
.BTFSectionLen
= offsetof(BTF::Header
, StrOff
);
248 EXPECT_PARSE_ERROR(Mock2
, BTFEndOfData
);
251 TEST(BTFParserTest
, badBTFExtMagic
) {
253 Mock
.Ext
.Header
.Magic
= 42;
254 EXPECT_PARSE_ERROR(Mock
, "invalid .BTF.ext magic: 2a");
257 TEST(BTFParserTest
, badBTFExtVersion
) {
259 Mock
.Ext
.Header
.Version
= 42;
260 EXPECT_PARSE_ERROR(Mock
, "unsupported .BTF.ext version: 42");
263 TEST(BTFParserTest
, badBTFExtHdrLen
) {
264 MockData1 Mock1
, Mock2
;
266 Mock1
.Ext
.Header
.HdrLen
= 5;
267 EXPECT_PARSE_ERROR(Mock1
, "unexpected .BTF.ext header length: 5");
269 Mock2
.Ext
.Header
.HdrLen
= sizeof(Mock2
.Ext
);
270 EXPECT_PARSE_ERROR(Mock2
, BTFExtEndOfData
);
273 TEST(BTFParserTest
, badBTFExtSectionLen
) {
274 MockData1 Mock1
, Mock2
, Mock3
;
276 // Cut-off header before HdrLen.
277 Mock1
.ExtSectionLen
= offsetof(BTF::ExtHeader
, HdrLen
);
278 EXPECT_PARSE_ERROR(Mock1
, BTFExtEndOfData
);
280 // Cut-off header before LineInfoLen.
281 Mock2
.ExtSectionLen
= offsetof(BTF::ExtHeader
, LineInfoLen
);
282 EXPECT_PARSE_ERROR(Mock2
, BTFExtEndOfData
);
284 // Cut-off line-info section somewhere in the middle.
285 Mock3
.ExtSectionLen
= offsetof(MockData1::E
, Lines
) + 4;
286 EXPECT_PARSE_ERROR(Mock3
, BTFExtEndOfData
);
289 TEST(BTFParserTest
, badBTFExtLineInfoRecSize
) {
290 MockData1 Mock1
, Mock2
;
292 Mock1
.Ext
.Lines
.LineRecSize
= 2;
293 EXPECT_PARSE_ERROR(Mock1
, "unexpected .BTF.ext line info record length: 2");
295 Mock2
.Ext
.Lines
.LineRecSize
= sizeof(Mock2
.Ext
.Lines
.Foo
.Lines
[0]) + 1;
296 EXPECT_PARSE_ERROR(Mock2
, BTFExtEndOfData
);
299 TEST(BTFParserTest
, badBTFExtLineSectionName
) {
302 Mock1
.Ext
.Lines
.Foo
.Sec
.SecNameOff
= offsetof(MockData1::B::S
, Buz
);
304 Mock1
, "can't find section 'buz' while parsing .BTF.ext line info");
307 TEST(BTFParserTest
, missingSections
) {
308 MockData1 Mock1
, Mock2
, Mock3
;
310 Mock1
.BTFSectionLen
= -1;
311 EXPECT_PARSE_ERROR(Mock1
, "can't find .BTF section");
312 EXPECT_FALSE(BTFParser::hasBTFSections(Mock1
.makeObj()));
314 Mock2
.ExtSectionLen
= -1;
315 EXPECT_PARSE_ERROR(Mock2
, "can't find .BTF.ext section");
316 EXPECT_FALSE(BTFParser::hasBTFSections(Mock2
.makeObj()));
318 EXPECT_TRUE(BTFParser::hasBTFSections(Mock3
.makeObj()));
321 // Check that BTFParser instance is reset when BTFParser::parse() is
322 // called several times.
323 TEST(BTFParserTest
, parserReset
) {
325 MockData1 Mock1
, Mock2
;
327 EXPECT_FALSE(BTF
.parse(Mock1
.makeObj()));
328 EXPECT_TRUE(BTF
.findLineInfo({16, 1}));
329 EXPECT_TRUE(BTF
.findLineInfo({0, 2}));
331 // Break the reference to "bar" section name, thus making
332 // information about "bar" line numbers unavailable.
333 Mock2
.Ext
.Lines
.Bar
.Sec
.SecNameOff
= 100500;
335 EXPECT_FALSE(BTF
.parse(Mock2
.makeObj()));
336 EXPECT_TRUE(BTF
.findLineInfo({16, 1}));
337 // Make sure that "bar" no longer available (its index is 2).
338 EXPECT_FALSE(BTF
.findLineInfo({0, 2}));
341 TEST(BTFParserTest
, btfContext
) {
344 std::unique_ptr
<BTFContext
> Ctx
= BTFContext::create(Mock
.makeObj());
346 DILineInfo I1
= Ctx
->getLineInfoForAddress({16, 1});
347 EXPECT_EQ(I1
.Line
, 7u);
348 EXPECT_EQ(I1
.Column
, 1u);
349 EXPECT_EQ(I1
.FileName
, "a.c");
350 EXPECT_EQ(I1
.LineSource
, "first line");
352 DILineInfo I2
= Ctx
->getLineInfoForAddress({24, 1});
353 EXPECT_EQ(I2
.Line
, 0u);
354 EXPECT_EQ(I2
.Column
, 0u);
355 EXPECT_EQ(I2
.FileName
, DILineInfo::BadString
);
356 EXPECT_EQ(I2
.LineSource
, std::nullopt
);
359 static uint32_t mkInfo(uint32_t Kind
) { return Kind
<< 24; }
361 template <typename T
> static void append(std::string
&S
, const T
&What
) {
362 S
.append((const char *)&What
, sizeof(What
));
366 SmallString
<0> ObjStorage
;
367 std::unique_ptr
<ObjectFile
> Obj
;
379 MockData2() { reset(); }
381 unsigned totalTypes() const { return TotalTypes
; }
383 uint32_t addString(StringRef S
) {
384 uint32_t Off
= Strings
.size();
385 Strings
.append(S
.data(), S
.size());
386 Strings
.append("\0", 1);
390 uint32_t addType(const BTF::CommonType
&Tp
) {
395 template <typename T
> void addTail(const T
&Tp
) { append(Types
, Tp
); }
409 LastRelocSecIdx
= -1;
415 void finishRelocSec() {
416 if (LastRelocSecIdx
== -1)
419 BTF::SecFieldReloc
*SecInfo
=
420 (BTF::SecFieldReloc
*)&Relocs
[LastRelocSecIdx
];
421 SecInfo
->NumFieldReloc
= NumRelocs
;
422 LastRelocSecIdx
= -1;
426 void finishLineSec() {
427 if (LastLineSecIdx
== -1)
430 BTF::SecLineInfo
*SecInfo
= (BTF::SecLineInfo
*)&Lines
[LastLineSecIdx
];
431 SecInfo
->NumLineInfo
= NumLines
;
436 void addRelocSec(const BTF::SecFieldReloc
&R
) {
438 LastRelocSecIdx
= Relocs
.size();
442 void addReloc(const BTF::BPFFieldReloc
&R
) {
447 void addLinesSec(const BTF::SecLineInfo
&R
) {
449 LastLineSecIdx
= Lines
.size();
453 void addLine(const BTF::BPFLineInfo
&R
) {
458 ObjectFile
&makeObj() {
462 BTF::Header BTFHeader
= {};
463 BTFHeader
.Magic
= BTF::MAGIC
;
464 BTFHeader
.Version
= 1;
465 BTFHeader
.HdrLen
= sizeof(BTFHeader
);
466 BTFHeader
.StrOff
= 0;
467 BTFHeader
.StrLen
= Strings
.size();
468 BTFHeader
.TypeOff
= Strings
.size();
469 BTFHeader
.TypeLen
= Types
.size();
472 append(BTFSec
, BTFHeader
);
473 BTFSec
.append(Strings
);
474 BTFSec
.append(Types
);
476 BTF::ExtHeader ExtHeader
= {};
477 ExtHeader
.Magic
= BTF::MAGIC
;
478 ExtHeader
.Version
= 1;
479 ExtHeader
.HdrLen
= sizeof(ExtHeader
);
480 ExtHeader
.FieldRelocOff
= 0;
481 ExtHeader
.FieldRelocLen
= Relocs
.size() + sizeof(uint32_t);
482 ExtHeader
.LineInfoOff
= ExtHeader
.FieldRelocLen
;
483 ExtHeader
.LineInfoLen
= Lines
.size() + sizeof(uint32_t);
486 append(ExtSec
, ExtHeader
);
487 append(ExtSec
, (uint32_t)sizeof(BTF::BPFFieldReloc
));
488 ExtSec
.append(Relocs
);
489 append(ExtSec
, (uint32_t)sizeof(BTF::BPFLineInfo
));
490 ExtSec
.append(Lines
);
492 std::string YamlBuffer
;
493 raw_string_ostream
Yaml(YamlBuffer
);
498 if (sys::IsBigEndianHost
)
499 Yaml
<< "\n Data: ELFDATA2MSB";
501 Yaml
<< "\n Data: ELFDATA2LSB";
515 << makeBinRef(BTFSec
.data(), BTFSec
.size());
520 << makeBinRef(ExtSec
.data(), ExtSec
.size());
522 Obj
= yaml::yaml2ObjectFile(ObjStorage
, YamlBuffer
,
523 [](const Twine
&Err
) { errs() << Err
; });
528 TEST(BTFParserTest
, allTypeKinds
) {
530 D
.addType({D
.addString("1"), mkInfo(BTF::BTF_KIND_INT
), {4}});
531 D
.addTail((uint32_t)0);
532 D
.addType({D
.addString("2"), mkInfo(BTF::BTF_KIND_PTR
), {1}});
533 D
.addType({D
.addString("3"), mkInfo(BTF::BTF_KIND_ARRAY
), {0}});
534 D
.addTail(BTF::BTFArray({1, 1, 2}));
535 D
.addType({D
.addString("4"), mkInfo(BTF::BTF_KIND_STRUCT
) | 2, {8}});
536 D
.addTail(BTF::BTFMember({D
.addString("a"), 1, 0}));
537 D
.addTail(BTF::BTFMember({D
.addString("b"), 1, 0}));
538 D
.addType({D
.addString("5"), mkInfo(BTF::BTF_KIND_UNION
) | 3, {8}});
539 D
.addTail(BTF::BTFMember({D
.addString("a"), 1, 0}));
540 D
.addTail(BTF::BTFMember({D
.addString("b"), 1, 0}));
541 D
.addTail(BTF::BTFMember({D
.addString("c"), 1, 0}));
542 D
.addType({D
.addString("6"), mkInfo(BTF::BTF_KIND_ENUM
) | 2, {4}});
543 D
.addTail(BTF::BTFEnum({D
.addString("U"), 1}));
544 D
.addTail(BTF::BTFEnum({D
.addString("V"), 2}));
545 D
.addType({D
.addString("7"), mkInfo(BTF::BTF_KIND_ENUM64
) | 1, {4}});
546 D
.addTail(BTF::BTFEnum64({D
.addString("W"), 0, 1}));
548 {D
.addString("8"), BTF::FWD_UNION_FLAG
| mkInfo(BTF::BTF_KIND_FWD
), {0}});
549 D
.addType({D
.addString("9"), mkInfo(BTF::BTF_KIND_TYPEDEF
), {1}});
550 D
.addType({D
.addString("10"), mkInfo(BTF::BTF_KIND_VOLATILE
), {1}});
551 D
.addType({D
.addString("11"), mkInfo(BTF::BTF_KIND_CONST
), {1}});
552 D
.addType({D
.addString("12"), mkInfo(BTF::BTF_KIND_RESTRICT
), {1}});
553 D
.addType({D
.addString("13"), mkInfo(BTF::BTF_KIND_FUNC_PROTO
) | 1, {1}});
554 D
.addTail(BTF::BTFParam({D
.addString("P"), 2}));
555 D
.addType({D
.addString("14"), mkInfo(BTF::BTF_KIND_FUNC
), {13}});
556 D
.addType({D
.addString("15"), mkInfo(BTF::BTF_KIND_VAR
), {2}});
557 D
.addTail((uint32_t)0);
558 D
.addType({D
.addString("16"), mkInfo(BTF::BTF_KIND_DATASEC
) | 3, {0}});
559 D
.addTail(BTF::BTFDataSec({1, 0, 4}));
560 D
.addTail(BTF::BTFDataSec({1, 4, 4}));
561 D
.addTail(BTF::BTFDataSec({1, 8, 4}));
562 D
.addType({D
.addString("17"), mkInfo(BTF::BTF_KIND_FLOAT
), {4}});
563 D
.addType({D
.addString("18"), mkInfo(BTF::BTF_KIND_DECL_TAG
), {0}});
564 D
.addTail((uint32_t)-1);
565 D
.addType({D
.addString("19"), mkInfo(BTF::BTF_KIND_TYPE_TAG
), {0}});
568 Error Err
= BTF
.parse(D
.makeObj());
571 EXPECT_EQ(D
.totalTypes() + 1 /* +1 for void */, BTF
.typesCount());
572 for (unsigned Id
= 1; Id
< D
.totalTypes() + 1; ++Id
) {
573 const BTF::CommonType
*Tp
= BTF
.findType(Id
);
576 raw_string_ostream
IdBufStream(IdBuf
);
578 EXPECT_EQ(BTF
.findString(Tp
->NameOff
), IdBuf
);
582 TEST(BTFParserTest
, bigStruct
) {
583 const uint32_t N
= 1000u;
585 uint32_t FStr
= D
.addString("f");
586 D
.addType({D
.addString("foo"), mkInfo(BTF::BTF_KIND_INT
), {4}});
587 D
.addTail((uint32_t)0);
588 D
.addType({D
.addString("big"), mkInfo(BTF::BTF_KIND_STRUCT
) | N
, {8}});
589 for (unsigned I
= 0; I
< N
; ++I
)
590 D
.addTail(BTF::BTFMember({FStr
, 1, 0}));
591 D
.addType({D
.addString("bar"), mkInfo(BTF::BTF_KIND_INT
), {4}});
592 D
.addTail((uint32_t)0);
595 ASSERT_SUCCEEDED(BTF
.parse(D
.makeObj()));
596 ASSERT_EQ(BTF
.typesCount(), 4u /* +1 for void */);
597 const BTF::CommonType
*Foo
= BTF
.findType(1);
598 const BTF::CommonType
*Big
= BTF
.findType(2);
599 const BTF::CommonType
*Bar
= BTF
.findType(3);
603 EXPECT_EQ(BTF
.findString(Foo
->NameOff
), "foo");
604 EXPECT_EQ(BTF
.findString(Big
->NameOff
), "big");
605 EXPECT_EQ(BTF
.findString(Bar
->NameOff
), "bar");
606 EXPECT_EQ(Big
->getVlen(), N
);
609 TEST(BTFParserTest
, incompleteTypes
) {
611 auto IncompleteType
= [&](const BTF::CommonType
&Tp
) {
614 EXPECT_PARSE_ERROR(D
, "incomplete type definition in .BTF section");
617 // All kinds that need tail.
618 IncompleteType({D
.addString("a"), mkInfo(BTF::BTF_KIND_INT
), {4}});
619 IncompleteType({D
.addString("b"), mkInfo(BTF::BTF_KIND_ARRAY
), {0}});
620 IncompleteType({D
.addString("c"), mkInfo(BTF::BTF_KIND_VAR
), {0}});
621 IncompleteType({D
.addString("d"), mkInfo(BTF::BTF_KIND_DECL_TAG
), {0}});
623 // All kinds with vlen.
624 IncompleteType({D
.addString("a"), mkInfo(BTF::BTF_KIND_STRUCT
) | 2, {8}});
625 IncompleteType({D
.addString("b"), mkInfo(BTF::BTF_KIND_UNION
) | 3, {8}});
626 IncompleteType({D
.addString("c"), mkInfo(BTF::BTF_KIND_ENUM
) | 2, {4}});
627 IncompleteType({D
.addString("d"), mkInfo(BTF::BTF_KIND_ENUM64
) | 1, {4}});
628 IncompleteType({D
.addString("e"), mkInfo(BTF::BTF_KIND_FUNC_PROTO
) | 1, {1}});
629 IncompleteType({D
.addString("f"), mkInfo(BTF::BTF_KIND_DATASEC
) | 3, {0}});
631 // An unexpected tail.
633 D
.addTail((uint32_t)0);
634 EXPECT_PARSE_ERROR(D
, "incomplete type definition in .BTF section");
637 // Use macro to preserve line number in error message.
638 #define SYMBOLIZE(SecAddr, Expected) \
640 const BTF::BPFFieldReloc *R = BTF.findFieldReloc((SecAddr)); \
642 SmallString<64> Symbolized; \
643 BTF.symbolize(R, Symbolized); \
644 EXPECT_EQ(Symbolized, (Expected)); \
647 // Shorter name for initializers below.
648 using SA
= SectionedAddress
;
650 TEST(BTFParserTest
, typeRelocs
) {
652 uint32_t Zero
= D
.addString("0");
653 // id 1: struct foo {}
656 D
.addType({D
.addString("foo"), mkInfo(BTF::BTF_KIND_STRUCT
), {0}});
657 D
.addType({D
.addString("bar"),
658 mkInfo(BTF::BTF_KIND_FWD
) | BTF::FWD_UNION_FLAG
,
660 D
.addType({D
.addString("buz"), mkInfo(BTF::BTF_KIND_FWD
), {0}});
661 D
.addRelocSec({D
.addString("foo"), 7});
662 // List of all possible correct type relocations for type id #1.
663 D
.addReloc({0, 1, Zero
, BTF::BTF_TYPE_ID_LOCAL
});
664 D
.addReloc({8, 1, Zero
, BTF::BTF_TYPE_ID_REMOTE
});
665 D
.addReloc({16, 1, Zero
, BTF::TYPE_EXISTENCE
});
666 D
.addReloc({24, 1, Zero
, BTF::TYPE_MATCH
});
667 D
.addReloc({32, 1, Zero
, BTF::TYPE_SIZE
});
668 // Forward declarations.
669 D
.addReloc({40, 2, Zero
, BTF::TYPE_SIZE
});
670 D
.addReloc({48, 3, Zero
, BTF::TYPE_SIZE
});
671 // Incorrect type relocation: bad type id.
672 D
.addReloc({56, 42, Zero
, BTF::TYPE_SIZE
});
673 // Incorrect type relocation: spec should be '0'.
674 D
.addReloc({64, 1, D
.addString("10"), BTF::TYPE_SIZE
});
677 Error E
= BTF
.parse(D
.makeObj());
680 SYMBOLIZE(SA({0, 1}), "<local_type_id> [1] struct foo");
681 SYMBOLIZE(SA({8, 1}), "<target_type_id> [1] struct foo");
682 SYMBOLIZE(SA({16, 1}), "<type_exists> [1] struct foo");
683 SYMBOLIZE(SA({24, 1}), "<type_matches> [1] struct foo");
684 SYMBOLIZE(SA({32, 1}), "<type_size> [1] struct foo");
685 SYMBOLIZE(SA({40, 1}), "<type_size> [2] fwd union bar");
686 SYMBOLIZE(SA({48, 1}), "<type_size> [3] fwd struct buz");
687 SYMBOLIZE(SA({56, 1}), "<type_size> [42] '0' <unknown type id: 42>");
688 SYMBOLIZE(SA({64, 1}),
689 "<type_size> [1] '10' "
690 "<unexpected type-based relocation spec: should be '0'>");
693 TEST(BTFParserTest
, enumRelocs
) {
695 // id 1: enum { U, V }
696 D
.addType({D
.addString("foo"), mkInfo(BTF::BTF_KIND_ENUM
) | 2, {4}});
697 D
.addTail(BTF::BTFEnum({D
.addString("U"), 1}));
698 D
.addTail(BTF::BTFEnum({D
.addString("V"), 2}));
700 D
.addType({D
.addString("int"), mkInfo(BTF::BTF_KIND_INT
), {4}});
701 D
.addTail((uint32_t)0);
702 // id 3: enum: uint64_t { A, B }
703 D
.addType({D
.addString("bar"), mkInfo(BTF::BTF_KIND_ENUM64
) | 2, {8}});
704 D
.addTail(BTF::BTFEnum64({D
.addString("A"), 1, 0}));
705 D
.addTail(BTF::BTFEnum64({D
.addString("B"), 2, 0}));
707 D
.addRelocSec({D
.addString("foo"), 5});
708 // An ok relocation accessing value #1: U.
709 D
.addReloc({0, 1, D
.addString("0"), BTF::ENUM_VALUE_EXISTENCE
});
710 // An ok relocation accessing value #2: V.
711 D
.addReloc({8, 1, D
.addString("1"), BTF::ENUM_VALUE
});
712 // Incorrect relocation: too many elements in string "1:0".
713 D
.addReloc({16, 1, D
.addString("1:0"), BTF::ENUM_VALUE
});
714 // Incorrect relocation: type id "2" is not an enum.
715 D
.addReloc({24, 2, D
.addString("1"), BTF::ENUM_VALUE
});
716 // Incorrect relocation: value #42 does not exist for enum "foo".
717 D
.addReloc({32, 1, D
.addString("42"), BTF::ENUM_VALUE
});
718 // An ok relocation accessing value #1: A.
719 D
.addReloc({40, 3, D
.addString("0"), BTF::ENUM_VALUE_EXISTENCE
});
720 // An ok relocation accessing value #2: B.
721 D
.addReloc({48, 3, D
.addString("1"), BTF::ENUM_VALUE
});
724 Error E
= BTF
.parse(D
.makeObj());
727 SYMBOLIZE(SA({0, 1}), "<enumval_exists> [1] enum foo::U = 1");
728 SYMBOLIZE(SA({8, 1}), "<enumval_value> [1] enum foo::V = 2");
731 "<enumval_value> [1] '1:0' <unexpected enumval relocation spec size>");
734 "<enumval_value> [2] '1' <unexpected type kind for enum relocation: 1>");
735 SYMBOLIZE(SA({32, 1}), "<enumval_value> [1] '42' <bad value index: 42>");
736 SYMBOLIZE(SA({40, 1}), "<enumval_exists> [3] enum bar::A = 1");
737 SYMBOLIZE(SA({48, 1}), "<enumval_value> [3] enum bar::B = 2");
740 TEST(BTFParserTest
, enumRelocsMods
) {
742 // id 1: enum { U, V }
743 D
.addType({D
.addString("foo"), mkInfo(BTF::BTF_KIND_ENUM
) | 2, {4}});
744 D
.addTail(BTF::BTFEnum({D
.addString("U"), 1}));
745 D
.addTail(BTF::BTFEnum({D
.addString("V"), 2}));
746 // id 2: typedef enum foo a;
747 D
.addType({D
.addString("a"), mkInfo(BTF::BTF_KIND_TYPEDEF
), {1}});
748 // id 3: const enum foo;
749 D
.addType({D
.addString(""), mkInfo(BTF::BTF_KIND_CONST
), {1}});
751 D
.addRelocSec({D
.addString("foo"), 0});
752 D
.addReloc({0, 2, D
.addString("0"), BTF::ENUM_VALUE
});
753 D
.addReloc({8, 3, D
.addString("1"), BTF::ENUM_VALUE
});
756 Error E
= BTF
.parse(D
.makeObj());
759 SYMBOLIZE(SA({0, 1}), "<enumval_value> [2] typedef a::U = 1");
760 SYMBOLIZE(SA({8, 1}), "<enumval_value> [3] const enum foo::V = 2");
763 TEST(BTFParserTest
, fieldRelocs
) {
766 D
.addType({D
.addString("int"), mkInfo(BTF::BTF_KIND_INT
), {4}});
767 D
.addTail((uint32_t)0);
768 // id 2: struct foo { int a; int b; }
769 D
.addType({D
.addString("foo"), mkInfo(BTF::BTF_KIND_STRUCT
) | 2, {8}});
770 D
.addTail(BTF::BTFMember({D
.addString("a"), 1, 0}));
771 D
.addTail(BTF::BTFMember({D
.addString("b"), 1, 0}));
772 // id 3: array of struct foo.
773 D
.addType({D
.addString(""), mkInfo(BTF::BTF_KIND_ARRAY
), {0}});
774 D
.addTail(BTF::BTFArray({2, 1, 2}));
775 // id 4: struct bar { struct foo u[2]; int v; }
776 D
.addType({D
.addString("bar"), mkInfo(BTF::BTF_KIND_STRUCT
) | 2, {8}});
777 D
.addTail(BTF::BTFMember({D
.addString("u"), 3, 0}));
778 D
.addTail(BTF::BTFMember({D
.addString("v"), 1, 0}));
779 // id 5: array with bad element type id.
780 D
.addType({D
.addString(""), mkInfo(BTF::BTF_KIND_ARRAY
), {0}});
781 D
.addTail(BTF::BTFArray({42, 1, 2}));
782 // id 6: struct buz { <bad type> u[2]; <bad type> v; }
783 D
.addType({D
.addString("bar"), mkInfo(BTF::BTF_KIND_STRUCT
) | 2, {8}});
784 D
.addTail(BTF::BTFMember({D
.addString("u"), 5, 0}));
785 D
.addTail(BTF::BTFMember({D
.addString("v"), 42, 0}));
787 D
.addRelocSec({D
.addString("foo"), 0 /* patched automatically */});
788 // All field relocations kinds for struct bar::v.
789 D
.addReloc({0, 4, D
.addString("0:1"), BTF::FIELD_BYTE_OFFSET
});
790 D
.addReloc({8, 4, D
.addString("0:1"), BTF::FIELD_BYTE_SIZE
});
791 D
.addReloc({16, 4, D
.addString("0:1"), BTF::FIELD_EXISTENCE
});
792 D
.addReloc({24, 4, D
.addString("0:1"), BTF::FIELD_SIGNEDNESS
});
793 D
.addReloc({32, 4, D
.addString("0:1"), BTF::FIELD_LSHIFT_U64
});
794 D
.addReloc({40, 4, D
.addString("0:1"), BTF::FIELD_RSHIFT_U64
});
795 // Non-zero first idx.
796 D
.addReloc({48, 4, D
.addString("7:1"), BTF::FIELD_BYTE_OFFSET
});
797 // Access through array and struct: struct bar::u[1].a.
798 D
.addReloc({56, 4, D
.addString("0:0:1:0"), BTF::FIELD_BYTE_OFFSET
});
799 // Access through array and struct: struct bar::u[1].b.
800 D
.addReloc({64, 4, D
.addString("0:0:1:1"), BTF::FIELD_BYTE_OFFSET
});
801 // Incorrect relocation: empty access string.
802 D
.addReloc({72, 4, D
.addString(""), BTF::FIELD_BYTE_OFFSET
});
803 // Incorrect relocation: member index out of range (only two members in bar).
804 D
.addReloc({80, 4, D
.addString("0:2"), BTF::FIELD_BYTE_OFFSET
});
805 // Incorrect relocation: unknown element type id (buz::u[0] access).
806 D
.addReloc({88, 6, D
.addString("0:0:0"), BTF::FIELD_BYTE_OFFSET
});
807 // Incorrect relocation: unknown member type id (buz::v access).
808 D
.addReloc({96, 6, D
.addString("0:1:0"), BTF::FIELD_BYTE_OFFSET
});
809 // Incorrect relocation: non structural type in the middle of access string
810 // struct bar::v.<something>.
811 D
.addReloc({104, 4, D
.addString("0:1:0"), BTF::FIELD_BYTE_OFFSET
});
814 Error E
= BTF
.parse(D
.makeObj());
817 SYMBOLIZE(SA({0, 1}), "<byte_off> [4] struct bar::v (0:1)");
818 SYMBOLIZE(SA({8, 1}), "<byte_sz> [4] struct bar::v (0:1)");
819 SYMBOLIZE(SA({16, 1}), "<field_exists> [4] struct bar::v (0:1)");
820 SYMBOLIZE(SA({24, 1}), "<signed> [4] struct bar::v (0:1)");
821 SYMBOLIZE(SA({32, 1}), "<lshift_u64> [4] struct bar::v (0:1)");
822 SYMBOLIZE(SA({40, 1}), "<rshift_u64> [4] struct bar::v (0:1)");
823 SYMBOLIZE(SA({48, 1}), "<byte_off> [4] struct bar::[7].v (7:1)");
824 SYMBOLIZE(SA({56, 1}), "<byte_off> [4] struct bar::u[1].a (0:0:1:0)");
825 SYMBOLIZE(SA({64, 1}), "<byte_off> [4] struct bar::u[1].b (0:0:1:1)");
826 SYMBOLIZE(SA({72, 1}), "<byte_off> [4] '' <field spec too short>");
827 SYMBOLIZE(SA({80, 1}),
828 "<byte_off> [4] '0:2' "
829 "<member index 2 for spec sub-string 1 is out of range>");
830 SYMBOLIZE(SA({88, 1}), "<byte_off> [6] '0:0:0' "
831 "<unknown element type id 42 for spec sub-string 2>");
832 SYMBOLIZE(SA({96, 1}), "<byte_off> [6] '0:1:0' "
833 "<unknown member type id 42 for spec sub-string 1>");
834 SYMBOLIZE(SA({104, 1}), "<byte_off> [4] '0:1:0' "
835 "<unexpected type kind 1 for spec sub-string 2>");
838 TEST(BTFParserTest
, fieldRelocsMods
) {
843 // typedef struct foo bar;
848 // const volatile restrict quux <some-var>;
850 D
.addType({D
.addString("int"), mkInfo(BTF::BTF_KIND_INT
), {4}});
851 D
.addTail((uint32_t)0);
853 D
.addType({D
.addString("foo"), mkInfo(BTF::BTF_KIND_STRUCT
) | 1, {4}});
854 D
.addTail(BTF::BTFMember({D
.addString("u"), Int
, 0}));
856 D
.addType({D
.addString("bar"), mkInfo(BTF::BTF_KIND_TYPEDEF
), {Foo
}});
858 D
.addType({D
.addString("bar"), mkInfo(BTF::BTF_KIND_CONST
), {Bar
}});
860 D
.addType({D
.addString("buz"), mkInfo(BTF::BTF_KIND_STRUCT
) | 1, {4}});
861 D
.addTail(BTF::BTFMember({D
.addString("v"), CBar
, 0}));
863 D
.addType({D
.addString("quux"), mkInfo(BTF::BTF_KIND_TYPEDEF
), {Buz
}});
865 D
.addType({D
.addString(""), mkInfo(BTF::BTF_KIND_RESTRICT
), {Quux
}});
867 D
.addType({D
.addString(""), mkInfo(BTF::BTF_KIND_VOLATILE
), {RQuux
}});
869 D
.addType({D
.addString(""), mkInfo(BTF::BTF_KIND_CONST
), {VRQuux
}});
871 D
.addType({D
.addString(""), mkInfo(BTF::BTF_KIND_CONST
), {77}});
873 D
.addType({D
.addString(""), mkInfo(BTF::BTF_KIND_VOLATILE
), {CUnknown
}});
875 D
.addRelocSec({D
.addString("foo"), 0});
876 D
.addReloc({0, Bar
, D
.addString("0:0"), BTF::FIELD_BYTE_OFFSET
});
877 D
.addReloc({8, CVRQuux
, D
.addString("0:0:0"), BTF::FIELD_BYTE_OFFSET
});
878 D
.addReloc({16, CVUnknown
, D
.addString("0:1:2"), BTF::FIELD_BYTE_OFFSET
});
881 Error E
= BTF
.parse(D
.makeObj());
884 // Should show modifiers / name of typedef.
885 SYMBOLIZE(SA({0, 1}), "<byte_off> [3] typedef bar::u (0:0)");
886 SYMBOLIZE(SA({8, 1}),
887 "<byte_off> [9] const volatile restrict typedef quux::v.u (0:0:0)");
888 SYMBOLIZE(SA({16, 1}),
889 "<byte_off> [11] '0:1:2' <unknown type id: 77 in modifiers chain>");
892 TEST(BTFParserTest
, relocTypeTagAndVoid
) {
894 // __attribute__((type_tag("tag"))) void
896 D
.addType({D
.addString("tag"), mkInfo(BTF::BTF_KIND_TYPE_TAG
), {0}});
898 D
.addRelocSec({D
.addString("foo"), 0});
899 D
.addReloc({0, Tag
, D
.addString("0"), BTF::TYPE_EXISTENCE
});
900 D
.addReloc({8, 0 /* void */, D
.addString("0"), BTF::TYPE_EXISTENCE
});
903 Error E
= BTF
.parse(D
.makeObj());
906 SYMBOLIZE(SA({0, 1}), "<type_exists> [1] type_tag(\"tag\") void");
907 SYMBOLIZE(SA({8, 1}), "<type_exists> [0] void");
910 TEST(BTFParserTest
, longRelocModifiersCycle
) {
914 {D
.addString(""), mkInfo(BTF::BTF_KIND_CONST
), {1 /* ourselves */}});
915 D
.addRelocSec({D
.addString("foo"), 0});
916 D
.addReloc({0, 1, D
.addString(""), BTF::TYPE_EXISTENCE
});
919 Error E
= BTF
.parse(D
.makeObj());
922 SYMBOLIZE(SA({0, 1}), "<type_exists> [1] '' <modifiers chain is too long>");
925 TEST(BTFParserTest
, relocAnonFieldsAndTypes
) {
932 D
.addType({D
.addString("int"), mkInfo(BTF::BTF_KIND_INT
), {4}});
933 D
.addTail((uint32_t)0);
935 D
.addType({D
.addString(""), mkInfo(BTF::BTF_KIND_STRUCT
) | 1, {4}});
936 D
.addTail(BTF::BTFMember({D
.addString(""), Int
, 0}));
938 D
.addRelocSec({D
.addString("foo"), 0});
939 D
.addReloc({0, Anon
, D
.addString("0"), BTF::TYPE_EXISTENCE
});
940 D
.addReloc({8, Anon
, D
.addString("0:0"), BTF::FIELD_BYTE_OFFSET
});
943 Error E
= BTF
.parse(D
.makeObj());
946 SYMBOLIZE(SA({0, 1}), "<type_exists> [2] struct <anon 2>");
947 SYMBOLIZE(SA({8, 1}), "<byte_off> [2] struct <anon 2>::<anon 0> (0:0)");
950 TEST(BTFParserTest
, miscBadRelos
) {
953 uint32_t S
= D
.addType({D
.addString("S"), mkInfo(BTF::BTF_KIND_STRUCT
), {0}});
955 D
.addRelocSec({D
.addString("foo"), 0});
956 D
.addReloc({0, 0, D
.addString(""), 777});
957 D
.addReloc({8, S
, D
.addString("abc"), BTF::FIELD_BYTE_OFFSET
});
958 D
.addReloc({16, S
, D
.addString("0#"), BTF::FIELD_BYTE_OFFSET
});
961 Error E
= BTF
.parse(D
.makeObj());
964 SYMBOLIZE(SA({0, 1}),
965 "<reloc kind #777> [0] '' <unknown relocation kind: 777>");
966 SYMBOLIZE(SA({8, 1}), "<byte_off> [1] 'abc' <spec string is not a number>");
967 SYMBOLIZE(SA({16, 1}),
968 "<byte_off> [1] '0#' <unexpected spec string delimiter: '#'>");
971 TEST(BTFParserTest
, relocsMultipleSections
) {
974 uint32_t S
= D
.addType({D
.addString("S"), mkInfo(BTF::BTF_KIND_STRUCT
), {0}});
975 uint32_t T
= D
.addType({D
.addString("T"), mkInfo(BTF::BTF_KIND_STRUCT
), {0}});
977 D
.addRelocSec({D
.addString("foo"), 0});
978 D
.addReloc({0, S
, D
.addString(""), BTF::TYPE_EXISTENCE
});
979 D
.addReloc({8, S
, D
.addString(""), BTF::TYPE_EXISTENCE
});
981 D
.addRelocSec({D
.addString("bar"), 0});
982 D
.addReloc({8, T
, D
.addString(""), BTF::TYPE_EXISTENCE
});
983 D
.addReloc({16, T
, D
.addString(""), BTF::TYPE_EXISTENCE
});
986 Error E
= BTF
.parse(D
.makeObj());
989 EXPECT_TRUE(BTF
.findFieldReloc({0, 1}));
990 EXPECT_TRUE(BTF
.findFieldReloc({8, 1}));
991 EXPECT_FALSE(BTF
.findFieldReloc({16, 1}));
993 EXPECT_FALSE(BTF
.findFieldReloc({0, 2}));
994 EXPECT_TRUE(BTF
.findFieldReloc({8, 2}));
995 EXPECT_TRUE(BTF
.findFieldReloc({16, 2}));
997 EXPECT_FALSE(BTF
.findFieldReloc({0, 3}));
998 EXPECT_FALSE(BTF
.findFieldReloc({8, 3}));
999 EXPECT_FALSE(BTF
.findFieldReloc({16, 3}));
1001 auto AssertReloType
= [&](const SectionedAddress
&A
, const char *Name
) {
1002 const BTF::BPFFieldReloc
*Relo
= BTF
.findFieldReloc(A
);
1004 const BTF::CommonType
*Type
= BTF
.findType(Relo
->TypeID
);
1006 EXPECT_EQ(BTF
.findString(Type
->NameOff
), Name
);
1009 AssertReloType({8, 1}, "S");
1010 AssertReloType({8, 2}, "T");
1013 TEST(BTFParserTest
, parserResetReloAndTypes
) {
1017 // First time: two types, two relocations.
1018 D
.addType({D
.addString("foo"), mkInfo(BTF::BTF_KIND_STRUCT
), {0}});
1019 D
.addType({D
.addString("bar"), mkInfo(BTF::BTF_KIND_STRUCT
), {0}});
1020 D
.addRelocSec({D
.addString("foo"), 0});
1021 D
.addReloc({0, 1, D
.addString(""), BTF::TYPE_EXISTENCE
});
1022 D
.addReloc({8, 2, D
.addString(""), BTF::TYPE_EXISTENCE
});
1024 Error E1
= BTF
.parse(D
.makeObj());
1027 ASSERT_TRUE(BTF
.findType(1));
1028 EXPECT_EQ(BTF
.findString(BTF
.findType(1)->NameOff
), "foo");
1029 EXPECT_TRUE(BTF
.findType(2));
1030 EXPECT_TRUE(BTF
.findFieldReloc({0, 1}));
1031 EXPECT_TRUE(BTF
.findFieldReloc({8, 1}));
1033 // Second time: one type, one relocation.
1035 D
.addType({D
.addString("buz"), mkInfo(BTF::BTF_KIND_STRUCT
), {0}});
1036 D
.addRelocSec({D
.addString("foo"), 0});
1037 D
.addReloc({0, 1, D
.addString(""), BTF::TYPE_EXISTENCE
});
1039 Error E2
= BTF
.parse(D
.makeObj());
1042 ASSERT_TRUE(BTF
.findType(1));
1043 EXPECT_EQ(BTF
.findString(BTF
.findType(1)->NameOff
), "buz");
1044 EXPECT_FALSE(BTF
.findType(2));
1045 EXPECT_TRUE(BTF
.findFieldReloc({0, 1}));
1046 EXPECT_FALSE(BTF
.findFieldReloc({8, 1}));
1049 TEST(BTFParserTest
, selectiveLoad
) {
1050 BTFParser BTF1
, BTF2
, BTF3
;
1053 D
.addType({D
.addString("foo"), mkInfo(BTF::BTF_KIND_STRUCT
), {0}});
1054 D
.addRelocSec({D
.addString("foo"), 0});
1055 D
.addReloc({0, 1, D
.addString(""), BTF::TYPE_EXISTENCE
});
1056 D
.addLinesSec({D
.addString("foo"), 0});
1057 D
.addLine({0, D
.addString("file.c"), D
.addString("some line"), LC(2, 3)});
1059 BTFParser::ParseOptions Opts
;
1061 ObjectFile
&Obj1
= D
.makeObj();
1063 Opts
.LoadLines
= true;
1064 ASSERT_SUCCEEDED(BTF1
.parse(Obj1
, Opts
));
1067 Opts
.LoadTypes
= true;
1068 ASSERT_SUCCEEDED(BTF2
.parse(Obj1
, Opts
));
1071 Opts
.LoadRelocs
= true;
1072 ASSERT_SUCCEEDED(BTF3
.parse(Obj1
, Opts
));
1074 EXPECT_TRUE(BTF1
.findLineInfo({0, 1}));
1075 EXPECT_FALSE(BTF2
.findLineInfo({0, 1}));
1076 EXPECT_FALSE(BTF3
.findLineInfo({0, 1}));
1078 EXPECT_FALSE(BTF1
.findType(1));
1079 EXPECT_TRUE(BTF2
.findType(1));
1080 EXPECT_FALSE(BTF3
.findType(1));
1082 EXPECT_FALSE(BTF1
.findFieldReloc({0, 1}));
1083 EXPECT_FALSE(BTF2
.findFieldReloc({0, 1}));
1084 EXPECT_TRUE(BTF3
.findFieldReloc({0, 1}));