xref: /llvm-project/llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp (revision 75bc20ff899753b100cb875ce703af2348a1d6bb)
1c8e055d4SEduard Zingerman //===-- SourcePrinter.cpp -  source interleaving utilities ----------------===//
2c8e055d4SEduard Zingerman //
3c8e055d4SEduard Zingerman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c8e055d4SEduard Zingerman // See https://llvm.org/LICENSE.txt for license information.
5c8e055d4SEduard Zingerman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c8e055d4SEduard Zingerman //
7c8e055d4SEduard Zingerman //===----------------------------------------------------------------------===//
8c8e055d4SEduard Zingerman 
9c8e055d4SEduard Zingerman #include "llvm/DebugInfo/BTF/BTFContext.h"
10c8e055d4SEduard Zingerman #include "llvm/ObjectYAML/YAML.h"
11c8e055d4SEduard Zingerman #include "llvm/ObjectYAML/yaml2obj.h"
128130166bSFangrui Song #include "llvm/Support/SwapByteOrder.h"
13c8e055d4SEduard Zingerman #include "llvm/Testing/Support/Error.h"
14c8e055d4SEduard Zingerman 
15c8e055d4SEduard Zingerman using namespace llvm;
16c8e055d4SEduard Zingerman using namespace llvm::object;
17c8e055d4SEduard Zingerman 
18c8e055d4SEduard Zingerman #define LC(Line, Col) ((Line << 10u) | Col)
19d15f96feSEduard Zingerman #define ASSERT_SUCCEEDED(E) ASSERT_THAT_ERROR((E), Succeeded())
20c8e055d4SEduard Zingerman 
21c8e055d4SEduard Zingerman const char BTFEndOfData[] =
22c8e055d4SEduard Zingerman     "error while reading .BTF section: unexpected end of data";
23c8e055d4SEduard Zingerman const char BTFExtEndOfData[] =
24c8e055d4SEduard Zingerman     "error while reading .BTF.ext section: unexpected end of data";
25c8e055d4SEduard Zingerman 
operator <<(raw_ostream & OS,const yaml::BinaryRef & Ref)26c8e055d4SEduard Zingerman static raw_ostream &operator<<(raw_ostream &OS, const yaml::BinaryRef &Ref) {
27c8e055d4SEduard Zingerman   Ref.writeAsHex(OS);
28c8e055d4SEduard Zingerman   return OS;
29c8e055d4SEduard Zingerman }
30c8e055d4SEduard Zingerman 
31c8e055d4SEduard Zingerman template <typename T>
makeBinRef(const T * Ptr,size_t Size=sizeof (T))32c8e055d4SEduard Zingerman static yaml::BinaryRef makeBinRef(const T *Ptr, size_t Size = sizeof(T)) {
33c8e055d4SEduard Zingerman   return yaml::BinaryRef(ArrayRef<uint8_t>((const uint8_t *)Ptr, Size));
34c8e055d4SEduard Zingerman }
35c8e055d4SEduard Zingerman 
36c8e055d4SEduard Zingerman namespace {
37c8e055d4SEduard Zingerman // This is a mockup for an ELF file containing .BTF and .BTF.ext sections.
38c8e055d4SEduard Zingerman // Binary content of these sections corresponds to the value of
39c8e055d4SEduard Zingerman // MockData1::BTF and MockData1::Ext fields.
40c8e055d4SEduard Zingerman //
41c8e055d4SEduard Zingerman // The yaml::yaml2ObjectFile() is used to generate actual ELF,
42c8e055d4SEduard Zingerman // see MockData1::makeObj().
43c8e055d4SEduard Zingerman //
44c8e055d4SEduard Zingerman // The `BTF` and `Ext` fields are initialized with correct values
45c8e055d4SEduard Zingerman // valid for a small example with a few sections, fields could be
46c8e055d4SEduard Zingerman // modified before a call to `makeObj()` to test parser with invalid
47c8e055d4SEduard Zingerman // input, etc.
48c8e055d4SEduard Zingerman 
49490e8e22SEduard Zingerman struct MockData1 {
50c8e055d4SEduard Zingerman // Use "pragma pack" to model .BTF & .BTF.ext sections content using
51c8e055d4SEduard Zingerman // 'struct' objects. This pragma is supported by CLANG, GCC & MSVC,
52c8e055d4SEduard Zingerman // which matters for LLVM CI.
53c8e055d4SEduard Zingerman #pragma pack(push, 1)
54c8e055d4SEduard Zingerman   struct B {
55c8e055d4SEduard Zingerman     BTF::Header Header = {};
56d15f96feSEduard Zingerman     // No types.
57c8e055d4SEduard Zingerman     struct S {
58c8e055d4SEduard Zingerman       char Foo[4] = "foo";
59c8e055d4SEduard Zingerman       char Bar[4] = "bar";
60c8e055d4SEduard Zingerman       char Buz[4] = "buz";
61c8e055d4SEduard Zingerman       char Line1[11] = "first line";
62c8e055d4SEduard Zingerman       char Line2[12] = "second line";
63c8e055d4SEduard Zingerman       char File1[4] = "a.c";
64c8e055d4SEduard Zingerman       char File2[4] = "b.c";
65c8e055d4SEduard Zingerman     } Strings;
66c8e055d4SEduard Zingerman 
B__anon10cc3c150111::MockData1::B67c8e055d4SEduard Zingerman     B() {
68c8e055d4SEduard Zingerman       Header.Magic = BTF::MAGIC;
69c8e055d4SEduard Zingerman       Header.Version = 1;
70c8e055d4SEduard Zingerman       Header.HdrLen = sizeof(Header);
71c8e055d4SEduard Zingerman       Header.StrOff = offsetof(B, Strings) - sizeof(Header);
72c8e055d4SEduard Zingerman       Header.StrLen = sizeof(Strings);
73c8e055d4SEduard Zingerman     }
74c8e055d4SEduard Zingerman   } BTF;
75c8e055d4SEduard Zingerman 
76c8e055d4SEduard Zingerman   struct E {
77c8e055d4SEduard Zingerman     BTF::ExtHeader Header = {};
78d15f96feSEduard Zingerman     // No func info.
79c8e055d4SEduard Zingerman     struct {
80c8e055d4SEduard Zingerman       uint32_t LineRecSize = sizeof(BTF::BPFLineInfo);
81c8e055d4SEduard Zingerman       struct {
82c8e055d4SEduard Zingerman         BTF::SecLineInfo Sec = {offsetof(B::S, Foo), 2};
83c8e055d4SEduard Zingerman         BTF::BPFLineInfo Lines[2] = {
84c8e055d4SEduard Zingerman             {16, offsetof(B::S, File1), offsetof(B::S, Line1), LC(7, 1)},
85c8e055d4SEduard Zingerman             {32, offsetof(B::S, File1), offsetof(B::S, Line2), LC(14, 5)},
86c8e055d4SEduard Zingerman         };
87c8e055d4SEduard Zingerman       } Foo;
88c8e055d4SEduard Zingerman       struct {
89c8e055d4SEduard Zingerman         BTF::SecLineInfo Sec = {offsetof(B::S, Bar), 1};
90c8e055d4SEduard Zingerman         BTF::BPFLineInfo Lines[1] = {
91c8e055d4SEduard Zingerman             {0, offsetof(B::S, File2), offsetof(B::S, Line1), LC(42, 4)},
92c8e055d4SEduard Zingerman         };
93c8e055d4SEduard Zingerman       } Bar;
94c8e055d4SEduard Zingerman     } Lines;
95c8e055d4SEduard Zingerman 
E__anon10cc3c150111::MockData1::E96c8e055d4SEduard Zingerman     E() {
97c8e055d4SEduard Zingerman       Header.Magic = BTF::MAGIC;
98c8e055d4SEduard Zingerman       Header.Version = 1;
99c8e055d4SEduard Zingerman       Header.HdrLen = sizeof(Header);
100c8e055d4SEduard Zingerman       Header.LineInfoOff = offsetof(E, Lines) - sizeof(Header);
101c8e055d4SEduard Zingerman       Header.LineInfoLen = sizeof(Lines);
102c8e055d4SEduard Zingerman     }
103c8e055d4SEduard Zingerman   } Ext;
104490e8e22SEduard Zingerman #pragma pack(pop)
105c8e055d4SEduard Zingerman 
106c8e055d4SEduard Zingerman   int BTFSectionLen = sizeof(BTF);
107c8e055d4SEduard Zingerman   int ExtSectionLen = sizeof(Ext);
108c8e055d4SEduard Zingerman 
109c8e055d4SEduard Zingerman   SmallString<0> Storage;
110c8e055d4SEduard Zingerman   std::unique_ptr<ObjectFile> Obj;
111c8e055d4SEduard Zingerman 
makeObj__anon10cc3c150111::MockData1112c8e055d4SEduard Zingerman   ObjectFile &makeObj() {
113c8e055d4SEduard Zingerman     std::string Buffer;
114c8e055d4SEduard Zingerman     raw_string_ostream Yaml(Buffer);
115c8e055d4SEduard Zingerman     Yaml << R"(
116c8e055d4SEduard Zingerman !ELF
117c8e055d4SEduard Zingerman FileHeader:
1188130166bSFangrui Song   Class:    ELFCLASS64)";
1198130166bSFangrui Song     if (sys::IsBigEndianHost)
1208130166bSFangrui Song       Yaml << "\n  Data:     ELFDATA2MSB";
1218130166bSFangrui Song     else
1228130166bSFangrui Song       Yaml << "\n  Data:     ELFDATA2LSB";
1238130166bSFangrui Song     Yaml << R"(
124c8e055d4SEduard Zingerman   Type:     ET_REL
125c8e055d4SEduard Zingerman   Machine:  EM_BPF
126c8e055d4SEduard Zingerman Sections:
127c8e055d4SEduard Zingerman   - Name:     foo
128c8e055d4SEduard Zingerman     Type:     SHT_PROGBITS
129c8e055d4SEduard Zingerman     Size:     0x0
130c8e055d4SEduard Zingerman   - Name:     bar
131c8e055d4SEduard Zingerman     Type:     SHT_PROGBITS
132c8e055d4SEduard Zingerman     Size:     0x0)";
133c8e055d4SEduard Zingerman 
134c8e055d4SEduard Zingerman     if (BTFSectionLen >= 0)
135c8e055d4SEduard Zingerman       Yaml << R"(
136c8e055d4SEduard Zingerman   - Name:     .BTF
137c8e055d4SEduard Zingerman     Type:     SHT_PROGBITS
138c8e055d4SEduard Zingerman     Content: )"
139c8e055d4SEduard Zingerman            << makeBinRef(&BTF, BTFSectionLen);
140c8e055d4SEduard Zingerman 
141c8e055d4SEduard Zingerman     if (ExtSectionLen >= 0)
142c8e055d4SEduard Zingerman       Yaml << R"(
143c8e055d4SEduard Zingerman   - Name:     .BTF.ext
144c8e055d4SEduard Zingerman     Type:     SHT_PROGBITS
145c8e055d4SEduard Zingerman     Content: )"
146c8e055d4SEduard Zingerman            << makeBinRef(&Ext, ExtSectionLen);
147c8e055d4SEduard Zingerman 
148c8e055d4SEduard Zingerman     Obj = yaml::yaml2ObjectFile(Storage, Buffer,
149c8e055d4SEduard Zingerman                                 [](const Twine &Err) { errs() << Err; });
150*75bc20ffSKazu Hirata     return *Obj;
151c8e055d4SEduard Zingerman   }
152c8e055d4SEduard Zingerman };
153c8e055d4SEduard Zingerman 
TEST(BTFParserTest,simpleCorrectInput)154c8e055d4SEduard Zingerman TEST(BTFParserTest, simpleCorrectInput) {
155c8e055d4SEduard Zingerman   BTFParser BTF;
156c8e055d4SEduard Zingerman   MockData1 Mock;
157c8e055d4SEduard Zingerman   Error Err = BTF.parse(Mock.makeObj());
158c8e055d4SEduard Zingerman   EXPECT_FALSE(Err);
159c8e055d4SEduard Zingerman 
160c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(offsetof(MockData1::B::S, Foo)), "foo");
161c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(offsetof(MockData1::B::S, Bar)), "bar");
162c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(offsetof(MockData1::B::S, Line1)), "first line");
163c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(offsetof(MockData1::B::S, Line2)), "second line");
164c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(offsetof(MockData1::B::S, File1)), "a.c");
165c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(offsetof(MockData1::B::S, File2)), "b.c");
166c8e055d4SEduard Zingerman 
167d15f96feSEduard Zingerman   // Invalid offset.
168c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(sizeof(MockData1::B::S)), StringRef());
169c8e055d4SEduard Zingerman 
170c8e055d4SEduard Zingerman   const BTF::BPFLineInfo *I1 = BTF.findLineInfo({16, 1});
1718130166bSFangrui Song   ASSERT_TRUE(I1);
172c8e055d4SEduard Zingerman   EXPECT_EQ(I1->getLine(), 7u);
173c8e055d4SEduard Zingerman   EXPECT_EQ(I1->getCol(), 1u);
174c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(I1->FileNameOff), "a.c");
175c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(I1->LineOff), "first line");
176c8e055d4SEduard Zingerman 
177c8e055d4SEduard Zingerman   const BTF::BPFLineInfo *I2 = BTF.findLineInfo({32, 1});
1788130166bSFangrui Song   ASSERT_TRUE(I2);
179c8e055d4SEduard Zingerman   EXPECT_EQ(I2->getLine(), 14u);
180c8e055d4SEduard Zingerman   EXPECT_EQ(I2->getCol(), 5u);
181c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(I2->FileNameOff), "a.c");
182c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(I2->LineOff), "second line");
183c8e055d4SEduard Zingerman 
184c8e055d4SEduard Zingerman   const BTF::BPFLineInfo *I3 = BTF.findLineInfo({0, 2});
1858130166bSFangrui Song   ASSERT_TRUE(I3);
186c8e055d4SEduard Zingerman   EXPECT_EQ(I3->getLine(), 42u);
187c8e055d4SEduard Zingerman   EXPECT_EQ(I3->getCol(), 4u);
188c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(I3->FileNameOff), "b.c");
189c8e055d4SEduard Zingerman   EXPECT_EQ(BTF.findString(I3->LineOff), "first line");
190c8e055d4SEduard Zingerman 
191d15f96feSEduard Zingerman   // No info for insn address.
192c8e055d4SEduard Zingerman   EXPECT_FALSE(BTF.findLineInfo({24, 1}));
193c8e055d4SEduard Zingerman   EXPECT_FALSE(BTF.findLineInfo({8, 2}));
194d15f96feSEduard Zingerman   // No info for section number.
195c8e055d4SEduard Zingerman   EXPECT_FALSE(BTF.findLineInfo({16, 3}));
196c8e055d4SEduard Zingerman }
197c8e055d4SEduard Zingerman 
TEST(BTFParserTest,badSectionNameOffset)198c8e055d4SEduard Zingerman TEST(BTFParserTest, badSectionNameOffset) {
199c8e055d4SEduard Zingerman   BTFParser BTF;
200c8e055d4SEduard Zingerman   MockData1 Mock;
201c8e055d4SEduard Zingerman   // "foo" is section #1, corrupting it's name offset will make impossible
202c8e055d4SEduard Zingerman   // to match section name with section index when BTF is parsed.
203c8e055d4SEduard Zingerman   Mock.Ext.Lines.Foo.Sec.SecNameOff = 100500;
204c8e055d4SEduard Zingerman   Error Err = BTF.parse(Mock.makeObj());
205c8e055d4SEduard Zingerman   EXPECT_FALSE(Err);
206d15f96feSEduard Zingerman   // "foo" line info should be corrupted.
207c8e055d4SEduard Zingerman   EXPECT_FALSE(BTF.findLineInfo({16, 1}));
208d15f96feSEduard Zingerman   // "bar" line info should be ok.
209c8e055d4SEduard Zingerman   EXPECT_TRUE(BTF.findLineInfo({0, 2}));
210c8e055d4SEduard Zingerman }
211c8e055d4SEduard Zingerman 
212d15f96feSEduard Zingerman // Keep this as macro to preserve line number info.
213c8e055d4SEduard Zingerman #define EXPECT_PARSE_ERROR(Mock, Message)                                      \
214c8e055d4SEduard Zingerman   do {                                                                         \
215c8e055d4SEduard Zingerman     BTFParser BTF;                                                             \
216c8e055d4SEduard Zingerman     EXPECT_THAT_ERROR(BTF.parse((Mock).makeObj()),                             \
217c8e055d4SEduard Zingerman                       FailedWithMessage(testing::HasSubstr(Message)));         \
218c8e055d4SEduard Zingerman   } while (false)
219c8e055d4SEduard Zingerman 
TEST(BTFParserTest,badBTFMagic)220c8e055d4SEduard Zingerman TEST(BTFParserTest, badBTFMagic) {
221c8e055d4SEduard Zingerman   MockData1 Mock;
222c8e055d4SEduard Zingerman   Mock.BTF.Header.Magic = 42;
223c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock, "invalid .BTF magic: 2a");
224c8e055d4SEduard Zingerman }
225c8e055d4SEduard Zingerman 
TEST(BTFParserTest,badBTFVersion)226c8e055d4SEduard Zingerman TEST(BTFParserTest, badBTFVersion) {
227c8e055d4SEduard Zingerman   MockData1 Mock;
228c8e055d4SEduard Zingerman   Mock.BTF.Header.Version = 42;
229c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock, "unsupported .BTF version: 42");
230c8e055d4SEduard Zingerman }
231c8e055d4SEduard Zingerman 
TEST(BTFParserTest,badBTFHdrLen)232c8e055d4SEduard Zingerman TEST(BTFParserTest, badBTFHdrLen) {
233c8e055d4SEduard Zingerman   MockData1 Mock;
234c8e055d4SEduard Zingerman   Mock.BTF.Header.HdrLen = 5;
235c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock, "unexpected .BTF header length: 5");
236c8e055d4SEduard Zingerman }
237c8e055d4SEduard Zingerman 
TEST(BTFParserTest,badBTFSectionLen)238c8e055d4SEduard Zingerman TEST(BTFParserTest, badBTFSectionLen) {
239c8e055d4SEduard Zingerman   MockData1 Mock1, Mock2;
240c8e055d4SEduard Zingerman 
241d15f96feSEduard Zingerman   // Cut-off string section by one byte.
242c8e055d4SEduard Zingerman   Mock1.BTFSectionLen =
243c8e055d4SEduard Zingerman       offsetof(MockData1::B, Strings) + sizeof(MockData1::B::S) - 1;
244c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock1, "invalid .BTF section size");
245c8e055d4SEduard Zingerman 
246d15f96feSEduard Zingerman   // Cut-off header.
247c8e055d4SEduard Zingerman   Mock2.BTFSectionLen = offsetof(BTF::Header, StrOff);
248c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock2, BTFEndOfData);
249c8e055d4SEduard Zingerman }
250c8e055d4SEduard Zingerman 
TEST(BTFParserTest,badBTFExtMagic)251c8e055d4SEduard Zingerman TEST(BTFParserTest, badBTFExtMagic) {
252c8e055d4SEduard Zingerman   MockData1 Mock;
253c8e055d4SEduard Zingerman   Mock.Ext.Header.Magic = 42;
254c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock, "invalid .BTF.ext magic: 2a");
255c8e055d4SEduard Zingerman }
256c8e055d4SEduard Zingerman 
TEST(BTFParserTest,badBTFExtVersion)257c8e055d4SEduard Zingerman TEST(BTFParserTest, badBTFExtVersion) {
258c8e055d4SEduard Zingerman   MockData1 Mock;
259c8e055d4SEduard Zingerman   Mock.Ext.Header.Version = 42;
260c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock, "unsupported .BTF.ext version: 42");
261c8e055d4SEduard Zingerman }
262c8e055d4SEduard Zingerman 
TEST(BTFParserTest,badBTFExtHdrLen)263c8e055d4SEduard Zingerman TEST(BTFParserTest, badBTFExtHdrLen) {
264c8e055d4SEduard Zingerman   MockData1 Mock1, Mock2;
265c8e055d4SEduard Zingerman 
266c8e055d4SEduard Zingerman   Mock1.Ext.Header.HdrLen = 5;
267c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock1, "unexpected .BTF.ext header length: 5");
268c8e055d4SEduard Zingerman 
269c8e055d4SEduard Zingerman   Mock2.Ext.Header.HdrLen = sizeof(Mock2.Ext);
270c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock2, BTFExtEndOfData);
271c8e055d4SEduard Zingerman }
272c8e055d4SEduard Zingerman 
TEST(BTFParserTest,badBTFExtSectionLen)273c8e055d4SEduard Zingerman TEST(BTFParserTest, badBTFExtSectionLen) {
274c8e055d4SEduard Zingerman   MockData1 Mock1, Mock2, Mock3;
275c8e055d4SEduard Zingerman 
276d15f96feSEduard Zingerman   // Cut-off header before HdrLen.
277c8e055d4SEduard Zingerman   Mock1.ExtSectionLen = offsetof(BTF::ExtHeader, HdrLen);
278c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock1, BTFExtEndOfData);
279c8e055d4SEduard Zingerman 
280d15f96feSEduard Zingerman   // Cut-off header before LineInfoLen.
281c8e055d4SEduard Zingerman   Mock2.ExtSectionLen = offsetof(BTF::ExtHeader, LineInfoLen);
282c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock2, BTFExtEndOfData);
283c8e055d4SEduard Zingerman 
284d15f96feSEduard Zingerman   // Cut-off line-info section somewhere in the middle.
285c8e055d4SEduard Zingerman   Mock3.ExtSectionLen = offsetof(MockData1::E, Lines) + 4;
286c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock3, BTFExtEndOfData);
287c8e055d4SEduard Zingerman }
288c8e055d4SEduard Zingerman 
TEST(BTFParserTest,badBTFExtLineInfoRecSize)289c8e055d4SEduard Zingerman TEST(BTFParserTest, badBTFExtLineInfoRecSize) {
290c8e055d4SEduard Zingerman   MockData1 Mock1, Mock2;
291c8e055d4SEduard Zingerman 
292c8e055d4SEduard Zingerman   Mock1.Ext.Lines.LineRecSize = 2;
293c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock1, "unexpected .BTF.ext line info record length: 2");
294c8e055d4SEduard Zingerman 
295c8e055d4SEduard Zingerman   Mock2.Ext.Lines.LineRecSize = sizeof(Mock2.Ext.Lines.Foo.Lines[0]) + 1;
296c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock2, BTFExtEndOfData);
297c8e055d4SEduard Zingerman }
298c8e055d4SEduard Zingerman 
TEST(BTFParserTest,badBTFExtLineSectionName)299c8e055d4SEduard Zingerman TEST(BTFParserTest, badBTFExtLineSectionName) {
300c8e055d4SEduard Zingerman   MockData1 Mock1;
301c8e055d4SEduard Zingerman 
302c8e055d4SEduard Zingerman   Mock1.Ext.Lines.Foo.Sec.SecNameOff = offsetof(MockData1::B::S, Buz);
303c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(
304c8e055d4SEduard Zingerman       Mock1, "can't find section 'buz' while parsing .BTF.ext line info");
305c8e055d4SEduard Zingerman }
306c8e055d4SEduard Zingerman 
TEST(BTFParserTest,missingSections)307c8e055d4SEduard Zingerman TEST(BTFParserTest, missingSections) {
308c8e055d4SEduard Zingerman   MockData1 Mock1, Mock2, Mock3;
309c8e055d4SEduard Zingerman 
310c8e055d4SEduard Zingerman   Mock1.BTFSectionLen = -1;
311c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock1, "can't find .BTF section");
312c8e055d4SEduard Zingerman   EXPECT_FALSE(BTFParser::hasBTFSections(Mock1.makeObj()));
313c8e055d4SEduard Zingerman 
314c8e055d4SEduard Zingerman   Mock2.ExtSectionLen = -1;
315c8e055d4SEduard Zingerman   EXPECT_PARSE_ERROR(Mock2, "can't find .BTF.ext section");
316c8e055d4SEduard Zingerman   EXPECT_FALSE(BTFParser::hasBTFSections(Mock2.makeObj()));
317c8e055d4SEduard Zingerman 
318c8e055d4SEduard Zingerman   EXPECT_TRUE(BTFParser::hasBTFSections(Mock3.makeObj()));
319c8e055d4SEduard Zingerman }
320c8e055d4SEduard Zingerman 
321c8e055d4SEduard Zingerman // Check that BTFParser instance is reset when BTFParser::parse() is
322c8e055d4SEduard Zingerman // called several times.
TEST(BTFParserTest,parserReset)323c8e055d4SEduard Zingerman TEST(BTFParserTest, parserReset) {
324c8e055d4SEduard Zingerman   BTFParser BTF;
325c8e055d4SEduard Zingerman   MockData1 Mock1, Mock2;
326c8e055d4SEduard Zingerman 
327c8e055d4SEduard Zingerman   EXPECT_FALSE(BTF.parse(Mock1.makeObj()));
328c8e055d4SEduard Zingerman   EXPECT_TRUE(BTF.findLineInfo({16, 1}));
329c8e055d4SEduard Zingerman   EXPECT_TRUE(BTF.findLineInfo({0, 2}));
330c8e055d4SEduard Zingerman 
331c8e055d4SEduard Zingerman   // Break the reference to "bar" section name, thus making
332c8e055d4SEduard Zingerman   // information about "bar" line numbers unavailable.
333c8e055d4SEduard Zingerman   Mock2.Ext.Lines.Bar.Sec.SecNameOff = 100500;
334c8e055d4SEduard Zingerman 
335c8e055d4SEduard Zingerman   EXPECT_FALSE(BTF.parse(Mock2.makeObj()));
336c8e055d4SEduard Zingerman   EXPECT_TRUE(BTF.findLineInfo({16, 1}));
337c8e055d4SEduard Zingerman   // Make sure that "bar" no longer available (its index is 2).
338c8e055d4SEduard Zingerman   EXPECT_FALSE(BTF.findLineInfo({0, 2}));
339c8e055d4SEduard Zingerman }
340c8e055d4SEduard Zingerman 
TEST(BTFParserTest,btfContext)341c8e055d4SEduard Zingerman TEST(BTFParserTest, btfContext) {
342c8e055d4SEduard Zingerman   MockData1 Mock;
343c8e055d4SEduard Zingerman   BTFParser BTF;
344c8e055d4SEduard Zingerman   std::unique_ptr<BTFContext> Ctx = BTFContext::create(Mock.makeObj());
345c8e055d4SEduard Zingerman 
346c8e055d4SEduard Zingerman   DILineInfo I1 = Ctx->getLineInfoForAddress({16, 1});
347c8e055d4SEduard Zingerman   EXPECT_EQ(I1.Line, 7u);
348c8e055d4SEduard Zingerman   EXPECT_EQ(I1.Column, 1u);
349c8e055d4SEduard Zingerman   EXPECT_EQ(I1.FileName, "a.c");
350c8e055d4SEduard Zingerman   EXPECT_EQ(I1.LineSource, "first line");
351c8e055d4SEduard Zingerman 
352c8e055d4SEduard Zingerman   DILineInfo I2 = Ctx->getLineInfoForAddress({24, 1});
353c8e055d4SEduard Zingerman   EXPECT_EQ(I2.Line, 0u);
354c8e055d4SEduard Zingerman   EXPECT_EQ(I2.Column, 0u);
355c8e055d4SEduard Zingerman   EXPECT_EQ(I2.FileName, DILineInfo::BadString);
356c8e055d4SEduard Zingerman   EXPECT_EQ(I2.LineSource, std::nullopt);
357c8e055d4SEduard Zingerman }
358c8e055d4SEduard Zingerman 
mkInfo(uint32_t Kind)359d15f96feSEduard Zingerman static uint32_t mkInfo(uint32_t Kind) { return Kind << 24; }
360d15f96feSEduard Zingerman 
append(std::string & S,const T & What)361d15f96feSEduard Zingerman template <typename T> static void append(std::string &S, const T &What) {
362d15f96feSEduard Zingerman   S.append((const char *)&What, sizeof(What));
363d15f96feSEduard Zingerman }
364d15f96feSEduard Zingerman 
365d15f96feSEduard Zingerman class MockData2 {
366d15f96feSEduard Zingerman   SmallString<0> ObjStorage;
367d15f96feSEduard Zingerman   std::unique_ptr<ObjectFile> Obj;
368d15f96feSEduard Zingerman   std::string Types;
369d15f96feSEduard Zingerman   std::string Strings;
370d15f96feSEduard Zingerman   std::string Relocs;
371d15f96feSEduard Zingerman   std::string Lines;
372d15f96feSEduard Zingerman   unsigned TotalTypes;
373d15f96feSEduard Zingerman   int LastRelocSecIdx;
374d15f96feSEduard Zingerman   unsigned NumRelocs;
375d15f96feSEduard Zingerman   int LastLineSecIdx;
376d15f96feSEduard Zingerman   unsigned NumLines;
377d15f96feSEduard Zingerman 
378d15f96feSEduard Zingerman public:
MockData2()379d15f96feSEduard Zingerman   MockData2() { reset(); }
380d15f96feSEduard Zingerman 
totalTypes() const381d15f96feSEduard Zingerman   unsigned totalTypes() const { return TotalTypes; }
382d15f96feSEduard Zingerman 
addString(StringRef S)383d15f96feSEduard Zingerman   uint32_t addString(StringRef S) {
384d15f96feSEduard Zingerman     uint32_t Off = Strings.size();
385d15f96feSEduard Zingerman     Strings.append(S.data(), S.size());
386d15f96feSEduard Zingerman     Strings.append("\0", 1);
387d15f96feSEduard Zingerman     return Off;
388d15f96feSEduard Zingerman   };
389d15f96feSEduard Zingerman 
addType(const BTF::CommonType & Tp)390d15f96feSEduard Zingerman   uint32_t addType(const BTF::CommonType &Tp) {
391d15f96feSEduard Zingerman     append(Types, Tp);
392d15f96feSEduard Zingerman     return ++TotalTypes;
393d15f96feSEduard Zingerman   }
394d15f96feSEduard Zingerman 
addTail(const T & Tp)395d15f96feSEduard Zingerman   template <typename T> void addTail(const T &Tp) { append(Types, Tp); }
396d15f96feSEduard Zingerman 
resetTypes()397d15f96feSEduard Zingerman   void resetTypes() {
398d15f96feSEduard Zingerman     Types.resize(0);
399d15f96feSEduard Zingerman     TotalTypes = 0;
400d15f96feSEduard Zingerman   }
401d15f96feSEduard Zingerman 
reset()402d15f96feSEduard Zingerman   void reset() {
403d15f96feSEduard Zingerman     ObjStorage.clear();
404d15f96feSEduard Zingerman     Types.resize(0);
405d15f96feSEduard Zingerman     Strings.resize(0);
406d15f96feSEduard Zingerman     Relocs.resize(0);
407d15f96feSEduard Zingerman     Lines.resize(0);
408d15f96feSEduard Zingerman     TotalTypes = 0;
409d15f96feSEduard Zingerman     LastRelocSecIdx = -1;
410d15f96feSEduard Zingerman     NumRelocs = 0;
411d15f96feSEduard Zingerman     LastLineSecIdx = -1;
412d15f96feSEduard Zingerman     NumLines = 0;
413d15f96feSEduard Zingerman   }
414d15f96feSEduard Zingerman 
finishRelocSec()415d15f96feSEduard Zingerman   void finishRelocSec() {
416d15f96feSEduard Zingerman     if (LastRelocSecIdx == -1)
417d15f96feSEduard Zingerman       return;
418d15f96feSEduard Zingerman 
419d15f96feSEduard Zingerman     BTF::SecFieldReloc *SecInfo =
420d15f96feSEduard Zingerman         (BTF::SecFieldReloc *)&Relocs[LastRelocSecIdx];
421d15f96feSEduard Zingerman     SecInfo->NumFieldReloc = NumRelocs;
422d15f96feSEduard Zingerman     LastRelocSecIdx = -1;
423d15f96feSEduard Zingerman     NumRelocs = 0;
424d15f96feSEduard Zingerman   }
425d15f96feSEduard Zingerman 
finishLineSec()426d15f96feSEduard Zingerman   void finishLineSec() {
427d15f96feSEduard Zingerman     if (LastLineSecIdx == -1)
428d15f96feSEduard Zingerman       return;
429d15f96feSEduard Zingerman 
430d15f96feSEduard Zingerman     BTF::SecLineInfo *SecInfo = (BTF::SecLineInfo *)&Lines[LastLineSecIdx];
431d15f96feSEduard Zingerman     SecInfo->NumLineInfo = NumLines;
432d15f96feSEduard Zingerman     NumLines = 0;
433d15f96feSEduard Zingerman     LastLineSecIdx = -1;
434d15f96feSEduard Zingerman   }
435d15f96feSEduard Zingerman 
addRelocSec(const BTF::SecFieldReloc & R)436d15f96feSEduard Zingerman   void addRelocSec(const BTF::SecFieldReloc &R) {
437d15f96feSEduard Zingerman     finishRelocSec();
438d15f96feSEduard Zingerman     LastRelocSecIdx = Relocs.size();
439d15f96feSEduard Zingerman     append(Relocs, R);
440d15f96feSEduard Zingerman   }
441d15f96feSEduard Zingerman 
addReloc(const BTF::BPFFieldReloc & R)442d15f96feSEduard Zingerman   void addReloc(const BTF::BPFFieldReloc &R) {
443d15f96feSEduard Zingerman     append(Relocs, R);
444d15f96feSEduard Zingerman     ++NumRelocs;
445d15f96feSEduard Zingerman   }
446d15f96feSEduard Zingerman 
addLinesSec(const BTF::SecLineInfo & R)447d15f96feSEduard Zingerman   void addLinesSec(const BTF::SecLineInfo &R) {
448d15f96feSEduard Zingerman     finishLineSec();
449d15f96feSEduard Zingerman     LastLineSecIdx = Lines.size();
450d15f96feSEduard Zingerman     append(Lines, R);
451d15f96feSEduard Zingerman   }
452d15f96feSEduard Zingerman 
addLine(const BTF::BPFLineInfo & R)453d15f96feSEduard Zingerman   void addLine(const BTF::BPFLineInfo &R) {
454d15f96feSEduard Zingerman     append(Lines, R);
455d15f96feSEduard Zingerman     ++NumLines;
456d15f96feSEduard Zingerman   }
457d15f96feSEduard Zingerman 
makeObj()458d15f96feSEduard Zingerman   ObjectFile &makeObj() {
459d15f96feSEduard Zingerman     finishRelocSec();
460d15f96feSEduard Zingerman     finishLineSec();
461d15f96feSEduard Zingerman 
462d15f96feSEduard Zingerman     BTF::Header BTFHeader = {};
463d15f96feSEduard Zingerman     BTFHeader.Magic = BTF::MAGIC;
464d15f96feSEduard Zingerman     BTFHeader.Version = 1;
465d15f96feSEduard Zingerman     BTFHeader.HdrLen = sizeof(BTFHeader);
466d15f96feSEduard Zingerman     BTFHeader.StrOff = 0;
467d15f96feSEduard Zingerman     BTFHeader.StrLen = Strings.size();
468d15f96feSEduard Zingerman     BTFHeader.TypeOff = Strings.size();
469d15f96feSEduard Zingerman     BTFHeader.TypeLen = Types.size();
470d15f96feSEduard Zingerman 
471d15f96feSEduard Zingerman     std::string BTFSec;
472d15f96feSEduard Zingerman     append(BTFSec, BTFHeader);
473d15f96feSEduard Zingerman     BTFSec.append(Strings);
474d15f96feSEduard Zingerman     BTFSec.append(Types);
475d15f96feSEduard Zingerman 
476d15f96feSEduard Zingerman     BTF::ExtHeader ExtHeader = {};
477d15f96feSEduard Zingerman     ExtHeader.Magic = BTF::MAGIC;
478d15f96feSEduard Zingerman     ExtHeader.Version = 1;
479d15f96feSEduard Zingerman     ExtHeader.HdrLen = sizeof(ExtHeader);
480d15f96feSEduard Zingerman     ExtHeader.FieldRelocOff = 0;
481d15f96feSEduard Zingerman     ExtHeader.FieldRelocLen = Relocs.size() + sizeof(uint32_t);
482d15f96feSEduard Zingerman     ExtHeader.LineInfoOff = ExtHeader.FieldRelocLen;
483d15f96feSEduard Zingerman     ExtHeader.LineInfoLen = Lines.size() + sizeof(uint32_t);
484d15f96feSEduard Zingerman 
485d15f96feSEduard Zingerman     std::string ExtSec;
486d15f96feSEduard Zingerman     append(ExtSec, ExtHeader);
487d15f96feSEduard Zingerman     append(ExtSec, (uint32_t)sizeof(BTF::BPFFieldReloc));
488d15f96feSEduard Zingerman     ExtSec.append(Relocs);
489d15f96feSEduard Zingerman     append(ExtSec, (uint32_t)sizeof(BTF::BPFLineInfo));
490d15f96feSEduard Zingerman     ExtSec.append(Lines);
491d15f96feSEduard Zingerman 
492d15f96feSEduard Zingerman     std::string YamlBuffer;
493d15f96feSEduard Zingerman     raw_string_ostream Yaml(YamlBuffer);
494d15f96feSEduard Zingerman     Yaml << R"(
495d15f96feSEduard Zingerman !ELF
496d15f96feSEduard Zingerman FileHeader:
497d15f96feSEduard Zingerman   Class:    ELFCLASS64)";
498d15f96feSEduard Zingerman     if (sys::IsBigEndianHost)
499d15f96feSEduard Zingerman       Yaml << "\n  Data:     ELFDATA2MSB";
500d15f96feSEduard Zingerman     else
501d15f96feSEduard Zingerman       Yaml << "\n  Data:     ELFDATA2LSB";
502d15f96feSEduard Zingerman     Yaml << R"(
503d15f96feSEduard Zingerman   Type:     ET_REL
504d15f96feSEduard Zingerman   Machine:  EM_BPF
505d15f96feSEduard Zingerman Sections:
506d15f96feSEduard Zingerman   - Name:     foo
507d15f96feSEduard Zingerman     Type:     SHT_PROGBITS
508d15f96feSEduard Zingerman     Size:     0x80
509d15f96feSEduard Zingerman   - Name:     bar
510d15f96feSEduard Zingerman     Type:     SHT_PROGBITS
511d15f96feSEduard Zingerman     Size:     0x80
512d15f96feSEduard Zingerman   - Name:     .BTF
513d15f96feSEduard Zingerman     Type:     SHT_PROGBITS
514d15f96feSEduard Zingerman     Content: )"
515d15f96feSEduard Zingerman          << makeBinRef(BTFSec.data(), BTFSec.size());
516d15f96feSEduard Zingerman     Yaml << R"(
517d15f96feSEduard Zingerman   - Name:     .BTF.ext
518d15f96feSEduard Zingerman     Type:     SHT_PROGBITS
519d15f96feSEduard Zingerman     Content: )"
520d15f96feSEduard Zingerman          << makeBinRef(ExtSec.data(), ExtSec.size());
521d15f96feSEduard Zingerman 
522d15f96feSEduard Zingerman     Obj = yaml::yaml2ObjectFile(ObjStorage, YamlBuffer,
523d15f96feSEduard Zingerman                                 [](const Twine &Err) { errs() << Err; });
524*75bc20ffSKazu Hirata     return *Obj;
525d15f96feSEduard Zingerman   }
526d15f96feSEduard Zingerman };
527d15f96feSEduard Zingerman 
TEST(BTFParserTest,allTypeKinds)528d15f96feSEduard Zingerman TEST(BTFParserTest, allTypeKinds) {
529d15f96feSEduard Zingerman   MockData2 D;
530d15f96feSEduard Zingerman   D.addType({D.addString("1"), mkInfo(BTF::BTF_KIND_INT), {4}});
531d15f96feSEduard Zingerman   D.addTail((uint32_t)0);
532d15f96feSEduard Zingerman   D.addType({D.addString("2"), mkInfo(BTF::BTF_KIND_PTR), {1}});
533d15f96feSEduard Zingerman   D.addType({D.addString("3"), mkInfo(BTF::BTF_KIND_ARRAY), {0}});
534d15f96feSEduard Zingerman   D.addTail(BTF::BTFArray({1, 1, 2}));
535d15f96feSEduard Zingerman   D.addType({D.addString("4"), mkInfo(BTF::BTF_KIND_STRUCT) | 2, {8}});
536d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("a"), 1, 0}));
537d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("b"), 1, 0}));
538d15f96feSEduard Zingerman   D.addType({D.addString("5"), mkInfo(BTF::BTF_KIND_UNION) | 3, {8}});
539d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("a"), 1, 0}));
540d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("b"), 1, 0}));
541d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("c"), 1, 0}));
542d15f96feSEduard Zingerman   D.addType({D.addString("6"), mkInfo(BTF::BTF_KIND_ENUM) | 2, {4}});
543d15f96feSEduard Zingerman   D.addTail(BTF::BTFEnum({D.addString("U"), 1}));
544d15f96feSEduard Zingerman   D.addTail(BTF::BTFEnum({D.addString("V"), 2}));
545d15f96feSEduard Zingerman   D.addType({D.addString("7"), mkInfo(BTF::BTF_KIND_ENUM64) | 1, {4}});
546d15f96feSEduard Zingerman   D.addTail(BTF::BTFEnum64({D.addString("W"), 0, 1}));
547d15f96feSEduard Zingerman   D.addType(
548d15f96feSEduard Zingerman       {D.addString("8"), BTF::FWD_UNION_FLAG | mkInfo(BTF::BTF_KIND_FWD), {0}});
549d15f96feSEduard Zingerman   D.addType({D.addString("9"), mkInfo(BTF::BTF_KIND_TYPEDEF), {1}});
550d15f96feSEduard Zingerman   D.addType({D.addString("10"), mkInfo(BTF::BTF_KIND_VOLATILE), {1}});
551d15f96feSEduard Zingerman   D.addType({D.addString("11"), mkInfo(BTF::BTF_KIND_CONST), {1}});
552d15f96feSEduard Zingerman   D.addType({D.addString("12"), mkInfo(BTF::BTF_KIND_RESTRICT), {1}});
553d15f96feSEduard Zingerman   D.addType({D.addString("13"), mkInfo(BTF::BTF_KIND_FUNC_PROTO) | 1, {1}});
554d15f96feSEduard Zingerman   D.addTail(BTF::BTFParam({D.addString("P"), 2}));
555d15f96feSEduard Zingerman   D.addType({D.addString("14"), mkInfo(BTF::BTF_KIND_FUNC), {13}});
556d15f96feSEduard Zingerman   D.addType({D.addString("15"), mkInfo(BTF::BTF_KIND_VAR), {2}});
557d15f96feSEduard Zingerman   D.addTail((uint32_t)0);
558d15f96feSEduard Zingerman   D.addType({D.addString("16"), mkInfo(BTF::BTF_KIND_DATASEC) | 3, {0}});
559d15f96feSEduard Zingerman   D.addTail(BTF::BTFDataSec({1, 0, 4}));
560d15f96feSEduard Zingerman   D.addTail(BTF::BTFDataSec({1, 4, 4}));
561d15f96feSEduard Zingerman   D.addTail(BTF::BTFDataSec({1, 8, 4}));
562d15f96feSEduard Zingerman   D.addType({D.addString("17"), mkInfo(BTF::BTF_KIND_FLOAT), {4}});
563d15f96feSEduard Zingerman   D.addType({D.addString("18"), mkInfo(BTF::BTF_KIND_DECL_TAG), {0}});
564d15f96feSEduard Zingerman   D.addTail((uint32_t)-1);
565d15f96feSEduard Zingerman   D.addType({D.addString("19"), mkInfo(BTF::BTF_KIND_TYPE_TAG), {0}});
566d15f96feSEduard Zingerman 
567d15f96feSEduard Zingerman   BTFParser BTF;
568d15f96feSEduard Zingerman   Error Err = BTF.parse(D.makeObj());
569d15f96feSEduard Zingerman   EXPECT_FALSE(Err);
570d15f96feSEduard Zingerman 
571d15f96feSEduard Zingerman   EXPECT_EQ(D.totalTypes() + 1 /* +1 for void */, BTF.typesCount());
572d15f96feSEduard Zingerman   for (unsigned Id = 1; Id < D.totalTypes() + 1; ++Id) {
573d15f96feSEduard Zingerman     const BTF::CommonType *Tp = BTF.findType(Id);
574d15f96feSEduard Zingerman     ASSERT_TRUE(Tp);
575d15f96feSEduard Zingerman     std::string IdBuf;
576d15f96feSEduard Zingerman     raw_string_ostream IdBufStream(IdBuf);
577d15f96feSEduard Zingerman     IdBufStream << Id;
578d15f96feSEduard Zingerman     EXPECT_EQ(BTF.findString(Tp->NameOff), IdBuf);
579d15f96feSEduard Zingerman   }
580d15f96feSEduard Zingerman }
581d15f96feSEduard Zingerman 
TEST(BTFParserTest,bigStruct)582d15f96feSEduard Zingerman TEST(BTFParserTest, bigStruct) {
583d15f96feSEduard Zingerman   const uint32_t N = 1000u;
584d15f96feSEduard Zingerman   MockData2 D;
585d15f96feSEduard Zingerman   uint32_t FStr = D.addString("f");
586d15f96feSEduard Zingerman   D.addType({D.addString("foo"), mkInfo(BTF::BTF_KIND_INT), {4}});
587d15f96feSEduard Zingerman   D.addTail((uint32_t)0);
588d15f96feSEduard Zingerman   D.addType({D.addString("big"), mkInfo(BTF::BTF_KIND_STRUCT) | N, {8}});
589d15f96feSEduard Zingerman   for (unsigned I = 0; I < N; ++I)
590d15f96feSEduard Zingerman     D.addTail(BTF::BTFMember({FStr, 1, 0}));
591d15f96feSEduard Zingerman   D.addType({D.addString("bar"), mkInfo(BTF::BTF_KIND_INT), {4}});
592d15f96feSEduard Zingerman   D.addTail((uint32_t)0);
593d15f96feSEduard Zingerman 
594d15f96feSEduard Zingerman   BTFParser BTF;
595d15f96feSEduard Zingerman   ASSERT_SUCCEEDED(BTF.parse(D.makeObj()));
596d15f96feSEduard Zingerman   ASSERT_EQ(BTF.typesCount(), 4u /* +1 for void */);
597d15f96feSEduard Zingerman   const BTF::CommonType *Foo = BTF.findType(1);
598d15f96feSEduard Zingerman   const BTF::CommonType *Big = BTF.findType(2);
599d15f96feSEduard Zingerman   const BTF::CommonType *Bar = BTF.findType(3);
600d15f96feSEduard Zingerman   ASSERT_TRUE(Foo);
601d15f96feSEduard Zingerman   ASSERT_TRUE(Big);
602d15f96feSEduard Zingerman   ASSERT_TRUE(Bar);
603d15f96feSEduard Zingerman   EXPECT_EQ(BTF.findString(Foo->NameOff), "foo");
604d15f96feSEduard Zingerman   EXPECT_EQ(BTF.findString(Big->NameOff), "big");
605d15f96feSEduard Zingerman   EXPECT_EQ(BTF.findString(Bar->NameOff), "bar");
606d15f96feSEduard Zingerman   EXPECT_EQ(Big->getVlen(), N);
607d15f96feSEduard Zingerman }
608d15f96feSEduard Zingerman 
TEST(BTFParserTest,incompleteTypes)609d15f96feSEduard Zingerman TEST(BTFParserTest, incompleteTypes) {
610d15f96feSEduard Zingerman   MockData2 D;
611d15f96feSEduard Zingerman   auto IncompleteType = [&](const BTF::CommonType &Tp) {
612d15f96feSEduard Zingerman     D.resetTypes();
613d15f96feSEduard Zingerman     D.addType(Tp);
614d15f96feSEduard Zingerman     EXPECT_PARSE_ERROR(D, "incomplete type definition in .BTF section");
615d15f96feSEduard Zingerman   };
616d15f96feSEduard Zingerman 
617d15f96feSEduard Zingerman   // All kinds that need tail.
618d15f96feSEduard Zingerman   IncompleteType({D.addString("a"), mkInfo(BTF::BTF_KIND_INT), {4}});
619d15f96feSEduard Zingerman   IncompleteType({D.addString("b"), mkInfo(BTF::BTF_KIND_ARRAY), {0}});
620d15f96feSEduard Zingerman   IncompleteType({D.addString("c"), mkInfo(BTF::BTF_KIND_VAR), {0}});
621d15f96feSEduard Zingerman   IncompleteType({D.addString("d"), mkInfo(BTF::BTF_KIND_DECL_TAG), {0}});
622d15f96feSEduard Zingerman 
623d15f96feSEduard Zingerman   // All kinds with vlen.
624d15f96feSEduard Zingerman   IncompleteType({D.addString("a"), mkInfo(BTF::BTF_KIND_STRUCT) | 2, {8}});
625d15f96feSEduard Zingerman   IncompleteType({D.addString("b"), mkInfo(BTF::BTF_KIND_UNION) | 3, {8}});
626d15f96feSEduard Zingerman   IncompleteType({D.addString("c"), mkInfo(BTF::BTF_KIND_ENUM) | 2, {4}});
627d15f96feSEduard Zingerman   IncompleteType({D.addString("d"), mkInfo(BTF::BTF_KIND_ENUM64) | 1, {4}});
628d15f96feSEduard Zingerman   IncompleteType({D.addString("e"), mkInfo(BTF::BTF_KIND_FUNC_PROTO) | 1, {1}});
629d15f96feSEduard Zingerman   IncompleteType({D.addString("f"), mkInfo(BTF::BTF_KIND_DATASEC) | 3, {0}});
630d15f96feSEduard Zingerman 
631d15f96feSEduard Zingerman   // An unexpected tail.
632d15f96feSEduard Zingerman   D.resetTypes();
633d15f96feSEduard Zingerman   D.addTail((uint32_t)0);
634d15f96feSEduard Zingerman   EXPECT_PARSE_ERROR(D, "incomplete type definition in .BTF section");
635d15f96feSEduard Zingerman }
636d15f96feSEduard Zingerman 
637d15f96feSEduard Zingerman // Use macro to preserve line number in error message.
638d15f96feSEduard Zingerman #define SYMBOLIZE(SecAddr, Expected)                                           \
639d15f96feSEduard Zingerman   do {                                                                         \
640d15f96feSEduard Zingerman     const BTF::BPFFieldReloc *R = BTF.findFieldReloc((SecAddr));               \
641d15f96feSEduard Zingerman     ASSERT_TRUE(R);                                                            \
642d15f96feSEduard Zingerman     SmallString<64> Symbolized;                                                \
643d15f96feSEduard Zingerman     BTF.symbolize(R, Symbolized);                                              \
644d15f96feSEduard Zingerman     EXPECT_EQ(Symbolized, (Expected));                                         \
645d15f96feSEduard Zingerman   } while (false)
646d15f96feSEduard Zingerman 
647d15f96feSEduard Zingerman // Shorter name for initializers below.
648d15f96feSEduard Zingerman using SA = SectionedAddress;
649d15f96feSEduard Zingerman 
TEST(BTFParserTest,typeRelocs)650d15f96feSEduard Zingerman TEST(BTFParserTest, typeRelocs) {
651d15f96feSEduard Zingerman   MockData2 D;
652d15f96feSEduard Zingerman   uint32_t Zero = D.addString("0");
653d15f96feSEduard Zingerman   // id 1: struct foo {}
654d15f96feSEduard Zingerman   // id 2: union bar;
655d15f96feSEduard Zingerman   // id 3: struct buz;
656d15f96feSEduard Zingerman   D.addType({D.addString("foo"), mkInfo(BTF::BTF_KIND_STRUCT), {0}});
657d15f96feSEduard Zingerman   D.addType({D.addString("bar"),
658d15f96feSEduard Zingerman              mkInfo(BTF::BTF_KIND_FWD) | BTF::FWD_UNION_FLAG,
659d15f96feSEduard Zingerman              {0}});
660d15f96feSEduard Zingerman   D.addType({D.addString("buz"), mkInfo(BTF::BTF_KIND_FWD), {0}});
661d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 7});
662d15f96feSEduard Zingerman   // List of all possible correct type relocations for type id #1.
663d15f96feSEduard Zingerman   D.addReloc({0, 1, Zero, BTF::BTF_TYPE_ID_LOCAL});
664d15f96feSEduard Zingerman   D.addReloc({8, 1, Zero, BTF::BTF_TYPE_ID_REMOTE});
665d15f96feSEduard Zingerman   D.addReloc({16, 1, Zero, BTF::TYPE_EXISTENCE});
666d15f96feSEduard Zingerman   D.addReloc({24, 1, Zero, BTF::TYPE_MATCH});
667d15f96feSEduard Zingerman   D.addReloc({32, 1, Zero, BTF::TYPE_SIZE});
668d15f96feSEduard Zingerman   // Forward declarations.
669d15f96feSEduard Zingerman   D.addReloc({40, 2, Zero, BTF::TYPE_SIZE});
670d15f96feSEduard Zingerman   D.addReloc({48, 3, Zero, BTF::TYPE_SIZE});
671d15f96feSEduard Zingerman   // Incorrect type relocation: bad type id.
672d15f96feSEduard Zingerman   D.addReloc({56, 42, Zero, BTF::TYPE_SIZE});
673d15f96feSEduard Zingerman   // Incorrect type relocation: spec should be '0'.
674d15f96feSEduard Zingerman   D.addReloc({64, 1, D.addString("10"), BTF::TYPE_SIZE});
675d15f96feSEduard Zingerman 
676d15f96feSEduard Zingerman   BTFParser BTF;
677d15f96feSEduard Zingerman   Error E = BTF.parse(D.makeObj());
678d15f96feSEduard Zingerman   EXPECT_FALSE(E);
679d15f96feSEduard Zingerman 
680d15f96feSEduard Zingerman   SYMBOLIZE(SA({0, 1}), "<local_type_id> [1] struct foo");
681d15f96feSEduard Zingerman   SYMBOLIZE(SA({8, 1}), "<target_type_id> [1] struct foo");
682d15f96feSEduard Zingerman   SYMBOLIZE(SA({16, 1}), "<type_exists> [1] struct foo");
683d15f96feSEduard Zingerman   SYMBOLIZE(SA({24, 1}), "<type_matches> [1] struct foo");
684d15f96feSEduard Zingerman   SYMBOLIZE(SA({32, 1}), "<type_size> [1] struct foo");
685d15f96feSEduard Zingerman   SYMBOLIZE(SA({40, 1}), "<type_size> [2] fwd union bar");
686d15f96feSEduard Zingerman   SYMBOLIZE(SA({48, 1}), "<type_size> [3] fwd struct buz");
687d15f96feSEduard Zingerman   SYMBOLIZE(SA({56, 1}), "<type_size> [42] '0' <unknown type id: 42>");
688d15f96feSEduard Zingerman   SYMBOLIZE(SA({64, 1}),
689d15f96feSEduard Zingerman             "<type_size> [1] '10' "
690d15f96feSEduard Zingerman             "<unexpected type-based relocation spec: should be '0'>");
691d15f96feSEduard Zingerman }
692d15f96feSEduard Zingerman 
TEST(BTFParserTest,enumRelocs)693d15f96feSEduard Zingerman TEST(BTFParserTest, enumRelocs) {
694d15f96feSEduard Zingerman   MockData2 D;
695d15f96feSEduard Zingerman   // id 1: enum { U, V }
696d15f96feSEduard Zingerman   D.addType({D.addString("foo"), mkInfo(BTF::BTF_KIND_ENUM) | 2, {4}});
697d15f96feSEduard Zingerman   D.addTail(BTF::BTFEnum({D.addString("U"), 1}));
698d15f96feSEduard Zingerman   D.addTail(BTF::BTFEnum({D.addString("V"), 2}));
699d15f96feSEduard Zingerman   // id 2: int
700d15f96feSEduard Zingerman   D.addType({D.addString("int"), mkInfo(BTF::BTF_KIND_INT), {4}});
701d15f96feSEduard Zingerman   D.addTail((uint32_t)0);
702d15f96feSEduard Zingerman   // id 3: enum: uint64_t { A, B }
703d15f96feSEduard Zingerman   D.addType({D.addString("bar"), mkInfo(BTF::BTF_KIND_ENUM64) | 2, {8}});
704d15f96feSEduard Zingerman   D.addTail(BTF::BTFEnum64({D.addString("A"), 1, 0}));
705d15f96feSEduard Zingerman   D.addTail(BTF::BTFEnum64({D.addString("B"), 2, 0}));
706d15f96feSEduard Zingerman 
707d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 5});
708d15f96feSEduard Zingerman   // An ok relocation accessing value #1: U.
709d15f96feSEduard Zingerman   D.addReloc({0, 1, D.addString("0"), BTF::ENUM_VALUE_EXISTENCE});
710d15f96feSEduard Zingerman   // An ok relocation accessing value #2: V.
711d15f96feSEduard Zingerman   D.addReloc({8, 1, D.addString("1"), BTF::ENUM_VALUE});
712d15f96feSEduard Zingerman   // Incorrect relocation: too many elements in string "1:0".
713d15f96feSEduard Zingerman   D.addReloc({16, 1, D.addString("1:0"), BTF::ENUM_VALUE});
714d15f96feSEduard Zingerman   // Incorrect relocation: type id "2" is not an enum.
715d15f96feSEduard Zingerman   D.addReloc({24, 2, D.addString("1"), BTF::ENUM_VALUE});
716d15f96feSEduard Zingerman   // Incorrect relocation: value #42 does not exist for enum "foo".
717d15f96feSEduard Zingerman   D.addReloc({32, 1, D.addString("42"), BTF::ENUM_VALUE});
718d15f96feSEduard Zingerman   // An ok relocation accessing value #1: A.
719d15f96feSEduard Zingerman   D.addReloc({40, 3, D.addString("0"), BTF::ENUM_VALUE_EXISTENCE});
720d15f96feSEduard Zingerman   // An ok relocation accessing value #2: B.
721d15f96feSEduard Zingerman   D.addReloc({48, 3, D.addString("1"), BTF::ENUM_VALUE});
722d15f96feSEduard Zingerman 
723d15f96feSEduard Zingerman   BTFParser BTF;
724d15f96feSEduard Zingerman   Error E = BTF.parse(D.makeObj());
725d15f96feSEduard Zingerman   EXPECT_FALSE(E);
726d15f96feSEduard Zingerman 
727d15f96feSEduard Zingerman   SYMBOLIZE(SA({0, 1}), "<enumval_exists> [1] enum foo::U = 1");
728d15f96feSEduard Zingerman   SYMBOLIZE(SA({8, 1}), "<enumval_value> [1] enum foo::V = 2");
729d15f96feSEduard Zingerman   SYMBOLIZE(
730d15f96feSEduard Zingerman       SA({16, 1}),
731d15f96feSEduard Zingerman       "<enumval_value> [1] '1:0' <unexpected enumval relocation spec size>");
732d15f96feSEduard Zingerman   SYMBOLIZE(
733d15f96feSEduard Zingerman       SA({24, 1}),
734d15f96feSEduard Zingerman       "<enumval_value> [2] '1' <unexpected type kind for enum relocation: 1>");
735d15f96feSEduard Zingerman   SYMBOLIZE(SA({32, 1}), "<enumval_value> [1] '42' <bad value index: 42>");
736d15f96feSEduard Zingerman   SYMBOLIZE(SA({40, 1}), "<enumval_exists> [3] enum bar::A = 1");
737d15f96feSEduard Zingerman   SYMBOLIZE(SA({48, 1}), "<enumval_value> [3] enum bar::B = 2");
738d15f96feSEduard Zingerman }
739d15f96feSEduard Zingerman 
TEST(BTFParserTest,enumRelocsMods)740d15f96feSEduard Zingerman TEST(BTFParserTest, enumRelocsMods) {
741d15f96feSEduard Zingerman   MockData2 D;
742d15f96feSEduard Zingerman   // id 1: enum { U, V }
743d15f96feSEduard Zingerman   D.addType({D.addString("foo"), mkInfo(BTF::BTF_KIND_ENUM) | 2, {4}});
744d15f96feSEduard Zingerman   D.addTail(BTF::BTFEnum({D.addString("U"), 1}));
745d15f96feSEduard Zingerman   D.addTail(BTF::BTFEnum({D.addString("V"), 2}));
746d15f96feSEduard Zingerman   // id 2: typedef enum foo a;
747d15f96feSEduard Zingerman   D.addType({D.addString("a"), mkInfo(BTF::BTF_KIND_TYPEDEF), {1}});
748d15f96feSEduard Zingerman   // id 3: const enum foo;
749d15f96feSEduard Zingerman   D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_CONST), {1}});
750d15f96feSEduard Zingerman 
751d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 0});
752d15f96feSEduard Zingerman   D.addReloc({0, 2, D.addString("0"), BTF::ENUM_VALUE});
753d15f96feSEduard Zingerman   D.addReloc({8, 3, D.addString("1"), BTF::ENUM_VALUE});
754d15f96feSEduard Zingerman 
755d15f96feSEduard Zingerman   BTFParser BTF;
756d15f96feSEduard Zingerman   Error E = BTF.parse(D.makeObj());
757d15f96feSEduard Zingerman   EXPECT_FALSE(E);
758d15f96feSEduard Zingerman 
759d15f96feSEduard Zingerman   SYMBOLIZE(SA({0, 1}), "<enumval_value> [2] typedef a::U = 1");
760d15f96feSEduard Zingerman   SYMBOLIZE(SA({8, 1}), "<enumval_value> [3] const enum foo::V = 2");
761d15f96feSEduard Zingerman }
762d15f96feSEduard Zingerman 
TEST(BTFParserTest,fieldRelocs)763d15f96feSEduard Zingerman TEST(BTFParserTest, fieldRelocs) {
764d15f96feSEduard Zingerman   MockData2 D;
765d15f96feSEduard Zingerman   // id 1: int
766d15f96feSEduard Zingerman   D.addType({D.addString("int"), mkInfo(BTF::BTF_KIND_INT), {4}});
767d15f96feSEduard Zingerman   D.addTail((uint32_t)0);
768d15f96feSEduard Zingerman   // id 2: struct foo { int a; int b; }
769d15f96feSEduard Zingerman   D.addType({D.addString("foo"), mkInfo(BTF::BTF_KIND_STRUCT) | 2, {8}});
770d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("a"), 1, 0}));
771d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("b"), 1, 0}));
772d15f96feSEduard Zingerman   // id 3: array of struct foo.
773d15f96feSEduard Zingerman   D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_ARRAY), {0}});
774d15f96feSEduard Zingerman   D.addTail(BTF::BTFArray({2, 1, 2}));
775d15f96feSEduard Zingerman   // id 4: struct bar { struct foo u[2]; int v; }
776d15f96feSEduard Zingerman   D.addType({D.addString("bar"), mkInfo(BTF::BTF_KIND_STRUCT) | 2, {8}});
777d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("u"), 3, 0}));
778d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("v"), 1, 0}));
779d15f96feSEduard Zingerman   // id 5: array with bad element type id.
780d15f96feSEduard Zingerman   D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_ARRAY), {0}});
781d15f96feSEduard Zingerman   D.addTail(BTF::BTFArray({42, 1, 2}));
782d15f96feSEduard Zingerman   // id 6: struct buz { <bad type> u[2]; <bad type> v; }
783d15f96feSEduard Zingerman   D.addType({D.addString("bar"), mkInfo(BTF::BTF_KIND_STRUCT) | 2, {8}});
784d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("u"), 5, 0}));
785d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("v"), 42, 0}));
786d15f96feSEduard Zingerman 
787d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 0 /* patched automatically */});
788d15f96feSEduard Zingerman   // All field relocations kinds for struct bar::v.
789d15f96feSEduard Zingerman   D.addReloc({0, 4, D.addString("0:1"), BTF::FIELD_BYTE_OFFSET});
790d15f96feSEduard Zingerman   D.addReloc({8, 4, D.addString("0:1"), BTF::FIELD_BYTE_SIZE});
791d15f96feSEduard Zingerman   D.addReloc({16, 4, D.addString("0:1"), BTF::FIELD_EXISTENCE});
792d15f96feSEduard Zingerman   D.addReloc({24, 4, D.addString("0:1"), BTF::FIELD_SIGNEDNESS});
793d15f96feSEduard Zingerman   D.addReloc({32, 4, D.addString("0:1"), BTF::FIELD_LSHIFT_U64});
794d15f96feSEduard Zingerman   D.addReloc({40, 4, D.addString("0:1"), BTF::FIELD_RSHIFT_U64});
795d15f96feSEduard Zingerman   // Non-zero first idx.
796d15f96feSEduard Zingerman   D.addReloc({48, 4, D.addString("7:1"), BTF::FIELD_BYTE_OFFSET});
797d15f96feSEduard Zingerman   // Access through array and struct: struct bar::u[1].a.
798d15f96feSEduard Zingerman   D.addReloc({56, 4, D.addString("0:0:1:0"), BTF::FIELD_BYTE_OFFSET});
799d15f96feSEduard Zingerman   // Access through array and struct: struct bar::u[1].b.
800d15f96feSEduard Zingerman   D.addReloc({64, 4, D.addString("0:0:1:1"), BTF::FIELD_BYTE_OFFSET});
801d15f96feSEduard Zingerman   // Incorrect relocation: empty access string.
802d15f96feSEduard Zingerman   D.addReloc({72, 4, D.addString(""), BTF::FIELD_BYTE_OFFSET});
803d15f96feSEduard Zingerman   // Incorrect relocation: member index out of range (only two members in bar).
804d15f96feSEduard Zingerman   D.addReloc({80, 4, D.addString("0:2"), BTF::FIELD_BYTE_OFFSET});
805d15f96feSEduard Zingerman   // Incorrect relocation: unknown element type id (buz::u[0] access).
806d15f96feSEduard Zingerman   D.addReloc({88, 6, D.addString("0:0:0"), BTF::FIELD_BYTE_OFFSET});
807d15f96feSEduard Zingerman   // Incorrect relocation: unknown member type id (buz::v access).
808d15f96feSEduard Zingerman   D.addReloc({96, 6, D.addString("0:1:0"), BTF::FIELD_BYTE_OFFSET});
809d15f96feSEduard Zingerman   // Incorrect relocation: non structural type in the middle of access string
810d15f96feSEduard Zingerman   //   struct bar::v.<something>.
811d15f96feSEduard Zingerman   D.addReloc({104, 4, D.addString("0:1:0"), BTF::FIELD_BYTE_OFFSET});
812d15f96feSEduard Zingerman 
813d15f96feSEduard Zingerman   BTFParser BTF;
814d15f96feSEduard Zingerman   Error E = BTF.parse(D.makeObj());
815d15f96feSEduard Zingerman   EXPECT_FALSE(E);
816d15f96feSEduard Zingerman 
817d15f96feSEduard Zingerman   SYMBOLIZE(SA({0, 1}), "<byte_off> [4] struct bar::v (0:1)");
818d15f96feSEduard Zingerman   SYMBOLIZE(SA({8, 1}), "<byte_sz> [4] struct bar::v (0:1)");
819d15f96feSEduard Zingerman   SYMBOLIZE(SA({16, 1}), "<field_exists> [4] struct bar::v (0:1)");
820d15f96feSEduard Zingerman   SYMBOLIZE(SA({24, 1}), "<signed> [4] struct bar::v (0:1)");
821d15f96feSEduard Zingerman   SYMBOLIZE(SA({32, 1}), "<lshift_u64> [4] struct bar::v (0:1)");
822d15f96feSEduard Zingerman   SYMBOLIZE(SA({40, 1}), "<rshift_u64> [4] struct bar::v (0:1)");
823d15f96feSEduard Zingerman   SYMBOLIZE(SA({48, 1}), "<byte_off> [4] struct bar::[7].v (7:1)");
824d15f96feSEduard Zingerman   SYMBOLIZE(SA({56, 1}), "<byte_off> [4] struct bar::u[1].a (0:0:1:0)");
825d15f96feSEduard Zingerman   SYMBOLIZE(SA({64, 1}), "<byte_off> [4] struct bar::u[1].b (0:0:1:1)");
826d15f96feSEduard Zingerman   SYMBOLIZE(SA({72, 1}), "<byte_off> [4] '' <field spec too short>");
827d15f96feSEduard Zingerman   SYMBOLIZE(SA({80, 1}),
828d15f96feSEduard Zingerman             "<byte_off> [4] '0:2' "
829d15f96feSEduard Zingerman             "<member index 2 for spec sub-string 1 is out of range>");
830d15f96feSEduard Zingerman   SYMBOLIZE(SA({88, 1}), "<byte_off> [6] '0:0:0' "
831d15f96feSEduard Zingerman                          "<unknown element type id 42 for spec sub-string 2>");
832d15f96feSEduard Zingerman   SYMBOLIZE(SA({96, 1}), "<byte_off> [6] '0:1:0' "
833d15f96feSEduard Zingerman                          "<unknown member type id 42 for spec sub-string 1>");
834d15f96feSEduard Zingerman   SYMBOLIZE(SA({104, 1}), "<byte_off> [4] '0:1:0' "
835d15f96feSEduard Zingerman                           "<unexpected type kind 1 for spec sub-string 2>");
836d15f96feSEduard Zingerman }
837d15f96feSEduard Zingerman 
TEST(BTFParserTest,fieldRelocsMods)838d15f96feSEduard Zingerman TEST(BTFParserTest, fieldRelocsMods) {
839d15f96feSEduard Zingerman   MockData2 D;
840d15f96feSEduard Zingerman   // struct foo {
841d15f96feSEduard Zingerman   //   int u;
842d15f96feSEduard Zingerman   // }
843d15f96feSEduard Zingerman   // typedef struct foo bar;
844d15f96feSEduard Zingerman   // struct buz {
845d15f96feSEduard Zingerman   //   const bar v;
846d15f96feSEduard Zingerman   // }
847d15f96feSEduard Zingerman   // typedef buz quux;
848d15f96feSEduard Zingerman   // const volatile restrict quux <some-var>;
849d15f96feSEduard Zingerman   uint32_t Int =
850d15f96feSEduard Zingerman       D.addType({D.addString("int"), mkInfo(BTF::BTF_KIND_INT), {4}});
851d15f96feSEduard Zingerman   D.addTail((uint32_t)0);
852d15f96feSEduard Zingerman   uint32_t Foo =
853d15f96feSEduard Zingerman       D.addType({D.addString("foo"), mkInfo(BTF::BTF_KIND_STRUCT) | 1, {4}});
854d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("u"), Int, 0}));
855d15f96feSEduard Zingerman   uint32_t Bar =
856d15f96feSEduard Zingerman       D.addType({D.addString("bar"), mkInfo(BTF::BTF_KIND_TYPEDEF), {Foo}});
857d15f96feSEduard Zingerman   uint32_t CBar =
858d15f96feSEduard Zingerman       D.addType({D.addString("bar"), mkInfo(BTF::BTF_KIND_CONST), {Bar}});
859d15f96feSEduard Zingerman   uint32_t Buz =
860d15f96feSEduard Zingerman       D.addType({D.addString("buz"), mkInfo(BTF::BTF_KIND_STRUCT) | 1, {4}});
861d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString("v"), CBar, 0}));
862d15f96feSEduard Zingerman   uint32_t Quux =
863d15f96feSEduard Zingerman       D.addType({D.addString("quux"), mkInfo(BTF::BTF_KIND_TYPEDEF), {Buz}});
864d15f96feSEduard Zingerman   uint32_t RQuux =
865d15f96feSEduard Zingerman       D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_RESTRICT), {Quux}});
866d15f96feSEduard Zingerman   uint32_t VRQuux =
867d15f96feSEduard Zingerman       D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_VOLATILE), {RQuux}});
868d15f96feSEduard Zingerman   uint32_t CVRQuux =
869d15f96feSEduard Zingerman       D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_CONST), {VRQuux}});
870d15f96feSEduard Zingerman   uint32_t CUnknown =
871d15f96feSEduard Zingerman       D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_CONST), {77}});
872d15f96feSEduard Zingerman   uint32_t CVUnknown =
873d15f96feSEduard Zingerman       D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_VOLATILE), {CUnknown}});
874d15f96feSEduard Zingerman 
875d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 0});
876d15f96feSEduard Zingerman   D.addReloc({0, Bar, D.addString("0:0"), BTF::FIELD_BYTE_OFFSET});
877d15f96feSEduard Zingerman   D.addReloc({8, CVRQuux, D.addString("0:0:0"), BTF::FIELD_BYTE_OFFSET});
878d15f96feSEduard Zingerman   D.addReloc({16, CVUnknown, D.addString("0:1:2"), BTF::FIELD_BYTE_OFFSET});
879d15f96feSEduard Zingerman 
880d15f96feSEduard Zingerman   BTFParser BTF;
881d15f96feSEduard Zingerman   Error E = BTF.parse(D.makeObj());
882d15f96feSEduard Zingerman   EXPECT_FALSE(E);
883d15f96feSEduard Zingerman 
884d15f96feSEduard Zingerman   // Should show modifiers / name of typedef.
885d15f96feSEduard Zingerman   SYMBOLIZE(SA({0, 1}), "<byte_off> [3] typedef bar::u (0:0)");
886d15f96feSEduard Zingerman   SYMBOLIZE(SA({8, 1}),
887d15f96feSEduard Zingerman             "<byte_off> [9] const volatile restrict typedef quux::v.u (0:0:0)");
888d15f96feSEduard Zingerman   SYMBOLIZE(SA({16, 1}),
889d15f96feSEduard Zingerman             "<byte_off> [11] '0:1:2' <unknown type id: 77 in modifiers chain>");
890d15f96feSEduard Zingerman }
891d15f96feSEduard Zingerman 
TEST(BTFParserTest,relocTypeTagAndVoid)892d15f96feSEduard Zingerman TEST(BTFParserTest, relocTypeTagAndVoid) {
893d15f96feSEduard Zingerman   MockData2 D;
894d15f96feSEduard Zingerman   // __attribute__((type_tag("tag"))) void
895d15f96feSEduard Zingerman   uint32_t Tag =
896d15f96feSEduard Zingerman       D.addType({D.addString("tag"), mkInfo(BTF::BTF_KIND_TYPE_TAG), {0}});
897d15f96feSEduard Zingerman 
898d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 0});
899d15f96feSEduard Zingerman   D.addReloc({0, Tag, D.addString("0"), BTF::TYPE_EXISTENCE});
900d15f96feSEduard Zingerman   D.addReloc({8, 0 /* void */, D.addString("0"), BTF::TYPE_EXISTENCE});
901d15f96feSEduard Zingerman 
902d15f96feSEduard Zingerman   BTFParser BTF;
903d15f96feSEduard Zingerman   Error E = BTF.parse(D.makeObj());
904d15f96feSEduard Zingerman   EXPECT_FALSE(E);
905d15f96feSEduard Zingerman 
906d15f96feSEduard Zingerman   SYMBOLIZE(SA({0, 1}), "<type_exists> [1] type_tag(\"tag\") void");
907d15f96feSEduard Zingerman   SYMBOLIZE(SA({8, 1}), "<type_exists> [0] void");
908d15f96feSEduard Zingerman }
909d15f96feSEduard Zingerman 
TEST(BTFParserTest,longRelocModifiersCycle)910d15f96feSEduard Zingerman TEST(BTFParserTest, longRelocModifiersCycle) {
911d15f96feSEduard Zingerman   MockData2 D;
912d15f96feSEduard Zingerman 
913d15f96feSEduard Zingerman   D.addType(
914d15f96feSEduard Zingerman       {D.addString(""), mkInfo(BTF::BTF_KIND_CONST), {1 /* ourselves */}});
915d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 0});
916d15f96feSEduard Zingerman   D.addReloc({0, 1, D.addString(""), BTF::TYPE_EXISTENCE});
917d15f96feSEduard Zingerman 
918d15f96feSEduard Zingerman   BTFParser BTF;
919d15f96feSEduard Zingerman   Error E = BTF.parse(D.makeObj());
920d15f96feSEduard Zingerman   EXPECT_FALSE(E);
921d15f96feSEduard Zingerman 
922d15f96feSEduard Zingerman   SYMBOLIZE(SA({0, 1}), "<type_exists> [1] '' <modifiers chain is too long>");
923d15f96feSEduard Zingerman }
924d15f96feSEduard Zingerman 
TEST(BTFParserTest,relocAnonFieldsAndTypes)925d15f96feSEduard Zingerman TEST(BTFParserTest, relocAnonFieldsAndTypes) {
926d15f96feSEduard Zingerman   MockData2 D;
927d15f96feSEduard Zingerman 
928d15f96feSEduard Zingerman   // struct {
929d15f96feSEduard Zingerman   //   int :32;
930d15f96feSEduard Zingerman   // } v;
931d15f96feSEduard Zingerman   uint32_t Int =
932d15f96feSEduard Zingerman       D.addType({D.addString("int"), mkInfo(BTF::BTF_KIND_INT), {4}});
933d15f96feSEduard Zingerman   D.addTail((uint32_t)0);
934d15f96feSEduard Zingerman   uint32_t Anon =
935d15f96feSEduard Zingerman       D.addType({D.addString(""), mkInfo(BTF::BTF_KIND_STRUCT) | 1, {4}});
936d15f96feSEduard Zingerman   D.addTail(BTF::BTFMember({D.addString(""), Int, 0}));
937d15f96feSEduard Zingerman 
938d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 0});
939d15f96feSEduard Zingerman   D.addReloc({0, Anon, D.addString("0"), BTF::TYPE_EXISTENCE});
940d15f96feSEduard Zingerman   D.addReloc({8, Anon, D.addString("0:0"), BTF::FIELD_BYTE_OFFSET});
941d15f96feSEduard Zingerman 
942d15f96feSEduard Zingerman   BTFParser BTF;
943d15f96feSEduard Zingerman   Error E = BTF.parse(D.makeObj());
944d15f96feSEduard Zingerman   EXPECT_FALSE(E);
945d15f96feSEduard Zingerman 
946d15f96feSEduard Zingerman   SYMBOLIZE(SA({0, 1}), "<type_exists> [2] struct <anon 2>");
947d15f96feSEduard Zingerman   SYMBOLIZE(SA({8, 1}), "<byte_off> [2] struct <anon 2>::<anon 0> (0:0)");
948d15f96feSEduard Zingerman }
949d15f96feSEduard Zingerman 
TEST(BTFParserTest,miscBadRelos)950d15f96feSEduard Zingerman TEST(BTFParserTest, miscBadRelos) {
951d15f96feSEduard Zingerman   MockData2 D;
952d15f96feSEduard Zingerman 
953d15f96feSEduard Zingerman   uint32_t S = D.addType({D.addString("S"), mkInfo(BTF::BTF_KIND_STRUCT), {0}});
954d15f96feSEduard Zingerman 
955d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 0});
956d15f96feSEduard Zingerman   D.addReloc({0, 0, D.addString(""), 777});
957d15f96feSEduard Zingerman   D.addReloc({8, S, D.addString("abc"), BTF::FIELD_BYTE_OFFSET});
958d15f96feSEduard Zingerman   D.addReloc({16, S, D.addString("0#"), BTF::FIELD_BYTE_OFFSET});
959d15f96feSEduard Zingerman 
960d15f96feSEduard Zingerman   BTFParser BTF;
961d15f96feSEduard Zingerman   Error E = BTF.parse(D.makeObj());
962d15f96feSEduard Zingerman   EXPECT_FALSE(E);
963d15f96feSEduard Zingerman 
964d15f96feSEduard Zingerman   SYMBOLIZE(SA({0, 1}),
965d15f96feSEduard Zingerman             "<reloc kind #777> [0] '' <unknown relocation kind: 777>");
966d15f96feSEduard Zingerman   SYMBOLIZE(SA({8, 1}), "<byte_off> [1] 'abc' <spec string is not a number>");
967d15f96feSEduard Zingerman   SYMBOLIZE(SA({16, 1}),
968d15f96feSEduard Zingerman             "<byte_off> [1] '0#' <unexpected spec string delimiter: '#'>");
969d15f96feSEduard Zingerman }
970d15f96feSEduard Zingerman 
TEST(BTFParserTest,relocsMultipleSections)971d15f96feSEduard Zingerman TEST(BTFParserTest, relocsMultipleSections) {
972d15f96feSEduard Zingerman   MockData2 D;
973d15f96feSEduard Zingerman 
974d15f96feSEduard Zingerman   uint32_t S = D.addType({D.addString("S"), mkInfo(BTF::BTF_KIND_STRUCT), {0}});
975d15f96feSEduard Zingerman   uint32_t T = D.addType({D.addString("T"), mkInfo(BTF::BTF_KIND_STRUCT), {0}});
976d15f96feSEduard Zingerman 
977d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 0});
978d15f96feSEduard Zingerman   D.addReloc({0, S, D.addString(""), BTF::TYPE_EXISTENCE});
979d15f96feSEduard Zingerman   D.addReloc({8, S, D.addString(""), BTF::TYPE_EXISTENCE});
980d15f96feSEduard Zingerman 
981d15f96feSEduard Zingerman   D.addRelocSec({D.addString("bar"), 0});
982d15f96feSEduard Zingerman   D.addReloc({8, T, D.addString(""), BTF::TYPE_EXISTENCE});
983d15f96feSEduard Zingerman   D.addReloc({16, T, D.addString(""), BTF::TYPE_EXISTENCE});
984d15f96feSEduard Zingerman 
985d15f96feSEduard Zingerman   BTFParser BTF;
986d15f96feSEduard Zingerman   Error E = BTF.parse(D.makeObj());
987d15f96feSEduard Zingerman   EXPECT_FALSE(E);
988d15f96feSEduard Zingerman 
989d15f96feSEduard Zingerman   EXPECT_TRUE(BTF.findFieldReloc({0, 1}));
990d15f96feSEduard Zingerman   EXPECT_TRUE(BTF.findFieldReloc({8, 1}));
991d15f96feSEduard Zingerman   EXPECT_FALSE(BTF.findFieldReloc({16, 1}));
992d15f96feSEduard Zingerman 
993d15f96feSEduard Zingerman   EXPECT_FALSE(BTF.findFieldReloc({0, 2}));
994d15f96feSEduard Zingerman   EXPECT_TRUE(BTF.findFieldReloc({8, 2}));
995d15f96feSEduard Zingerman   EXPECT_TRUE(BTF.findFieldReloc({16, 2}));
996d15f96feSEduard Zingerman 
997d15f96feSEduard Zingerman   EXPECT_FALSE(BTF.findFieldReloc({0, 3}));
998d15f96feSEduard Zingerman   EXPECT_FALSE(BTF.findFieldReloc({8, 3}));
999d15f96feSEduard Zingerman   EXPECT_FALSE(BTF.findFieldReloc({16, 3}));
1000d15f96feSEduard Zingerman 
1001d15f96feSEduard Zingerman   auto AssertReloType = [&](const SectionedAddress &A, const char *Name) {
1002d15f96feSEduard Zingerman     const BTF::BPFFieldReloc *Relo = BTF.findFieldReloc(A);
1003d15f96feSEduard Zingerman     ASSERT_TRUE(Relo);
1004d15f96feSEduard Zingerman     const BTF::CommonType *Type = BTF.findType(Relo->TypeID);
1005d15f96feSEduard Zingerman     ASSERT_TRUE(Type);
1006d15f96feSEduard Zingerman     EXPECT_EQ(BTF.findString(Type->NameOff), Name);
1007d15f96feSEduard Zingerman   };
1008d15f96feSEduard Zingerman 
1009d15f96feSEduard Zingerman   AssertReloType({8, 1}, "S");
1010d15f96feSEduard Zingerman   AssertReloType({8, 2}, "T");
1011d15f96feSEduard Zingerman }
1012d15f96feSEduard Zingerman 
TEST(BTFParserTest,parserResetReloAndTypes)1013d15f96feSEduard Zingerman TEST(BTFParserTest, parserResetReloAndTypes) {
1014d15f96feSEduard Zingerman   BTFParser BTF;
1015d15f96feSEduard Zingerman   MockData2 D;
1016d15f96feSEduard Zingerman 
1017d15f96feSEduard Zingerman   // First time: two types, two relocations.
1018d15f96feSEduard Zingerman   D.addType({D.addString("foo"), mkInfo(BTF::BTF_KIND_STRUCT), {0}});
1019d15f96feSEduard Zingerman   D.addType({D.addString("bar"), mkInfo(BTF::BTF_KIND_STRUCT), {0}});
1020d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 0});
1021d15f96feSEduard Zingerman   D.addReloc({0, 1, D.addString(""), BTF::TYPE_EXISTENCE});
1022d15f96feSEduard Zingerman   D.addReloc({8, 2, D.addString(""), BTF::TYPE_EXISTENCE});
1023d15f96feSEduard Zingerman 
1024d15f96feSEduard Zingerman   Error E1 = BTF.parse(D.makeObj());
1025d15f96feSEduard Zingerman   EXPECT_FALSE(E1);
1026d15f96feSEduard Zingerman 
1027d15f96feSEduard Zingerman   ASSERT_TRUE(BTF.findType(1));
1028d15f96feSEduard Zingerman   EXPECT_EQ(BTF.findString(BTF.findType(1)->NameOff), "foo");
1029d15f96feSEduard Zingerman   EXPECT_TRUE(BTF.findType(2));
1030d15f96feSEduard Zingerman   EXPECT_TRUE(BTF.findFieldReloc({0, 1}));
1031d15f96feSEduard Zingerman   EXPECT_TRUE(BTF.findFieldReloc({8, 1}));
1032d15f96feSEduard Zingerman 
1033d15f96feSEduard Zingerman   // Second time: one type, one relocation.
1034d15f96feSEduard Zingerman   D.reset();
1035d15f96feSEduard Zingerman   D.addType({D.addString("buz"), mkInfo(BTF::BTF_KIND_STRUCT), {0}});
1036d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 0});
1037d15f96feSEduard Zingerman   D.addReloc({0, 1, D.addString(""), BTF::TYPE_EXISTENCE});
1038d15f96feSEduard Zingerman 
1039d15f96feSEduard Zingerman   Error E2 = BTF.parse(D.makeObj());
1040d15f96feSEduard Zingerman   EXPECT_FALSE(E2);
1041d15f96feSEduard Zingerman 
1042d15f96feSEduard Zingerman   ASSERT_TRUE(BTF.findType(1));
1043d15f96feSEduard Zingerman   EXPECT_EQ(BTF.findString(BTF.findType(1)->NameOff), "buz");
1044d15f96feSEduard Zingerman   EXPECT_FALSE(BTF.findType(2));
1045d15f96feSEduard Zingerman   EXPECT_TRUE(BTF.findFieldReloc({0, 1}));
1046d15f96feSEduard Zingerman   EXPECT_FALSE(BTF.findFieldReloc({8, 1}));
1047d15f96feSEduard Zingerman }
1048d15f96feSEduard Zingerman 
TEST(BTFParserTest,selectiveLoad)1049d15f96feSEduard Zingerman TEST(BTFParserTest, selectiveLoad) {
1050d15f96feSEduard Zingerman   BTFParser BTF1, BTF2, BTF3;
1051d15f96feSEduard Zingerman   MockData2 D;
1052d15f96feSEduard Zingerman 
1053d15f96feSEduard Zingerman   D.addType({D.addString("foo"), mkInfo(BTF::BTF_KIND_STRUCT), {0}});
1054d15f96feSEduard Zingerman   D.addRelocSec({D.addString("foo"), 0});
1055d15f96feSEduard Zingerman   D.addReloc({0, 1, D.addString(""), BTF::TYPE_EXISTENCE});
1056d15f96feSEduard Zingerman   D.addLinesSec({D.addString("foo"), 0});
1057d15f96feSEduard Zingerman   D.addLine({0, D.addString("file.c"), D.addString("some line"), LC(2, 3)});
1058d15f96feSEduard Zingerman 
1059d15f96feSEduard Zingerman   BTFParser::ParseOptions Opts;
1060d15f96feSEduard Zingerman 
1061d15f96feSEduard Zingerman   ObjectFile &Obj1 = D.makeObj();
1062d15f96feSEduard Zingerman   Opts = {};
1063d15f96feSEduard Zingerman   Opts.LoadLines = true;
1064d15f96feSEduard Zingerman   ASSERT_SUCCEEDED(BTF1.parse(Obj1, Opts));
1065d15f96feSEduard Zingerman 
1066d15f96feSEduard Zingerman   Opts = {};
1067d15f96feSEduard Zingerman   Opts.LoadTypes = true;
1068d15f96feSEduard Zingerman   ASSERT_SUCCEEDED(BTF2.parse(Obj1, Opts));
1069d15f96feSEduard Zingerman 
1070d15f96feSEduard Zingerman   Opts = {};
1071d15f96feSEduard Zingerman   Opts.LoadRelocs = true;
1072d15f96feSEduard Zingerman   ASSERT_SUCCEEDED(BTF3.parse(Obj1, Opts));
1073d15f96feSEduard Zingerman 
1074d15f96feSEduard Zingerman   EXPECT_TRUE(BTF1.findLineInfo({0, 1}));
1075d15f96feSEduard Zingerman   EXPECT_FALSE(BTF2.findLineInfo({0, 1}));
1076d15f96feSEduard Zingerman   EXPECT_FALSE(BTF3.findLineInfo({0, 1}));
1077d15f96feSEduard Zingerman 
1078d15f96feSEduard Zingerman   EXPECT_FALSE(BTF1.findType(1));
1079d15f96feSEduard Zingerman   EXPECT_TRUE(BTF2.findType(1));
1080d15f96feSEduard Zingerman   EXPECT_FALSE(BTF3.findType(1));
1081d15f96feSEduard Zingerman 
1082d15f96feSEduard Zingerman   EXPECT_FALSE(BTF1.findFieldReloc({0, 1}));
1083d15f96feSEduard Zingerman   EXPECT_FALSE(BTF2.findFieldReloc({0, 1}));
1084d15f96feSEduard Zingerman   EXPECT_TRUE(BTF3.findFieldReloc({0, 1}));
1085d15f96feSEduard Zingerman }
1086d15f96feSEduard Zingerman 
1087c8e055d4SEduard Zingerman } // namespace
1088