Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / unittests / DebugInfo / BTF / BTFParserTest.cpp
blob7b4f7939e67830482455c885a5eed291f7f4488c
1 //===-- SourcePrinter.cpp - source interleaving utilities ----------------===//
2 //
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
6 //
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"
15 using namespace llvm;
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) {
27 Ref.writeAsHex(OS);
28 return OS;
31 template <typename T>
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));
36 namespace {
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
47 // input, etc.
49 struct MockData1 {
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.
53 #pragma pack(push, 1)
54 struct B {
55 BTF::Header Header = {};
56 // No types.
57 struct S {
58 char Foo[4] = "foo";
59 char Bar[4] = "bar";
60 char Buz[4] = "buz";
61 char Line1[11] = "first line";
62 char Line2[12] = "second line";
63 char File1[4] = "a.c";
64 char File2[4] = "b.c";
65 } Strings;
67 B() {
68 Header.Magic = BTF::MAGIC;
69 Header.Version = 1;
70 Header.HdrLen = sizeof(Header);
71 Header.StrOff = offsetof(B, Strings) - sizeof(Header);
72 Header.StrLen = sizeof(Strings);
74 } BTF;
76 struct E {
77 BTF::ExtHeader Header = {};
78 // No func info.
79 struct {
80 uint32_t LineRecSize = sizeof(BTF::BPFLineInfo);
81 struct {
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)},
87 } Foo;
88 struct {
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)},
93 } Bar;
94 } Lines;
96 E() {
97 Header.Magic = BTF::MAGIC;
98 Header.Version = 1;
99 Header.HdrLen = sizeof(Header);
100 Header.LineInfoOff = offsetof(E, Lines) - sizeof(Header);
101 Header.LineInfoLen = sizeof(Lines);
103 } Ext;
104 #pragma pack(pop)
106 int BTFSectionLen = sizeof(BTF);
107 int ExtSectionLen = sizeof(Ext);
109 SmallString<0> Storage;
110 std::unique_ptr<ObjectFile> Obj;
112 ObjectFile &makeObj() {
113 std::string Buffer;
114 raw_string_ostream Yaml(Buffer);
115 Yaml << R"(
116 !ELF
117 FileHeader:
118 Class: ELFCLASS64)";
119 if (sys::IsBigEndianHost)
120 Yaml << "\n Data: ELFDATA2MSB";
121 else
122 Yaml << "\n Data: ELFDATA2LSB";
123 Yaml << R"(
124 Type: ET_REL
125 Machine: EM_BPF
126 Sections:
127 - Name: foo
128 Type: SHT_PROGBITS
129 Size: 0x0
130 - Name: bar
131 Type: SHT_PROGBITS
132 Size: 0x0)";
134 if (BTFSectionLen >= 0)
135 Yaml << R"(
136 - Name: .BTF
137 Type: SHT_PROGBITS
138 Content: )"
139 << makeBinRef(&BTF, BTFSectionLen);
141 if (ExtSectionLen >= 0)
142 Yaml << R"(
143 - Name: .BTF.ext
144 Type: SHT_PROGBITS
145 Content: )"
146 << makeBinRef(&Ext, ExtSectionLen);
148 Obj = yaml::yaml2ObjectFile(Storage, Buffer,
149 [](const Twine &Err) { errs() << Err; });
150 return *Obj.get();
154 TEST(BTFParserTest, simpleCorrectInput) {
155 BTFParser BTF;
156 MockData1 Mock;
157 Error Err = BTF.parse(Mock.makeObj());
158 EXPECT_FALSE(Err);
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");
167 // Invalid offset.
168 EXPECT_EQ(BTF.findString(sizeof(MockData1::B::S)), StringRef());
170 const BTF::BPFLineInfo *I1 = BTF.findLineInfo({16, 1});
171 ASSERT_TRUE(I1);
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});
178 ASSERT_TRUE(I2);
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});
185 ASSERT_TRUE(I3);
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) {
199 BTFParser BTF;
200 MockData1 Mock;
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());
205 EXPECT_FALSE(Err);
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) \
214 do { \
215 BTFParser BTF; \
216 EXPECT_THAT_ERROR(BTF.parse((Mock).makeObj()), \
217 FailedWithMessage(testing::HasSubstr(Message))); \
218 } while (false)
220 TEST(BTFParserTest, badBTFMagic) {
221 MockData1 Mock;
222 Mock.BTF.Header.Magic = 42;
223 EXPECT_PARSE_ERROR(Mock, "invalid .BTF magic: 2a");
226 TEST(BTFParserTest, badBTFVersion) {
227 MockData1 Mock;
228 Mock.BTF.Header.Version = 42;
229 EXPECT_PARSE_ERROR(Mock, "unsupported .BTF version: 42");
232 TEST(BTFParserTest, badBTFHdrLen) {
233 MockData1 Mock;
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");
246 // Cut-off header.
247 Mock2.BTFSectionLen = offsetof(BTF::Header, StrOff);
248 EXPECT_PARSE_ERROR(Mock2, BTFEndOfData);
251 TEST(BTFParserTest, badBTFExtMagic) {
252 MockData1 Mock;
253 Mock.Ext.Header.Magic = 42;
254 EXPECT_PARSE_ERROR(Mock, "invalid .BTF.ext magic: 2a");
257 TEST(BTFParserTest, badBTFExtVersion) {
258 MockData1 Mock;
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) {
300 MockData1 Mock1;
302 Mock1.Ext.Lines.Foo.Sec.SecNameOff = offsetof(MockData1::B::S, Buz);
303 EXPECT_PARSE_ERROR(
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) {
324 BTFParser BTF;
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) {
342 MockData1 Mock;
343 BTFParser BTF;
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));
365 class MockData2 {
366 SmallString<0> ObjStorage;
367 std::unique_ptr<ObjectFile> Obj;
368 std::string Types;
369 std::string Strings;
370 std::string Relocs;
371 std::string Lines;
372 unsigned TotalTypes;
373 int LastRelocSecIdx;
374 unsigned NumRelocs;
375 int LastLineSecIdx;
376 unsigned NumLines;
378 public:
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);
387 return Off;
390 uint32_t addType(const BTF::CommonType &Tp) {
391 append(Types, Tp);
392 return ++TotalTypes;
395 template <typename T> void addTail(const T &Tp) { append(Types, Tp); }
397 void resetTypes() {
398 Types.resize(0);
399 TotalTypes = 0;
402 void reset() {
403 ObjStorage.clear();
404 Types.resize(0);
405 Strings.resize(0);
406 Relocs.resize(0);
407 Lines.resize(0);
408 TotalTypes = 0;
409 LastRelocSecIdx = -1;
410 NumRelocs = 0;
411 LastLineSecIdx = -1;
412 NumLines = 0;
415 void finishRelocSec() {
416 if (LastRelocSecIdx == -1)
417 return;
419 BTF::SecFieldReloc *SecInfo =
420 (BTF::SecFieldReloc *)&Relocs[LastRelocSecIdx];
421 SecInfo->NumFieldReloc = NumRelocs;
422 LastRelocSecIdx = -1;
423 NumRelocs = 0;
426 void finishLineSec() {
427 if (LastLineSecIdx == -1)
428 return;
430 BTF::SecLineInfo *SecInfo = (BTF::SecLineInfo *)&Lines[LastLineSecIdx];
431 SecInfo->NumLineInfo = NumLines;
432 NumLines = 0;
433 LastLineSecIdx = -1;
436 void addRelocSec(const BTF::SecFieldReloc &R) {
437 finishRelocSec();
438 LastRelocSecIdx = Relocs.size();
439 append(Relocs, R);
442 void addReloc(const BTF::BPFFieldReloc &R) {
443 append(Relocs, R);
444 ++NumRelocs;
447 void addLinesSec(const BTF::SecLineInfo &R) {
448 finishLineSec();
449 LastLineSecIdx = Lines.size();
450 append(Lines, R);
453 void addLine(const BTF::BPFLineInfo &R) {
454 append(Lines, R);
455 ++NumLines;
458 ObjectFile &makeObj() {
459 finishRelocSec();
460 finishLineSec();
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();
471 std::string BTFSec;
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);
485 std::string ExtSec;
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);
494 Yaml << R"(
495 !ELF
496 FileHeader:
497 Class: ELFCLASS64)";
498 if (sys::IsBigEndianHost)
499 Yaml << "\n Data: ELFDATA2MSB";
500 else
501 Yaml << "\n Data: ELFDATA2LSB";
502 Yaml << R"(
503 Type: ET_REL
504 Machine: EM_BPF
505 Sections:
506 - Name: foo
507 Type: SHT_PROGBITS
508 Size: 0x80
509 - Name: bar
510 Type: SHT_PROGBITS
511 Size: 0x80
512 - Name: .BTF
513 Type: SHT_PROGBITS
514 Content: )"
515 << makeBinRef(BTFSec.data(), BTFSec.size());
516 Yaml << R"(
517 - Name: .BTF.ext
518 Type: SHT_PROGBITS
519 Content: )"
520 << makeBinRef(ExtSec.data(), ExtSec.size());
522 Obj = yaml::yaml2ObjectFile(ObjStorage, YamlBuffer,
523 [](const Twine &Err) { errs() << Err; });
524 return *Obj.get();
528 TEST(BTFParserTest, allTypeKinds) {
529 MockData2 D;
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}));
547 D.addType(
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}});
567 BTFParser BTF;
568 Error Err = BTF.parse(D.makeObj());
569 EXPECT_FALSE(Err);
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);
574 ASSERT_TRUE(Tp);
575 std::string IdBuf;
576 raw_string_ostream IdBufStream(IdBuf);
577 IdBufStream << Id;
578 EXPECT_EQ(BTF.findString(Tp->NameOff), IdBuf);
582 TEST(BTFParserTest, bigStruct) {
583 const uint32_t N = 1000u;
584 MockData2 D;
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);
594 BTFParser BTF;
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);
600 ASSERT_TRUE(Foo);
601 ASSERT_TRUE(Big);
602 ASSERT_TRUE(Bar);
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) {
610 MockData2 D;
611 auto IncompleteType = [&](const BTF::CommonType &Tp) {
612 D.resetTypes();
613 D.addType(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.
632 D.resetTypes();
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) \
639 do { \
640 const BTF::BPFFieldReloc *R = BTF.findFieldReloc((SecAddr)); \
641 ASSERT_TRUE(R); \
642 SmallString<64> Symbolized; \
643 BTF.symbolize(R, Symbolized); \
644 EXPECT_EQ(Symbolized, (Expected)); \
645 } while (false)
647 // Shorter name for initializers below.
648 using SA = SectionedAddress;
650 TEST(BTFParserTest, typeRelocs) {
651 MockData2 D;
652 uint32_t Zero = D.addString("0");
653 // id 1: struct foo {}
654 // id 2: union bar;
655 // id 3: struct buz;
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,
659 {0}});
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});
676 BTFParser BTF;
677 Error E = BTF.parse(D.makeObj());
678 EXPECT_FALSE(E);
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) {
694 MockData2 D;
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}));
699 // id 2: int
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});
723 BTFParser BTF;
724 Error E = BTF.parse(D.makeObj());
725 EXPECT_FALSE(E);
727 SYMBOLIZE(SA({0, 1}), "<enumval_exists> [1] enum foo::U = 1");
728 SYMBOLIZE(SA({8, 1}), "<enumval_value> [1] enum foo::V = 2");
729 SYMBOLIZE(
730 SA({16, 1}),
731 "<enumval_value> [1] '1:0' <unexpected enumval relocation spec size>");
732 SYMBOLIZE(
733 SA({24, 1}),
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) {
741 MockData2 D;
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});
755 BTFParser BTF;
756 Error E = BTF.parse(D.makeObj());
757 EXPECT_FALSE(E);
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) {
764 MockData2 D;
765 // id 1: int
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});
813 BTFParser BTF;
814 Error E = BTF.parse(D.makeObj());
815 EXPECT_FALSE(E);
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) {
839 MockData2 D;
840 // struct foo {
841 // int u;
842 // }
843 // typedef struct foo bar;
844 // struct buz {
845 // const bar v;
846 // }
847 // typedef buz quux;
848 // const volatile restrict quux <some-var>;
849 uint32_t Int =
850 D.addType({D.addString("int"), mkInfo(BTF::BTF_KIND_INT), {4}});
851 D.addTail((uint32_t)0);
852 uint32_t Foo =
853 D.addType({D.addString("foo"), mkInfo(BTF::BTF_KIND_STRUCT) | 1, {4}});
854 D.addTail(BTF::BTFMember({D.addString("u"), Int, 0}));
855 uint32_t Bar =
856 D.addType({D.addString("bar"), mkInfo(BTF::BTF_KIND_TYPEDEF), {Foo}});
857 uint32_t CBar =
858 D.addType({D.addString("bar"), mkInfo(BTF::BTF_KIND_CONST), {Bar}});
859 uint32_t Buz =
860 D.addType({D.addString("buz"), mkInfo(BTF::BTF_KIND_STRUCT) | 1, {4}});
861 D.addTail(BTF::BTFMember({D.addString("v"), CBar, 0}));
862 uint32_t Quux =
863 D.addType({D.addString("quux"), mkInfo(BTF::BTF_KIND_TYPEDEF), {Buz}});
864 uint32_t RQuux =
865 D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_RESTRICT), {Quux}});
866 uint32_t VRQuux =
867 D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_VOLATILE), {RQuux}});
868 uint32_t CVRQuux =
869 D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_CONST), {VRQuux}});
870 uint32_t CUnknown =
871 D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_CONST), {77}});
872 uint32_t CVUnknown =
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});
880 BTFParser BTF;
881 Error E = BTF.parse(D.makeObj());
882 EXPECT_FALSE(E);
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) {
893 MockData2 D;
894 // __attribute__((type_tag("tag"))) void
895 uint32_t Tag =
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});
902 BTFParser BTF;
903 Error E = BTF.parse(D.makeObj());
904 EXPECT_FALSE(E);
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) {
911 MockData2 D;
913 D.addType(
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});
918 BTFParser BTF;
919 Error E = BTF.parse(D.makeObj());
920 EXPECT_FALSE(E);
922 SYMBOLIZE(SA({0, 1}), "<type_exists> [1] '' <modifiers chain is too long>");
925 TEST(BTFParserTest, relocAnonFieldsAndTypes) {
926 MockData2 D;
928 // struct {
929 // int :32;
930 // } v;
931 uint32_t Int =
932 D.addType({D.addString("int"), mkInfo(BTF::BTF_KIND_INT), {4}});
933 D.addTail((uint32_t)0);
934 uint32_t Anon =
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});
942 BTFParser BTF;
943 Error E = BTF.parse(D.makeObj());
944 EXPECT_FALSE(E);
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) {
951 MockData2 D;
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});
960 BTFParser BTF;
961 Error E = BTF.parse(D.makeObj());
962 EXPECT_FALSE(E);
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) {
972 MockData2 D;
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});
985 BTFParser BTF;
986 Error E = BTF.parse(D.makeObj());
987 EXPECT_FALSE(E);
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);
1003 ASSERT_TRUE(Relo);
1004 const BTF::CommonType *Type = BTF.findType(Relo->TypeID);
1005 ASSERT_TRUE(Type);
1006 EXPECT_EQ(BTF.findString(Type->NameOff), Name);
1009 AssertReloType({8, 1}, "S");
1010 AssertReloType({8, 2}, "T");
1013 TEST(BTFParserTest, parserResetReloAndTypes) {
1014 BTFParser BTF;
1015 MockData2 D;
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());
1025 EXPECT_FALSE(E1);
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.
1034 D.reset();
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());
1040 EXPECT_FALSE(E2);
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;
1051 MockData2 D;
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();
1062 Opts = {};
1063 Opts.LoadLines = true;
1064 ASSERT_SUCCEEDED(BTF1.parse(Obj1, Opts));
1066 Opts = {};
1067 Opts.LoadTypes = true;
1068 ASSERT_SUCCEEDED(BTF2.parse(Obj1, Opts));
1070 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}));
1087 } // namespace