1 //===- llvm/unittest/DebugInfo/GSYMTest.cpp -------------------------------===//
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 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ADT/DenseMap.h"
10 #include "llvm/ADT/SmallString.h"
11 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
12 #include "llvm/DebugInfo/GSYM/DwarfTransformer.h"
13 #include "llvm/DebugInfo/GSYM/ExtractRanges.h"
14 #include "llvm/DebugInfo/GSYM/FileEntry.h"
15 #include "llvm/DebugInfo/GSYM/FileWriter.h"
16 #include "llvm/DebugInfo/GSYM/FunctionInfo.h"
17 #include "llvm/DebugInfo/GSYM/GsymCreator.h"
18 #include "llvm/DebugInfo/GSYM/GsymReader.h"
19 #include "llvm/DebugInfo/GSYM/Header.h"
20 #include "llvm/DebugInfo/GSYM/InlineInfo.h"
21 #include "llvm/DebugInfo/GSYM/StringTable.h"
22 #include "llvm/ObjectYAML/DWARFEmitter.h"
23 #include "llvm/Support/DataExtractor.h"
24 #include "llvm/Support/Endian.h"
25 #include "llvm/Testing/Support/Error.h"
26
27 #include "gtest/gtest.h"
28 #include "gmock/gmock.h"
29 #include <string>
30
31 using namespace llvm;
32 using namespace gsym;
33
checkError(ArrayRef<std::string> ExpectedMsgs,Error Err)34 void checkError(ArrayRef<std::string> ExpectedMsgs, Error Err) {
35 ASSERT_TRUE(bool(Err));
36 size_t WhichMsg = 0;
37 Error Remaining =
38 handleErrors(std::move(Err), [&](const ErrorInfoBase &Actual) {
39 ASSERT_LT(WhichMsg, ExpectedMsgs.size());
40 // Use .str(), because googletest doesn't visualise a StringRef
41 // properly.
42 EXPECT_EQ(Actual.message(), ExpectedMsgs[WhichMsg++]);
43 });
44 EXPECT_EQ(WhichMsg, ExpectedMsgs.size());
45 EXPECT_FALSE(Remaining);
46 }
47
checkError(std::string ExpectedMsg,Error Err)48 void checkError(std::string ExpectedMsg, Error Err) {
49 checkError(ArrayRef<std::string>{ExpectedMsg}, std::move(Err));
50 }
TEST(GSYMTest,TestFileEntry)51 TEST(GSYMTest, TestFileEntry) {
52 // Make sure default constructed GSYM FileEntry has zeroes in the
53 // directory and basename string table indexes.
54 FileEntry empty1;
55 FileEntry empty2;
56 EXPECT_EQ(empty1.Dir, 0u);
57 EXPECT_EQ(empty1.Base, 0u);
58 // Verify equality operator works
59 FileEntry a1(10, 30);
60 FileEntry a2(10, 30);
61 FileEntry b(10, 40);
62 EXPECT_EQ(empty1, empty2);
63 EXPECT_EQ(a1, a2);
64 EXPECT_NE(a1, b);
65 EXPECT_NE(a1, empty1);
66 // Test we can use llvm::gsym::FileEntry in llvm::DenseMap.
67 DenseMap<FileEntry, uint32_t> EntryToIndex;
68 constexpr uint32_t Index1 = 1;
69 constexpr uint32_t Index2 = 1;
70 auto R = EntryToIndex.insert(std::make_pair(a1, Index1));
71 EXPECT_TRUE(R.second);
72 EXPECT_EQ(R.first->second, Index1);
73 R = EntryToIndex.insert(std::make_pair(a1, Index1));
74 EXPECT_FALSE(R.second);
75 EXPECT_EQ(R.first->second, Index1);
76 R = EntryToIndex.insert(std::make_pair(b, Index2));
77 EXPECT_TRUE(R.second);
78 EXPECT_EQ(R.first->second, Index2);
79 R = EntryToIndex.insert(std::make_pair(a1, Index2));
80 EXPECT_FALSE(R.second);
81 EXPECT_EQ(R.first->second, Index2);
82 }
83
TEST(GSYMTest,TestFunctionInfo)84 TEST(GSYMTest, TestFunctionInfo) {
85 // Test GSYM FunctionInfo structs and functionality.
86 FunctionInfo invalid;
87 EXPECT_FALSE(invalid.isValid());
88 EXPECT_FALSE(invalid.hasRichInfo());
89 const uint64_t StartAddr = 0x1000;
90 const uint64_t EndAddr = 0x1100;
91 const uint64_t Size = EndAddr - StartAddr;
92 const uint32_t NameOffset = 30;
93 FunctionInfo FI(StartAddr, Size, NameOffset);
94 EXPECT_TRUE(FI.isValid());
95 EXPECT_FALSE(FI.hasRichInfo());
96 EXPECT_EQ(FI.startAddress(), StartAddr);
97 EXPECT_EQ(FI.endAddress(), EndAddr);
98 EXPECT_EQ(FI.size(), Size);
99 const uint32_t FileIdx = 1;
100 const uint32_t Line = 12;
101 FI.OptLineTable = LineTable();
102 FI.OptLineTable->push(LineEntry(StartAddr,FileIdx,Line));
103 EXPECT_TRUE(FI.hasRichInfo());
104 FI.clear();
105 EXPECT_FALSE(FI.isValid());
106 EXPECT_FALSE(FI.hasRichInfo());
107
108 FunctionInfo A1(0x1000, 0x100, NameOffset);
109 FunctionInfo A2(0x1000, 0x100, NameOffset);
110 FunctionInfo B;
111 // Check == operator
112 EXPECT_EQ(A1, A2);
113 // Make sure things are not equal if they only differ by start address.
114 B = A2;
115 B.Range = {0x1001, B.endAddress()};
116 EXPECT_NE(B, A2);
117 // Make sure things are not equal if they only differ by size.
118 B = A2;
119 B.Range = {B.startAddress(), B.startAddress() + 0x101};
120 EXPECT_NE(B, A2);
121 // Make sure things are not equal if they only differ by name.
122 B = A2;
123 B.Name = 60;
124 EXPECT_NE(B, A2);
125 // Check < operator.
126 // Check less than where address differs.
127 B = A2;
128 B.Range = {A2.startAddress() + 0x1000, A2.endAddress() + 0x1000};
129 EXPECT_LT(A1, B);
130
131 // We use the < operator to take a variety of different FunctionInfo
132 // structs from a variety of sources: symtab, debug info, runtime info
133 // and we sort them and want the sorting to allow us to quickly get the
134 // best version of a function info.
135 FunctionInfo FISymtab(StartAddr, Size, NameOffset);
136 FunctionInfo FIWithLines(StartAddr, Size, NameOffset);
137 FIWithLines.OptLineTable = LineTable();
138 FIWithLines.OptLineTable->push(LineEntry(StartAddr,FileIdx,Line));
139 // Test that a FunctionInfo with just a name and size is less than one
140 // that has name, size and any number of line table entries
141 EXPECT_LT(FISymtab, FIWithLines);
142
143 FunctionInfo FIWithLinesAndInline = FIWithLines;
144 FIWithLinesAndInline.Inline = InlineInfo();
145 FIWithLinesAndInline.Inline->Ranges.insert(
146 AddressRange(StartAddr, StartAddr + 0x10));
147 // Test that a FunctionInfo with name, size, and line entries is less than
148 // the same one with valid inline info
149 EXPECT_LT(FIWithLines, FIWithLinesAndInline);
150
151 // Test if we have an entry with lines and one with more lines for the same
152 // range, the ones with more lines is greater than the one with less.
153 FunctionInfo FIWithMoreLines = FIWithLines;
154 FIWithMoreLines.OptLineTable->push(LineEntry(StartAddr,FileIdx,Line+5));
155 EXPECT_LT(FIWithLines, FIWithMoreLines);
156
157 // Test that if we have the same number of lines we compare the line entries
158 // in the FunctionInfo.OptLineTable.Lines vector.
159 FunctionInfo FIWithLinesWithHigherAddress = FIWithLines;
160 FIWithLinesWithHigherAddress.OptLineTable->get(0).Addr += 0x10;
161 EXPECT_LT(FIWithLines, FIWithLinesWithHigherAddress);
162 }
163
TestFunctionInfoDecodeError(llvm::support::endianness ByteOrder,StringRef Bytes,const uint64_t BaseAddr,std::string ExpectedErrorMsg)164 static void TestFunctionInfoDecodeError(llvm::support::endianness ByteOrder,
165 StringRef Bytes,
166 const uint64_t BaseAddr,
167 std::string ExpectedErrorMsg) {
168 uint8_t AddressSize = 4;
169 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
170 llvm::Expected<FunctionInfo> Decoded = FunctionInfo::decode(Data, BaseAddr);
171 // Make sure decoding fails.
172 ASSERT_FALSE((bool)Decoded);
173 // Make sure decoded object is the same as the one we encoded.
174 checkError(ExpectedErrorMsg, Decoded.takeError());
175 }
176
TEST(GSYMTest,TestFunctionInfoDecodeErrors)177 TEST(GSYMTest, TestFunctionInfoDecodeErrors) {
178 // Test decoding FunctionInfo objects that ensure we report an appropriate
179 // error message.
180 const llvm::support::endianness ByteOrder = llvm::support::little;
181 SmallString<512> Str;
182 raw_svector_ostream OutStrm(Str);
183 FileWriter FW(OutStrm, ByteOrder);
184 const uint64_t BaseAddr = 0x100;
185 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
186 "0x00000000: missing FunctionInfo Size");
187 FW.writeU32(0x100); // Function size.
188 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
189 "0x00000004: missing FunctionInfo Name");
190 // Write out an invalid Name string table offset of zero.
191 FW.writeU32(0);
192 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
193 "0x00000004: invalid FunctionInfo Name value 0x00000000");
194 // Modify the Name to be 0x00000001, which is a valid value.
195 FW.fixup32(0x00000001, 4);
196 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
197 "0x00000008: missing FunctionInfo InfoType value");
198 auto FixupOffset = FW.tell();
199 FW.writeU32(1); // InfoType::LineTableInfo.
200 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
201 "0x0000000c: missing FunctionInfo InfoType length");
202 FW.fixup32(4, FixupOffset); // Write an invalid InfoType enumeration value
203 FW.writeU32(0); // LineTableInfo InfoType data length.
204 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
205 "0x00000008: unsupported InfoType 4");
206 }
207
TestFunctionInfoEncodeError(llvm::support::endianness ByteOrder,const FunctionInfo & FI,std::string ExpectedErrorMsg)208 static void TestFunctionInfoEncodeError(llvm::support::endianness ByteOrder,
209 const FunctionInfo &FI,
210 std::string ExpectedErrorMsg) {
211 SmallString<512> Str;
212 raw_svector_ostream OutStrm(Str);
213 FileWriter FW(OutStrm, ByteOrder);
214 Expected<uint64_t> ExpectedOffset = FI.encode(FW);
215 ASSERT_FALSE(ExpectedOffset);
216 checkError(ExpectedErrorMsg, ExpectedOffset.takeError());
217 }
218
TEST(GSYMTest,TestFunctionInfoEncodeErrors)219 TEST(GSYMTest, TestFunctionInfoEncodeErrors) {
220 const uint64_t FuncAddr = 0x1000;
221 const uint64_t FuncSize = 0x100;
222 const uint32_t InvalidName = 0;
223 const uint32_t ValidName = 1;
224 FunctionInfo InvalidNameFI(FuncAddr, FuncSize, InvalidName);
225 TestFunctionInfoEncodeError(llvm::support::little, InvalidNameFI,
226 "attempted to encode invalid FunctionInfo object");
227
228 FunctionInfo InvalidLineTableFI(FuncAddr, FuncSize, ValidName);
229 // Empty line tables are not valid. Verify if the encoding of anything
230 // in our line table fails, that we see get the error propagated.
231 InvalidLineTableFI.OptLineTable = LineTable();
232 TestFunctionInfoEncodeError(llvm::support::little, InvalidLineTableFI,
233 "attempted to encode invalid LineTable object");
234
235 FunctionInfo InvalidInlineInfoFI(FuncAddr, FuncSize, ValidName);
236 // Empty line tables are not valid. Verify if the encoding of anything
237 // in our line table fails, that we see get the error propagated.
238 InvalidInlineInfoFI.Inline = InlineInfo();
239 TestFunctionInfoEncodeError(llvm::support::little, InvalidInlineInfoFI,
240 "attempted to encode invalid InlineInfo object");
241 }
242
TestFunctionInfoEncodeDecode(llvm::support::endianness ByteOrder,const FunctionInfo & FI)243 static void TestFunctionInfoEncodeDecode(llvm::support::endianness ByteOrder,
244 const FunctionInfo &FI) {
245 // Test encoding and decoding FunctionInfo objects.
246 SmallString<512> Str;
247 raw_svector_ostream OutStrm(Str);
248 FileWriter FW(OutStrm, ByteOrder);
249 llvm::Expected<uint64_t> ExpectedOffset = FI.encode(FW);
250 ASSERT_TRUE(bool(ExpectedOffset));
251 // Verify we got the encoded offset back from the encode function.
252 ASSERT_EQ(ExpectedOffset.get(), 0ULL);
253 std::string Bytes(OutStrm.str());
254 uint8_t AddressSize = 4;
255 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
256 llvm::Expected<FunctionInfo> Decoded =
257 FunctionInfo::decode(Data, FI.Range.start());
258 // Make sure decoding succeeded.
259 ASSERT_TRUE((bool)Decoded);
260 // Make sure decoded object is the same as the one we encoded.
261 EXPECT_EQ(FI, Decoded.get());
262 }
263
AddLines(uint64_t FuncAddr,uint32_t FileIdx,FunctionInfo & FI)264 static void AddLines(uint64_t FuncAddr, uint32_t FileIdx, FunctionInfo &FI) {
265 FI.OptLineTable = LineTable();
266 LineEntry Line0(FuncAddr + 0x000, FileIdx, 10);
267 LineEntry Line1(FuncAddr + 0x010, FileIdx, 11);
268 LineEntry Line2(FuncAddr + 0x100, FileIdx, 1000);
269 FI.OptLineTable->push(Line0);
270 FI.OptLineTable->push(Line1);
271 FI.OptLineTable->push(Line2);
272 }
273
274
AddInline(uint64_t FuncAddr,uint64_t FuncSize,FunctionInfo & FI)275 static void AddInline(uint64_t FuncAddr, uint64_t FuncSize, FunctionInfo &FI) {
276 FI.Inline = InlineInfo();
277 FI.Inline->Ranges.insert(AddressRange(FuncAddr, FuncAddr + FuncSize));
278 InlineInfo Inline1;
279 Inline1.Ranges.insert(AddressRange(FuncAddr + 0x10, FuncAddr + 0x30));
280 Inline1.Name = 1;
281 Inline1.CallFile = 1;
282 Inline1.CallLine = 11;
283 FI.Inline->Children.push_back(Inline1);
284 }
285
TEST(GSYMTest,TestFunctionInfoEncoding)286 TEST(GSYMTest, TestFunctionInfoEncoding) {
287 constexpr uint64_t FuncAddr = 0x1000;
288 constexpr uint64_t FuncSize = 0x100;
289 constexpr uint32_t FuncName = 1;
290 constexpr uint32_t FileIdx = 1;
291 // Make sure that we can encode and decode a FunctionInfo with no line table
292 // or inline info.
293 FunctionInfo FI(FuncAddr, FuncSize, FuncName);
294 TestFunctionInfoEncodeDecode(llvm::support::little, FI);
295 TestFunctionInfoEncodeDecode(llvm::support::big, FI);
296
297 // Make sure that we can encode and decode a FunctionInfo with a line table
298 // and no inline info.
299 FunctionInfo FILines(FuncAddr, FuncSize, FuncName);
300 AddLines(FuncAddr, FileIdx, FILines);
301 TestFunctionInfoEncodeDecode(llvm::support::little, FILines);
302 TestFunctionInfoEncodeDecode(llvm::support::big, FILines);
303
304 // Make sure that we can encode and decode a FunctionInfo with no line table
305 // and with inline info.
306 FunctionInfo FIInline(FuncAddr, FuncSize, FuncName);
307 AddInline(FuncAddr, FuncSize, FIInline);
308 TestFunctionInfoEncodeDecode(llvm::support::little, FIInline);
309 TestFunctionInfoEncodeDecode(llvm::support::big, FIInline);
310
311 // Make sure that we can encode and decode a FunctionInfo with no line table
312 // and with inline info.
313 FunctionInfo FIBoth(FuncAddr, FuncSize, FuncName);
314 AddLines(FuncAddr, FileIdx, FIBoth);
315 AddInline(FuncAddr, FuncSize, FIBoth);
316 TestFunctionInfoEncodeDecode(llvm::support::little, FIBoth);
317 TestFunctionInfoEncodeDecode(llvm::support::big, FIBoth);
318 }
319
TestInlineInfoEncodeDecode(llvm::support::endianness ByteOrder,const InlineInfo & Inline)320 static void TestInlineInfoEncodeDecode(llvm::support::endianness ByteOrder,
321 const InlineInfo &Inline) {
322 // Test encoding and decoding InlineInfo objects
323 SmallString<512> Str;
324 raw_svector_ostream OutStrm(Str);
325 FileWriter FW(OutStrm, ByteOrder);
326 const uint64_t BaseAddr = Inline.Ranges[0].start();
327 llvm::Error Err = Inline.encode(FW, BaseAddr);
328 ASSERT_FALSE(Err);
329 std::string Bytes(OutStrm.str());
330 uint8_t AddressSize = 4;
331 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
332 llvm::Expected<InlineInfo> Decoded = InlineInfo::decode(Data, BaseAddr);
333 // Make sure decoding succeeded.
334 ASSERT_TRUE((bool)Decoded);
335 // Make sure decoded object is the same as the one we encoded.
336 EXPECT_EQ(Inline, Decoded.get());
337 }
338
TestInlineInfoDecodeError(llvm::support::endianness ByteOrder,StringRef Bytes,const uint64_t BaseAddr,std::string ExpectedErrorMsg)339 static void TestInlineInfoDecodeError(llvm::support::endianness ByteOrder,
340 StringRef Bytes, const uint64_t BaseAddr,
341 std::string ExpectedErrorMsg) {
342 uint8_t AddressSize = 4;
343 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
344 llvm::Expected<InlineInfo> Decoded = InlineInfo::decode(Data, BaseAddr);
345 // Make sure decoding fails.
346 ASSERT_FALSE((bool)Decoded);
347 // Make sure decoded object is the same as the one we encoded.
348 checkError(ExpectedErrorMsg, Decoded.takeError());
349 }
350
TestInlineInfoEncodeError(llvm::support::endianness ByteOrder,const InlineInfo & Inline,std::string ExpectedErrorMsg)351 static void TestInlineInfoEncodeError(llvm::support::endianness ByteOrder,
352 const InlineInfo &Inline,
353 std::string ExpectedErrorMsg) {
354 SmallString<512> Str;
355 raw_svector_ostream OutStrm(Str);
356 FileWriter FW(OutStrm, ByteOrder);
357 const uint64_t BaseAddr =
358 Inline.Ranges.empty() ? 0 : Inline.Ranges[0].start();
359 llvm::Error Err = Inline.encode(FW, BaseAddr);
360 checkError(ExpectedErrorMsg, std::move(Err));
361 }
362
TEST(GSYMTest,TestInlineInfo)363 TEST(GSYMTest, TestInlineInfo) {
364 // Test InlineInfo structs.
365 InlineInfo II;
366 EXPECT_FALSE(II.isValid());
367 II.Ranges.insert(AddressRange(0x1000, 0x2000));
368 // Make sure InlineInfo in valid with just an address range since
369 // top level InlineInfo objects have ranges with no name, call file
370 // or call line
371 EXPECT_TRUE(II.isValid());
372 // Make sure InlineInfo isn't after being cleared.
373 II.clear();
374 EXPECT_FALSE(II.isValid());
375
376 // Create an InlineInfo that contains the following data. The
377 // indentation of the address range indicates the parent child
378 // relationships of the InlineInfo objects:
379 //
380 // Variable Range and values
381 // =========== ====================================================
382 // Root [0x100-0x200) (no name, file, or line)
383 // Inline1 [0x150-0x160) Name = 1, File = 1, Line = 11
384 // Inline1Sub1 [0x152-0x155) Name = 2, File = 2, Line = 22
385 // Inline1Sub2 [0x157-0x158) Name = 3, File = 3, Line = 33
386 InlineInfo Root;
387 Root.Ranges.insert(AddressRange(0x100, 0x200));
388 InlineInfo Inline1;
389 Inline1.Ranges.insert(AddressRange(0x150, 0x160));
390 Inline1.Name = 1;
391 Inline1.CallFile = 1;
392 Inline1.CallLine = 11;
393 InlineInfo Inline1Sub1;
394 Inline1Sub1.Ranges.insert(AddressRange(0x152, 0x155));
395 Inline1Sub1.Name = 2;
396 Inline1Sub1.CallFile = 2;
397 Inline1Sub1.CallLine = 22;
398 InlineInfo Inline1Sub2;
399 Inline1Sub2.Ranges.insert(AddressRange(0x157, 0x158));
400 Inline1Sub2.Name = 3;
401 Inline1Sub2.CallFile = 3;
402 Inline1Sub2.CallLine = 33;
403 Inline1.Children.push_back(Inline1Sub1);
404 Inline1.Children.push_back(Inline1Sub2);
405 Root.Children.push_back(Inline1);
406
407 // Make sure an address that is out of range won't match
408 EXPECT_FALSE(Root.getInlineStack(0x50));
409
410 // Verify that we get no inline stacks for addresses out of [0x100-0x200)
411 EXPECT_FALSE(Root.getInlineStack(Root.Ranges[0].start() - 1));
412 EXPECT_FALSE(Root.getInlineStack(Root.Ranges[0].end()));
413
414 // Verify we get no inline stack entries for addresses that are in
415 // [0x100-0x200) but not in [0x150-0x160)
416 EXPECT_FALSE(Root.getInlineStack(Inline1.Ranges[0].start() - 1));
417 EXPECT_FALSE(Root.getInlineStack(Inline1.Ranges[0].end()));
418
419 // Verify we get one inline stack entry for addresses that are in
420 // [[0x150-0x160)) but not in [0x152-0x155) or [0x157-0x158)
421 auto InlineInfos = Root.getInlineStack(Inline1.Ranges[0].start());
422 ASSERT_TRUE(InlineInfos);
423 ASSERT_EQ(InlineInfos->size(), 1u);
424 ASSERT_EQ(*InlineInfos->at(0), Inline1);
425 InlineInfos = Root.getInlineStack(Inline1.Ranges[0].end() - 1);
426 EXPECT_TRUE(InlineInfos);
427 ASSERT_EQ(InlineInfos->size(), 1u);
428 ASSERT_EQ(*InlineInfos->at(0), Inline1);
429
430 // Verify we get two inline stack entries for addresses that are in
431 // [0x152-0x155)
432 InlineInfos = Root.getInlineStack(Inline1Sub1.Ranges[0].start());
433 EXPECT_TRUE(InlineInfos);
434 ASSERT_EQ(InlineInfos->size(), 2u);
435 ASSERT_EQ(*InlineInfos->at(0), Inline1Sub1);
436 ASSERT_EQ(*InlineInfos->at(1), Inline1);
437 InlineInfos = Root.getInlineStack(Inline1Sub1.Ranges[0].end() - 1);
438 EXPECT_TRUE(InlineInfos);
439 ASSERT_EQ(InlineInfos->size(), 2u);
440 ASSERT_EQ(*InlineInfos->at(0), Inline1Sub1);
441 ASSERT_EQ(*InlineInfos->at(1), Inline1);
442
443 // Verify we get two inline stack entries for addresses that are in
444 // [0x157-0x158)
445 InlineInfos = Root.getInlineStack(Inline1Sub2.Ranges[0].start());
446 EXPECT_TRUE(InlineInfos);
447 ASSERT_EQ(InlineInfos->size(), 2u);
448 ASSERT_EQ(*InlineInfos->at(0), Inline1Sub2);
449 ASSERT_EQ(*InlineInfos->at(1), Inline1);
450 InlineInfos = Root.getInlineStack(Inline1Sub2.Ranges[0].end() - 1);
451 EXPECT_TRUE(InlineInfos);
452 ASSERT_EQ(InlineInfos->size(), 2u);
453 ASSERT_EQ(*InlineInfos->at(0), Inline1Sub2);
454 ASSERT_EQ(*InlineInfos->at(1), Inline1);
455
456 // Test encoding and decoding InlineInfo objects
457 TestInlineInfoEncodeDecode(llvm::support::little, Root);
458 TestInlineInfoEncodeDecode(llvm::support::big, Root);
459 }
460
TEST(GSYMTest,TestInlineInfoEncodeErrors)461 TEST(GSYMTest, TestInlineInfoEncodeErrors) {
462 // Test InlineInfo encoding errors.
463
464 // Test that we get an error when trying to encode an InlineInfo object
465 // that has no ranges.
466 InlineInfo Empty;
467 std::string EmptyErr("attempted to encode invalid InlineInfo object");
468 TestInlineInfoEncodeError(llvm::support::little, Empty, EmptyErr);
469 TestInlineInfoEncodeError(llvm::support::big, Empty, EmptyErr);
470
471 // Verify that we get an error trying to encode an InlineInfo object that has
472 // a child InlineInfo that has no ranges.
473 InlineInfo ContainsEmpty;
474 ContainsEmpty.Ranges.insert({0x100, 0x200});
475 ContainsEmpty.Children.push_back(Empty);
476 TestInlineInfoEncodeError(llvm::support::little, ContainsEmpty, EmptyErr);
477 TestInlineInfoEncodeError(llvm::support::big, ContainsEmpty, EmptyErr);
478
479 // Verify that we get an error trying to encode an InlineInfo object that has
480 // a child whose address range is not contained in the parent address range.
481 InlineInfo ChildNotContained;
482 std::string ChildNotContainedErr("child range not contained in parent");
483 ChildNotContained.Ranges.insert({0x100, 0x200});
484 InlineInfo ChildNotContainedChild;
485 ChildNotContainedChild.Ranges.insert({0x200, 0x300});
486 ChildNotContained.Children.push_back(ChildNotContainedChild);
487 TestInlineInfoEncodeError(llvm::support::little, ChildNotContained,
488 ChildNotContainedErr);
489 TestInlineInfoEncodeError(llvm::support::big, ChildNotContained,
490 ChildNotContainedErr);
491
492 }
493
TEST(GSYMTest,TestInlineInfoDecodeErrors)494 TEST(GSYMTest, TestInlineInfoDecodeErrors) {
495 // Test decoding InlineInfo objects that ensure we report an appropriate
496 // error message.
497 const llvm::support::endianness ByteOrder = llvm::support::little;
498 SmallString<512> Str;
499 raw_svector_ostream OutStrm(Str);
500 FileWriter FW(OutStrm, ByteOrder);
501 const uint64_t BaseAddr = 0x100;
502 TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
503 "0x00000000: missing InlineInfo address ranges data");
504 AddressRanges Ranges;
505 Ranges.insert({BaseAddr, BaseAddr+0x100});
506 encodeRanges(Ranges, FW, BaseAddr);
507 TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
508 "0x00000004: missing InlineInfo uint8_t indicating children");
509 FW.writeU8(0);
510 TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
511 "0x00000005: missing InlineInfo uint32_t for name");
512 FW.writeU32(0);
513 TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
514 "0x00000009: missing ULEB128 for InlineInfo call file");
515 FW.writeU8(0);
516 TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
517 "0x0000000a: missing ULEB128 for InlineInfo call line");
518 }
519
TEST(GSYMTest,TestLineEntry)520 TEST(GSYMTest, TestLineEntry) {
521 // test llvm::gsym::LineEntry structs.
522 const uint64_t ValidAddr = 0x1000;
523 const uint64_t InvalidFileIdx = 0;
524 const uint32_t ValidFileIdx = 1;
525 const uint32_t ValidLine = 5;
526
527 LineEntry Invalid;
528 EXPECT_FALSE(Invalid.isValid());
529 // Make sure that an entry is invalid if it has a bad file index.
530 LineEntry BadFile(ValidAddr, InvalidFileIdx, ValidLine);
531 EXPECT_FALSE(BadFile.isValid());
532 // Test operators
533 LineEntry E1(ValidAddr, ValidFileIdx, ValidLine);
534 LineEntry E2(ValidAddr, ValidFileIdx, ValidLine);
535 LineEntry DifferentAddr(ValidAddr + 1, ValidFileIdx, ValidLine);
536 LineEntry DifferentFile(ValidAddr, ValidFileIdx + 1, ValidLine);
537 LineEntry DifferentLine(ValidAddr, ValidFileIdx, ValidLine + 1);
538 EXPECT_TRUE(E1.isValid());
539 EXPECT_EQ(E1, E2);
540 EXPECT_NE(E1, DifferentAddr);
541 EXPECT_NE(E1, DifferentFile);
542 EXPECT_NE(E1, DifferentLine);
543 EXPECT_LT(E1, DifferentAddr);
544 }
545
TEST(GSYMTest,TestStringTable)546 TEST(GSYMTest, TestStringTable) {
547 StringTable StrTab(StringRef("\0Hello\0World\0", 13));
548 // Test extracting strings from a string table.
549 EXPECT_EQ(StrTab.getString(0), "");
550 EXPECT_EQ(StrTab.getString(1), "Hello");
551 EXPECT_EQ(StrTab.getString(7), "World");
552 EXPECT_EQ(StrTab.getString(8), "orld");
553 // Test pointing to last NULL terminator gets empty string.
554 EXPECT_EQ(StrTab.getString(12), "");
555 // Test pointing to past end gets empty string.
556 EXPECT_EQ(StrTab.getString(13), "");
557 }
558
TestFileWriterHelper(llvm::support::endianness ByteOrder)559 static void TestFileWriterHelper(llvm::support::endianness ByteOrder) {
560 SmallString<512> Str;
561 raw_svector_ostream OutStrm(Str);
562 FileWriter FW(OutStrm, ByteOrder);
563 const int64_t MinSLEB = INT64_MIN;
564 const int64_t MaxSLEB = INT64_MAX;
565 const uint64_t MinULEB = 0;
566 const uint64_t MaxULEB = UINT64_MAX;
567 const uint8_t U8 = 0x10;
568 const uint16_t U16 = 0x1122;
569 const uint32_t U32 = 0x12345678;
570 const uint64_t U64 = 0x33445566778899aa;
571 const char *Hello = "hello";
572 FW.writeU8(U8);
573 FW.writeU16(U16);
574 FW.writeU32(U32);
575 FW.writeU64(U64);
576 FW.alignTo(16);
577 const off_t FixupOffset = FW.tell();
578 FW.writeU32(0);
579 FW.writeSLEB(MinSLEB);
580 FW.writeSLEB(MaxSLEB);
581 FW.writeULEB(MinULEB);
582 FW.writeULEB(MaxULEB);
583 FW.writeNullTerminated(Hello);
584 // Test Seek, Tell using Fixup32.
585 FW.fixup32(U32, FixupOffset);
586
587 std::string Bytes(OutStrm.str());
588 uint8_t AddressSize = 4;
589 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
590 uint64_t Offset = 0;
591 EXPECT_EQ(Data.getU8(&Offset), U8);
592 EXPECT_EQ(Data.getU16(&Offset), U16);
593 EXPECT_EQ(Data.getU32(&Offset), U32);
594 EXPECT_EQ(Data.getU64(&Offset), U64);
595 Offset = alignTo(Offset, 16);
596 EXPECT_EQ(Data.getU32(&Offset), U32);
597 EXPECT_EQ(Data.getSLEB128(&Offset), MinSLEB);
598 EXPECT_EQ(Data.getSLEB128(&Offset), MaxSLEB);
599 EXPECT_EQ(Data.getULEB128(&Offset), MinULEB);
600 EXPECT_EQ(Data.getULEB128(&Offset), MaxULEB);
601 EXPECT_EQ(Data.getCStrRef(&Offset), StringRef(Hello));
602 }
603
TEST(GSYMTest,TestFileWriter)604 TEST(GSYMTest, TestFileWriter) {
605 TestFileWriterHelper(llvm::support::little);
606 TestFileWriterHelper(llvm::support::big);
607 }
608
TEST(GSYMTest,TestAddressRangeEncodeDecode)609 TEST(GSYMTest, TestAddressRangeEncodeDecode) {
610 // Test encoding and decoding AddressRange objects. AddressRange objects
611 // are always stored as offsets from the a base address. The base address
612 // is the FunctionInfo's base address for function level ranges, and is
613 // the base address of the parent range for subranges.
614 SmallString<512> Str;
615 raw_svector_ostream OutStrm(Str);
616 const auto ByteOrder = llvm::support::endian::system_endianness();
617 FileWriter FW(OutStrm, ByteOrder);
618 const uint64_t BaseAddr = 0x1000;
619 const AddressRange Range1(0x1000, 0x1010);
620 const AddressRange Range2(0x1020, 0x1030);
621 encodeRange(Range1, FW, BaseAddr);
622 encodeRange(Range2, FW, BaseAddr);
623 std::string Bytes(OutStrm.str());
624 uint8_t AddressSize = 4;
625 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
626
627 AddressRange DecodedRange1, DecodedRange2;
628 uint64_t Offset = 0;
629 DecodedRange1 = decodeRange(Data, BaseAddr, Offset);
630 DecodedRange2 = decodeRange(Data, BaseAddr, Offset);
631 EXPECT_EQ(Range1, DecodedRange1);
632 EXPECT_EQ(Range2, DecodedRange2);
633 }
634
TestAddressRangeEncodeDecodeHelper(const AddressRanges & Ranges,const uint64_t BaseAddr)635 static void TestAddressRangeEncodeDecodeHelper(const AddressRanges &Ranges,
636 const uint64_t BaseAddr) {
637 SmallString<512> Str;
638 raw_svector_ostream OutStrm(Str);
639 const auto ByteOrder = llvm::support::endian::system_endianness();
640 FileWriter FW(OutStrm, ByteOrder);
641 encodeRanges(Ranges, FW, BaseAddr);
642
643 std::string Bytes(OutStrm.str());
644 uint8_t AddressSize = 4;
645 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
646
647 AddressRanges DecodedRanges;
648 uint64_t Offset = 0;
649 decodeRanges(DecodedRanges, Data, BaseAddr, Offset);
650 EXPECT_EQ(Ranges, DecodedRanges);
651 }
652
TEST(GSYMTest,TestAddressRangesEncodeDecode)653 TEST(GSYMTest, TestAddressRangesEncodeDecode) {
654 // Test encoding and decoding AddressRanges. AddressRanges objects contain
655 // ranges that are stored as offsets from the a base address. The base address
656 // is the FunctionInfo's base address for function level ranges, and is the
657 // base address of the parent range for subranges.
658 const uint64_t BaseAddr = 0x1000;
659
660 // Test encoding and decoding with no ranges.
661 AddressRanges Ranges;
662 TestAddressRangeEncodeDecodeHelper(Ranges, BaseAddr);
663
664 // Test encoding and decoding with 1 range.
665 Ranges.insert(AddressRange(0x1000, 0x1010));
666 TestAddressRangeEncodeDecodeHelper(Ranges, BaseAddr);
667
668 // Test encoding and decoding with multiple ranges.
669 Ranges.insert(AddressRange(0x1020, 0x1030));
670 Ranges.insert(AddressRange(0x1050, 0x1070));
671 TestAddressRangeEncodeDecodeHelper(Ranges, BaseAddr);
672 }
673
TestLineTableHelper(llvm::support::endianness ByteOrder,const LineTable & LT)674 static void TestLineTableHelper(llvm::support::endianness ByteOrder,
675 const LineTable <) {
676 SmallString<512> Str;
677 raw_svector_ostream OutStrm(Str);
678 FileWriter FW(OutStrm, ByteOrder);
679 const uint64_t BaseAddr = LT[0].Addr;
680 llvm::Error Err = LT.encode(FW, BaseAddr);
681 ASSERT_FALSE(Err);
682 std::string Bytes(OutStrm.str());
683 uint8_t AddressSize = 4;
684 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
685 llvm::Expected<LineTable> Decoded = LineTable::decode(Data, BaseAddr);
686 // Make sure decoding succeeded.
687 ASSERT_TRUE((bool)Decoded);
688 // Make sure decoded object is the same as the one we encoded.
689 EXPECT_EQ(LT, Decoded.get());
690 }
691
TEST(GSYMTest,TestLineTable)692 TEST(GSYMTest, TestLineTable) {
693 const uint64_t StartAddr = 0x1000;
694 const uint32_t FileIdx = 1;
695 LineTable LT;
696 LineEntry Line0(StartAddr+0x000, FileIdx, 10);
697 LineEntry Line1(StartAddr+0x010, FileIdx, 11);
698 LineEntry Line2(StartAddr+0x100, FileIdx, 1000);
699 ASSERT_TRUE(LT.empty());
700 ASSERT_EQ(LT.size(), (size_t)0);
701 LT.push(Line0);
702 ASSERT_EQ(LT.size(), (size_t)1);
703 LT.push(Line1);
704 LT.push(Line2);
705 LT.push(LineEntry(StartAddr+0x120, FileIdx, 900));
706 LT.push(LineEntry(StartAddr+0x120, FileIdx, 2000));
707 LT.push(LineEntry(StartAddr+0x121, FileIdx, 2001));
708 LT.push(LineEntry(StartAddr+0x122, FileIdx, 2002));
709 LT.push(LineEntry(StartAddr+0x123, FileIdx, 2003));
710 ASSERT_FALSE(LT.empty());
711 ASSERT_EQ(LT.size(), (size_t)8);
712 // Test operator[].
713 ASSERT_EQ(LT[0], Line0);
714 ASSERT_EQ(LT[1], Line1);
715 ASSERT_EQ(LT[2], Line2);
716
717 // Test encoding and decoding line tables.
718 TestLineTableHelper(llvm::support::little, LT);
719 TestLineTableHelper(llvm::support::big, LT);
720
721 // Verify the clear method works as expected.
722 LT.clear();
723 ASSERT_TRUE(LT.empty());
724 ASSERT_EQ(LT.size(), (size_t)0);
725
726 LineTable LT1;
727 LineTable LT2;
728
729 // Test that two empty line tables are equal and neither are less than
730 // each other.
731 ASSERT_EQ(LT1, LT2);
732 ASSERT_FALSE(LT1 < LT1);
733 ASSERT_FALSE(LT1 < LT2);
734 ASSERT_FALSE(LT2 < LT1);
735 ASSERT_FALSE(LT2 < LT2);
736
737 // Test that a line table with less number of line entries is less than a
738 // line table with more line entries and that they are not equal.
739 LT2.push(Line0);
740 ASSERT_LT(LT1, LT2);
741 ASSERT_NE(LT1, LT2);
742
743 // Test that two line tables with the same entries are equal.
744 LT1.push(Line0);
745 ASSERT_EQ(LT1, LT2);
746 ASSERT_FALSE(LT1 < LT2);
747 ASSERT_FALSE(LT2 < LT2);
748 }
749
TestLineTableDecodeError(llvm::support::endianness ByteOrder,StringRef Bytes,const uint64_t BaseAddr,std::string ExpectedErrorMsg)750 static void TestLineTableDecodeError(llvm::support::endianness ByteOrder,
751 StringRef Bytes, const uint64_t BaseAddr,
752 std::string ExpectedErrorMsg) {
753 uint8_t AddressSize = 4;
754 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
755 llvm::Expected<LineTable> Decoded = LineTable::decode(Data, BaseAddr);
756 // Make sure decoding fails.
757 ASSERT_FALSE((bool)Decoded);
758 // Make sure decoded object is the same as the one we encoded.
759 checkError(ExpectedErrorMsg, Decoded.takeError());
760 }
761
TEST(GSYMTest,TestLineTableDecodeErrors)762 TEST(GSYMTest, TestLineTableDecodeErrors) {
763 // Test decoding InlineInfo objects that ensure we report an appropriate
764 // error message.
765 const llvm::support::endianness ByteOrder = llvm::support::little;
766 SmallString<512> Str;
767 raw_svector_ostream OutStrm(Str);
768 FileWriter FW(OutStrm, ByteOrder);
769 const uint64_t BaseAddr = 0x100;
770 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
771 "0x00000000: missing LineTable MinDelta");
772 FW.writeU8(1); // MinDelta (ULEB)
773 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
774 "0x00000001: missing LineTable MaxDelta");
775 FW.writeU8(10); // MaxDelta (ULEB)
776 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
777 "0x00000002: missing LineTable FirstLine");
778 FW.writeU8(20); // FirstLine (ULEB)
779 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
780 "0x00000003: EOF found before EndSequence");
781 // Test a SetFile with the argument missing from the stream
782 FW.writeU8(1); // SetFile opcode (uint8_t)
783 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
784 "0x00000004: EOF found before SetFile value");
785 FW.writeU8(5); // SetFile value as index (ULEB)
786 // Test a AdvancePC with the argument missing from the stream
787 FW.writeU8(2); // AdvancePC opcode (uint8_t)
788 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
789 "0x00000006: EOF found before AdvancePC value");
790 FW.writeU8(20); // AdvancePC value as offset (ULEB)
791 // Test a AdvancePC with the argument missing from the stream
792 FW.writeU8(3); // AdvanceLine opcode (uint8_t)
793 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
794 "0x00000008: EOF found before AdvanceLine value");
795 FW.writeU8(20); // AdvanceLine value as offset (LLEB)
796 }
797
TEST(GSYMTest,TestLineTableEncodeErrors)798 TEST(GSYMTest, TestLineTableEncodeErrors) {
799 const uint64_t BaseAddr = 0x1000;
800 const uint32_t FileIdx = 1;
801 const llvm::support::endianness ByteOrder = llvm::support::little;
802 SmallString<512> Str;
803 raw_svector_ostream OutStrm(Str);
804 FileWriter FW(OutStrm, ByteOrder);
805 LineTable LT;
806 checkError("attempted to encode invalid LineTable object",
807 LT.encode(FW, BaseAddr));
808
809 // Try to encode a line table where a line entry has an address that is less
810 // than BaseAddr and verify we get an appropriate error.
811 LineEntry Line0(BaseAddr+0x000, FileIdx, 10);
812 LineEntry Line1(BaseAddr+0x010, FileIdx, 11);
813 LT.push(Line0);
814 LT.push(Line1);
815 checkError("LineEntry has address 0x1000 which is less than the function "
816 "start address 0x1010", LT.encode(FW, BaseAddr+0x10));
817 LT.clear();
818
819 // Try to encode a line table where a line entries has an address that is less
820 // than BaseAddr and verify we get an appropriate error.
821 LT.push(Line1);
822 LT.push(Line0);
823 checkError("LineEntry in LineTable not in ascending order",
824 LT.encode(FW, BaseAddr));
825 LT.clear();
826 }
827
TestHeaderEncodeError(const Header & H,std::string ExpectedErrorMsg)828 static void TestHeaderEncodeError(const Header &H,
829 std::string ExpectedErrorMsg) {
830 const support::endianness ByteOrder = llvm::support::little;
831 SmallString<512> Str;
832 raw_svector_ostream OutStrm(Str);
833 FileWriter FW(OutStrm, ByteOrder);
834 llvm::Error Err = H.encode(FW);
835 checkError(ExpectedErrorMsg, std::move(Err));
836 }
837
TestHeaderDecodeError(StringRef Bytes,std::string ExpectedErrorMsg)838 static void TestHeaderDecodeError(StringRef Bytes,
839 std::string ExpectedErrorMsg) {
840 const support::endianness ByteOrder = llvm::support::little;
841 uint8_t AddressSize = 4;
842 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
843 llvm::Expected<Header> Decoded = Header::decode(Data);
844 // Make sure decoding fails.
845 ASSERT_FALSE((bool)Decoded);
846 // Make sure decoded object is the same as the one we encoded.
847 checkError(ExpectedErrorMsg, Decoded.takeError());
848 }
849
850 // Populate a GSYM header with valid values.
InitHeader(Header & H)851 static void InitHeader(Header &H) {
852 H.Magic = GSYM_MAGIC;
853 H.Version = GSYM_VERSION;
854 H.AddrOffSize = 4;
855 H.UUIDSize = 16;
856 H.BaseAddress = 0x1000;
857 H.NumAddresses = 1;
858 H.StrtabOffset= 0x2000;
859 H.StrtabSize = 0x1000;
860 for (size_t i=0; i<GSYM_MAX_UUID_SIZE; ++i) {
861 if (i < H.UUIDSize)
862 H.UUID[i] = i;
863 else
864 H.UUID[i] = 0;
865 }
866 }
867
TEST(GSYMTest,TestHeaderEncodeErrors)868 TEST(GSYMTest, TestHeaderEncodeErrors) {
869 Header H;
870 InitHeader(H);
871 H.Magic = 12;
872 TestHeaderEncodeError(H, "invalid GSYM magic 0x0000000c");
873 InitHeader(H);
874 H.Version = 12;
875 TestHeaderEncodeError(H, "unsupported GSYM version 12");
876 InitHeader(H);
877 H.AddrOffSize = 12;
878 TestHeaderEncodeError(H, "invalid address offset size 12");
879 InitHeader(H);
880 H.UUIDSize = 128;
881 TestHeaderEncodeError(H, "invalid UUID size 128");
882 }
883
TEST(GSYMTest,TestHeaderDecodeErrors)884 TEST(GSYMTest, TestHeaderDecodeErrors) {
885 const llvm::support::endianness ByteOrder = llvm::support::little;
886 SmallString<512> Str;
887 raw_svector_ostream OutStrm(Str);
888 FileWriter FW(OutStrm, ByteOrder);
889 Header H;
890 InitHeader(H);
891 llvm::Error Err = H.encode(FW);
892 ASSERT_FALSE(Err);
893 FW.fixup32(12, offsetof(Header, Magic));
894 TestHeaderDecodeError(OutStrm.str(), "invalid GSYM magic 0x0000000c");
895 FW.fixup32(GSYM_MAGIC, offsetof(Header, Magic));
896 FW.fixup32(12, offsetof(Header, Version));
897 TestHeaderDecodeError(OutStrm.str(), "unsupported GSYM version 12");
898 FW.fixup32(GSYM_VERSION, offsetof(Header, Version));
899 FW.fixup32(12, offsetof(Header, AddrOffSize));
900 TestHeaderDecodeError(OutStrm.str(), "invalid address offset size 12");
901 FW.fixup32(4, offsetof(Header, AddrOffSize));
902 FW.fixup32(128, offsetof(Header, UUIDSize));
903 TestHeaderDecodeError(OutStrm.str(), "invalid UUID size 128");
904 }
905
TestHeaderEncodeDecode(const Header & H,support::endianness ByteOrder)906 static void TestHeaderEncodeDecode(const Header &H,
907 support::endianness ByteOrder) {
908 uint8_t AddressSize = 4;
909 SmallString<512> Str;
910 raw_svector_ostream OutStrm(Str);
911 FileWriter FW(OutStrm, ByteOrder);
912 llvm::Error Err = H.encode(FW);
913 ASSERT_FALSE(Err);
914 std::string Bytes(OutStrm.str());
915 DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
916 llvm::Expected<Header> Decoded = Header::decode(Data);
917 // Make sure decoding succeeded.
918 ASSERT_TRUE((bool)Decoded);
919 EXPECT_EQ(H, Decoded.get());
920
921 }
TEST(GSYMTest,TestHeaderEncodeDecode)922 TEST(GSYMTest, TestHeaderEncodeDecode) {
923 Header H;
924 InitHeader(H);
925 TestHeaderEncodeDecode(H, llvm::support::little);
926 TestHeaderEncodeDecode(H, llvm::support::big);
927 }
928
TestGsymCreatorEncodeError(llvm::support::endianness ByteOrder,const GsymCreator & GC,std::string ExpectedErrorMsg)929 static void TestGsymCreatorEncodeError(llvm::support::endianness ByteOrder,
930 const GsymCreator &GC,
931 std::string ExpectedErrorMsg) {
932 SmallString<512> Str;
933 raw_svector_ostream OutStrm(Str);
934 FileWriter FW(OutStrm, ByteOrder);
935 llvm::Error Err = GC.encode(FW);
936 ASSERT_TRUE(bool(Err));
937 checkError(ExpectedErrorMsg, std::move(Err));
938 }
939
TEST(GSYMTest,TestGsymCreatorEncodeErrors)940 TEST(GSYMTest, TestGsymCreatorEncodeErrors) {
941 const uint8_t ValidUUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
942 14, 15, 16};
943 const uint8_t InvalidUUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
944 14, 15, 16, 17, 18, 19, 20, 21};
945 // Verify we get an error when trying to encode an GsymCreator with no
946 // function infos. We shouldn't be saving a GSYM file in this case since
947 // there is nothing inside of it.
948 GsymCreator GC;
949 TestGsymCreatorEncodeError(llvm::support::little, GC,
950 "no functions to encode");
951 const uint64_t FuncAddr = 0x1000;
952 const uint64_t FuncSize = 0x100;
953 const uint32_t FuncName = GC.insertString("foo");
954 // Verify we get an error trying to encode a GsymCreator that isn't
955 // finalized.
956 GC.addFunctionInfo(FunctionInfo(FuncAddr, FuncSize, FuncName));
957 TestGsymCreatorEncodeError(llvm::support::little, GC,
958 "GsymCreator wasn't finalized prior to encoding");
959 std::string finalizeIssues;
960 raw_string_ostream OS(finalizeIssues);
961 llvm::Error finalizeErr = GC.finalize(OS);
962 ASSERT_FALSE(bool(finalizeErr));
963 finalizeErr = GC.finalize(OS);
964 ASSERT_TRUE(bool(finalizeErr));
965 checkError("already finalized", std::move(finalizeErr));
966 // Verify we get an error trying to encode a GsymCreator with a UUID that is
967 // too long.
968 GC.setUUID(InvalidUUID);
969 TestGsymCreatorEncodeError(llvm::support::little, GC,
970 "invalid UUID size 21");
971 GC.setUUID(ValidUUID);
972 // Verify errors are propagated when we try to encoding an invalid line
973 // table.
974 GC.forEachFunctionInfo([](FunctionInfo &FI) -> bool {
975 FI.OptLineTable = LineTable(); // Invalid line table.
976 return false; // Stop iterating
977 });
978 TestGsymCreatorEncodeError(llvm::support::little, GC,
979 "attempted to encode invalid LineTable object");
980 // Verify errors are propagated when we try to encoding an invalid inline
981 // info.
982 GC.forEachFunctionInfo([](FunctionInfo &FI) -> bool {
983 FI.OptLineTable = llvm::None;
984 FI.Inline = InlineInfo(); // Invalid InlineInfo.
985 return false; // Stop iterating
986 });
987 TestGsymCreatorEncodeError(llvm::support::little, GC,
988 "attempted to encode invalid InlineInfo object");
989 }
990
Compare(const GsymCreator & GC,const GsymReader & GR)991 static void Compare(const GsymCreator &GC, const GsymReader &GR) {
992 // Verify that all of the data in a GsymCreator is correctly decoded from
993 // a GsymReader. To do this, we iterator over
994 GC.forEachFunctionInfo([&](const FunctionInfo &FI) -> bool {
995 auto DecodedFI = GR.getFunctionInfo(FI.Range.start());
996 EXPECT_TRUE(bool(DecodedFI));
997 EXPECT_EQ(FI, *DecodedFI);
998 return true; // Keep iterating over all FunctionInfo objects.
999 });
1000 }
1001
TestEncodeDecode(const GsymCreator & GC,support::endianness ByteOrder,uint16_t Version,uint8_t AddrOffSize,uint64_t BaseAddress,uint32_t NumAddresses,ArrayRef<uint8_t> UUID)1002 static void TestEncodeDecode(const GsymCreator &GC,
1003 support::endianness ByteOrder, uint16_t Version,
1004 uint8_t AddrOffSize, uint64_t BaseAddress,
1005 uint32_t NumAddresses, ArrayRef<uint8_t> UUID) {
1006 SmallString<512> Str;
1007 raw_svector_ostream OutStrm(Str);
1008 FileWriter FW(OutStrm, ByteOrder);
1009 llvm::Error Err = GC.encode(FW);
1010 ASSERT_FALSE((bool)Err);
1011 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
1012 ASSERT_TRUE(bool(GR));
1013 const Header &Hdr = GR->getHeader();
1014 EXPECT_EQ(Hdr.Version, Version);
1015 EXPECT_EQ(Hdr.AddrOffSize, AddrOffSize);
1016 EXPECT_EQ(Hdr.UUIDSize, UUID.size());
1017 EXPECT_EQ(Hdr.BaseAddress, BaseAddress);
1018 EXPECT_EQ(Hdr.NumAddresses, NumAddresses);
1019 EXPECT_EQ(ArrayRef<uint8_t>(Hdr.UUID, Hdr.UUIDSize), UUID);
1020 Compare(GC, GR.get());
1021 }
1022
TEST(GSYMTest,TestGsymCreator1ByteAddrOffsets)1023 TEST(GSYMTest, TestGsymCreator1ByteAddrOffsets) {
1024 uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
1025 GsymCreator GC;
1026 GC.setUUID(UUID);
1027 constexpr uint64_t BaseAddr = 0x1000;
1028 constexpr uint8_t AddrOffSize = 1;
1029 const uint32_t Func1Name = GC.insertString("foo");
1030 const uint32_t Func2Name = GC.insertString("bar");
1031 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x00, 0x10, Func1Name));
1032 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x20, 0x10, Func2Name));
1033 Error Err = GC.finalize(llvm::nulls());
1034 ASSERT_FALSE(Err);
1035 TestEncodeDecode(GC, llvm::support::little,
1036 GSYM_VERSION,
1037 AddrOffSize,
1038 BaseAddr,
1039 2, // NumAddresses
1040 ArrayRef<uint8_t>(UUID));
1041 TestEncodeDecode(GC, llvm::support::big,
1042 GSYM_VERSION,
1043 AddrOffSize,
1044 BaseAddr,
1045 2, // NumAddresses
1046 ArrayRef<uint8_t>(UUID));
1047 }
1048
TEST(GSYMTest,TestGsymCreator2ByteAddrOffsets)1049 TEST(GSYMTest, TestGsymCreator2ByteAddrOffsets) {
1050 uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
1051 GsymCreator GC;
1052 GC.setUUID(UUID);
1053 constexpr uint64_t BaseAddr = 0x1000;
1054 constexpr uint8_t AddrOffSize = 2;
1055 const uint32_t Func1Name = GC.insertString("foo");
1056 const uint32_t Func2Name = GC.insertString("bar");
1057 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name));
1058 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x200, 0x100, Func2Name));
1059 Error Err = GC.finalize(llvm::nulls());
1060 ASSERT_FALSE(Err);
1061 TestEncodeDecode(GC, llvm::support::little,
1062 GSYM_VERSION,
1063 AddrOffSize,
1064 BaseAddr,
1065 2, // NumAddresses
1066 ArrayRef<uint8_t>(UUID));
1067 TestEncodeDecode(GC, llvm::support::big,
1068 GSYM_VERSION,
1069 AddrOffSize,
1070 BaseAddr,
1071 2, // NumAddresses
1072 ArrayRef<uint8_t>(UUID));
1073 }
1074
TEST(GSYMTest,TestGsymCreator4ByteAddrOffsets)1075 TEST(GSYMTest, TestGsymCreator4ByteAddrOffsets) {
1076 uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
1077 GsymCreator GC;
1078 GC.setUUID(UUID);
1079 constexpr uint64_t BaseAddr = 0x1000;
1080 constexpr uint8_t AddrOffSize = 4;
1081 const uint32_t Func1Name = GC.insertString("foo");
1082 const uint32_t Func2Name = GC.insertString("bar");
1083 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name));
1084 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x20000, 0x100, Func2Name));
1085 Error Err = GC.finalize(llvm::nulls());
1086 ASSERT_FALSE(Err);
1087 TestEncodeDecode(GC, llvm::support::little,
1088 GSYM_VERSION,
1089 AddrOffSize,
1090 BaseAddr,
1091 2, // NumAddresses
1092 ArrayRef<uint8_t>(UUID));
1093 TestEncodeDecode(GC, llvm::support::big,
1094 GSYM_VERSION,
1095 AddrOffSize,
1096 BaseAddr,
1097 2, // NumAddresses
1098 ArrayRef<uint8_t>(UUID));
1099 }
1100
TEST(GSYMTest,TestGsymCreator8ByteAddrOffsets)1101 TEST(GSYMTest, TestGsymCreator8ByteAddrOffsets) {
1102 uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
1103 GsymCreator GC;
1104 GC.setUUID(UUID);
1105 constexpr uint64_t BaseAddr = 0x1000;
1106 constexpr uint8_t AddrOffSize = 8;
1107 const uint32_t Func1Name = GC.insertString("foo");
1108 const uint32_t Func2Name = GC.insertString("bar");
1109 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name));
1110 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x100000000, 0x100, Func2Name));
1111 Error Err = GC.finalize(llvm::nulls());
1112 ASSERT_FALSE(Err);
1113 TestEncodeDecode(GC, llvm::support::little,
1114 GSYM_VERSION,
1115 AddrOffSize,
1116 BaseAddr,
1117 2, // NumAddresses
1118 ArrayRef<uint8_t>(UUID));
1119 TestEncodeDecode(GC, llvm::support::big,
1120 GSYM_VERSION,
1121 AddrOffSize,
1122 BaseAddr,
1123 2, // NumAddresses
1124 ArrayRef<uint8_t>(UUID));
1125 }
1126
VerifyFunctionInfo(const GsymReader & GR,uint64_t Addr,const FunctionInfo & FI)1127 static void VerifyFunctionInfo(const GsymReader &GR, uint64_t Addr,
1128 const FunctionInfo &FI) {
1129 auto ExpFI = GR.getFunctionInfo(Addr);
1130 ASSERT_TRUE(bool(ExpFI));
1131 ASSERT_EQ(FI, ExpFI.get());
1132 }
1133
VerifyFunctionInfoError(const GsymReader & GR,uint64_t Addr,std::string ErrMessage)1134 static void VerifyFunctionInfoError(const GsymReader &GR, uint64_t Addr,
1135 std::string ErrMessage) {
1136 auto ExpFI = GR.getFunctionInfo(Addr);
1137 ASSERT_FALSE(bool(ExpFI));
1138 checkError(ErrMessage, ExpFI.takeError());
1139 }
1140
TEST(GSYMTest,TestGsymReader)1141 TEST(GSYMTest, TestGsymReader) {
1142 uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
1143 GsymCreator GC;
1144 GC.setUUID(UUID);
1145 constexpr uint64_t BaseAddr = 0x1000;
1146 constexpr uint64_t Func1Addr = BaseAddr;
1147 constexpr uint64_t Func2Addr = BaseAddr+0x20;
1148 constexpr uint64_t FuncSize = 0x10;
1149 const uint32_t Func1Name = GC.insertString("foo");
1150 const uint32_t Func2Name = GC.insertString("bar");
1151 const auto ByteOrder = support::endian::system_endianness();
1152 GC.addFunctionInfo(FunctionInfo(Func1Addr, FuncSize, Func1Name));
1153 GC.addFunctionInfo(FunctionInfo(Func2Addr, FuncSize, Func2Name));
1154 Error FinalizeErr = GC.finalize(llvm::nulls());
1155 ASSERT_FALSE(FinalizeErr);
1156 SmallString<512> Str;
1157 raw_svector_ostream OutStrm(Str);
1158 FileWriter FW(OutStrm, ByteOrder);
1159 llvm::Error Err = GC.encode(FW);
1160 ASSERT_FALSE((bool)Err);
1161 if (auto ExpectedGR = GsymReader::copyBuffer(OutStrm.str())) {
1162 const GsymReader &GR = ExpectedGR.get();
1163 VerifyFunctionInfoError(GR, Func1Addr-1, "address 0xfff is not in GSYM");
1164
1165 FunctionInfo Func1(Func1Addr, FuncSize, Func1Name);
1166 VerifyFunctionInfo(GR, Func1Addr, Func1);
1167 VerifyFunctionInfo(GR, Func1Addr+1, Func1);
1168 VerifyFunctionInfo(GR, Func1Addr+FuncSize-1, Func1);
1169 VerifyFunctionInfoError(GR, Func1Addr+FuncSize,
1170 "address 0x1010 is not in GSYM");
1171 VerifyFunctionInfoError(GR, Func2Addr-1, "address 0x101f is not in GSYM");
1172 FunctionInfo Func2(Func2Addr, FuncSize, Func2Name);
1173 VerifyFunctionInfo(GR, Func2Addr, Func2);
1174 VerifyFunctionInfo(GR, Func2Addr+1, Func2);
1175 VerifyFunctionInfo(GR, Func2Addr+FuncSize-1, Func2);
1176 VerifyFunctionInfoError(GR, Func2Addr+FuncSize,
1177 "address 0x1030 is not in GSYM");
1178 }
1179 }
1180
TEST(GSYMTest,TestGsymLookups)1181 TEST(GSYMTest, TestGsymLookups) {
1182 // Test creating a GSYM file with a function that has a inline information.
1183 // Verify that lookups work correctly. Lookups do not decode the entire
1184 // FunctionInfo or InlineInfo, they only extract information needed for the
1185 // lookup to happen which avoids allocations which can slow down
1186 // symbolication.
1187 GsymCreator GC;
1188 FunctionInfo FI(0x1000, 0x100, GC.insertString("main"));
1189 const auto ByteOrder = support::endian::system_endianness();
1190 FI.OptLineTable = LineTable();
1191 const uint32_t MainFileIndex = GC.insertFile("/tmp/main.c");
1192 const uint32_t FooFileIndex = GC.insertFile("/tmp/foo.h");
1193 FI.OptLineTable->push(LineEntry(0x1000, MainFileIndex, 5));
1194 FI.OptLineTable->push(LineEntry(0x1010, FooFileIndex, 10));
1195 FI.OptLineTable->push(LineEntry(0x1012, FooFileIndex, 20));
1196 FI.OptLineTable->push(LineEntry(0x1014, FooFileIndex, 11));
1197 FI.OptLineTable->push(LineEntry(0x1016, FooFileIndex, 30));
1198 FI.OptLineTable->push(LineEntry(0x1018, FooFileIndex, 12));
1199 FI.OptLineTable->push(LineEntry(0x1020, MainFileIndex, 8));
1200 FI.Inline = InlineInfo();
1201
1202 FI.Inline->Name = GC.insertString("inline1");
1203 FI.Inline->CallFile = MainFileIndex;
1204 FI.Inline->CallLine = 6;
1205 FI.Inline->Ranges.insert(AddressRange(0x1010, 0x1020));
1206 InlineInfo Inline2;
1207 Inline2.Name = GC.insertString("inline2");
1208 Inline2.CallFile = FooFileIndex;
1209 Inline2.CallLine = 33;
1210 Inline2.Ranges.insert(AddressRange(0x1012, 0x1014));
1211 FI.Inline->Children.emplace_back(Inline2);
1212 InlineInfo Inline3;
1213 Inline3.Name = GC.insertString("inline3");
1214 Inline3.CallFile = FooFileIndex;
1215 Inline3.CallLine = 35;
1216 Inline3.Ranges.insert(AddressRange(0x1016, 0x1018));
1217 FI.Inline->Children.emplace_back(Inline3);
1218 GC.addFunctionInfo(std::move(FI));
1219 Error FinalizeErr = GC.finalize(llvm::nulls());
1220 ASSERT_FALSE(FinalizeErr);
1221 SmallString<512> Str;
1222 raw_svector_ostream OutStrm(Str);
1223 FileWriter FW(OutStrm, ByteOrder);
1224 llvm::Error Err = GC.encode(FW);
1225 ASSERT_FALSE((bool)Err);
1226 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
1227 ASSERT_TRUE(bool(GR));
1228
1229 // Verify inline info is correct when doing lookups.
1230 auto LR = GR->lookup(0x1000);
1231 ASSERT_THAT_EXPECTED(LR, Succeeded());
1232 EXPECT_THAT(LR->Locations,
1233 testing::ElementsAre(SourceLocation{"main", "/tmp", "main.c", 5}));
1234 LR = GR->lookup(0x100F);
1235 ASSERT_THAT_EXPECTED(LR, Succeeded());
1236 EXPECT_THAT(LR->Locations,
1237 testing::ElementsAre(SourceLocation{"main", "/tmp", "main.c", 5, 15}));
1238
1239 LR = GR->lookup(0x1010);
1240 ASSERT_THAT_EXPECTED(LR, Succeeded());
1241
1242 EXPECT_THAT(LR->Locations,
1243 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "foo.h", 10},
1244 SourceLocation{"main", "/tmp", "main.c", 6, 16}));
1245
1246 LR = GR->lookup(0x1012);
1247 ASSERT_THAT_EXPECTED(LR, Succeeded());
1248 EXPECT_THAT(LR->Locations,
1249 testing::ElementsAre(SourceLocation{"inline2", "/tmp", "foo.h", 20},
1250 SourceLocation{"inline1", "/tmp", "foo.h", 33, 2},
1251 SourceLocation{"main", "/tmp", "main.c", 6, 18}));
1252
1253 LR = GR->lookup(0x1014);
1254 ASSERT_THAT_EXPECTED(LR, Succeeded());
1255 EXPECT_THAT(LR->Locations,
1256 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "foo.h", 11, 4},
1257 SourceLocation{"main", "/tmp", "main.c", 6, 20}));
1258
1259 LR = GR->lookup(0x1016);
1260 ASSERT_THAT_EXPECTED(LR, Succeeded());
1261 EXPECT_THAT(LR->Locations,
1262 testing::ElementsAre(SourceLocation{"inline3", "/tmp", "foo.h", 30},
1263 SourceLocation{"inline1", "/tmp", "foo.h", 35, 6},
1264 SourceLocation{"main", "/tmp", "main.c", 6, 22}));
1265
1266 LR = GR->lookup(0x1018);
1267 ASSERT_THAT_EXPECTED(LR, Succeeded());
1268 EXPECT_THAT(LR->Locations,
1269 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "foo.h", 12, 8},
1270 SourceLocation{"main", "/tmp", "main.c", 6, 24}));
1271
1272 LR = GR->lookup(0x1020);
1273 ASSERT_THAT_EXPECTED(LR, Succeeded());
1274 EXPECT_THAT(LR->Locations,
1275 testing::ElementsAre(SourceLocation{"main", "/tmp", "main.c", 8, 32}));
1276 }
1277
1278
TEST(GSYMTest,TestDWARFFunctionWithAddresses)1279 TEST(GSYMTest, TestDWARFFunctionWithAddresses) {
1280 // Create a single compile unit with a single function and make sure it gets
1281 // converted to DWARF correctly. The function's address range is in where
1282 // DW_AT_low_pc and DW_AT_high_pc are both addresses.
1283 StringRef yamldata = R"(
1284 debug_str:
1285 - ''
1286 - /tmp/main.c
1287 - main
1288 debug_abbrev:
1289 - Table:
1290 - Code: 0x00000001
1291 Tag: DW_TAG_compile_unit
1292 Children: DW_CHILDREN_yes
1293 Attributes:
1294 - Attribute: DW_AT_name
1295 Form: DW_FORM_strp
1296 - Attribute: DW_AT_low_pc
1297 Form: DW_FORM_addr
1298 - Attribute: DW_AT_high_pc
1299 Form: DW_FORM_addr
1300 - Attribute: DW_AT_language
1301 Form: DW_FORM_data2
1302 - Code: 0x00000002
1303 Tag: DW_TAG_subprogram
1304 Children: DW_CHILDREN_no
1305 Attributes:
1306 - Attribute: DW_AT_name
1307 Form: DW_FORM_strp
1308 - Attribute: DW_AT_low_pc
1309 Form: DW_FORM_addr
1310 - Attribute: DW_AT_high_pc
1311 Form: DW_FORM_addr
1312 debug_info:
1313 - Version: 4
1314 AddrSize: 8
1315 Entries:
1316 - AbbrCode: 0x00000001
1317 Values:
1318 - Value: 0x0000000000000001
1319 - Value: 0x0000000000001000
1320 - Value: 0x0000000000002000
1321 - Value: 0x0000000000000004
1322 - AbbrCode: 0x00000002
1323 Values:
1324 - Value: 0x000000000000000D
1325 - Value: 0x0000000000001000
1326 - Value: 0x0000000000002000
1327 - AbbrCode: 0x00000000
1328 )";
1329 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata);
1330 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded());
1331 std::unique_ptr<DWARFContext> DwarfContext =
1332 DWARFContext::create(*ErrOrSections, 8);
1333 ASSERT_TRUE(DwarfContext.get() != nullptr);
1334 auto &OS = llvm::nulls();
1335 GsymCreator GC;
1336 DwarfTransformer DT(*DwarfContext, OS, GC);
1337 const uint32_t ThreadCount = 1;
1338 ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded());
1339 ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
1340 SmallString<512> Str;
1341 raw_svector_ostream OutStrm(Str);
1342 const auto ByteOrder = support::endian::system_endianness();
1343 FileWriter FW(OutStrm, ByteOrder);
1344 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded());
1345 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
1346 ASSERT_THAT_EXPECTED(GR, Succeeded());
1347 // There should only be one function in our GSYM.
1348 EXPECT_EQ(GR->getNumAddresses(), 1u);
1349 auto ExpFI = GR->getFunctionInfo(0x1000);
1350 ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
1351 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000));
1352 EXPECT_FALSE(ExpFI->OptLineTable.has_value());
1353 EXPECT_FALSE(ExpFI->Inline.has_value());
1354 }
1355
TEST(GSYMTest,TestDWARFFunctionWithAddressAndOffset)1356 TEST(GSYMTest, TestDWARFFunctionWithAddressAndOffset) {
1357 // Create a single compile unit with a single function and make sure it gets
1358 // converted to DWARF correctly. The function's address range is in where
1359 // DW_AT_low_pc is an address and the DW_AT_high_pc is an offset.
1360 StringRef yamldata = R"(
1361 debug_str:
1362 - ''
1363 - /tmp/main.c
1364 - main
1365 debug_abbrev:
1366 - Table:
1367 - Code: 0x00000001
1368 Tag: DW_TAG_compile_unit
1369 Children: DW_CHILDREN_yes
1370 Attributes:
1371 - Attribute: DW_AT_name
1372 Form: DW_FORM_strp
1373 - Attribute: DW_AT_low_pc
1374 Form: DW_FORM_addr
1375 - Attribute: DW_AT_high_pc
1376 Form: DW_FORM_data4
1377 - Attribute: DW_AT_language
1378 Form: DW_FORM_data2
1379 - Code: 0x00000002
1380 Tag: DW_TAG_subprogram
1381 Children: DW_CHILDREN_no
1382 Attributes:
1383 - Attribute: DW_AT_name
1384 Form: DW_FORM_strp
1385 - Attribute: DW_AT_low_pc
1386 Form: DW_FORM_addr
1387 - Attribute: DW_AT_high_pc
1388 Form: DW_FORM_data4
1389 debug_info:
1390 - Version: 4
1391 AddrSize: 8
1392 Entries:
1393 - AbbrCode: 0x00000001
1394 Values:
1395 - Value: 0x0000000000000001
1396 - Value: 0x0000000000001000
1397 - Value: 0x0000000000001000
1398 - Value: 0x0000000000000004
1399 - AbbrCode: 0x00000002
1400 Values:
1401 - Value: 0x000000000000000D
1402 - Value: 0x0000000000001000
1403 - Value: 0x0000000000001000
1404 - AbbrCode: 0x00000000
1405 )";
1406 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata);
1407 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded());
1408 std::unique_ptr<DWARFContext> DwarfContext =
1409 DWARFContext::create(*ErrOrSections, 8);
1410 ASSERT_TRUE(DwarfContext.get() != nullptr);
1411 auto &OS = llvm::nulls();
1412 GsymCreator GC;
1413 DwarfTransformer DT(*DwarfContext, OS, GC);
1414 const uint32_t ThreadCount = 1;
1415 ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded());
1416 ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
1417 SmallString<512> Str;
1418 raw_svector_ostream OutStrm(Str);
1419 const auto ByteOrder = support::endian::system_endianness();
1420 FileWriter FW(OutStrm, ByteOrder);
1421 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded());
1422 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
1423 ASSERT_THAT_EXPECTED(GR, Succeeded());
1424 // There should only be one function in our GSYM.
1425 EXPECT_EQ(GR->getNumAddresses(), 1u);
1426 auto ExpFI = GR->getFunctionInfo(0x1000);
1427 ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
1428 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000));
1429 EXPECT_FALSE(ExpFI->OptLineTable.has_value());
1430 EXPECT_FALSE(ExpFI->Inline.has_value());
1431 }
1432
TEST(GSYMTest,TestDWARFStructMethodNoMangled)1433 TEST(GSYMTest, TestDWARFStructMethodNoMangled) {
1434 // Sometimes the compiler will omit the mangled name in the DWARF for static
1435 // and member functions of classes and structs. This test verifies that the
1436 // fully qualified name of the method is computed and used as the string for
1437 // the function in the GSYM in these cases. Otherwise we might just get a
1438 // function name like "erase" instead of "std::vector<int>::erase".
1439 StringRef yamldata = R"(
1440 debug_str:
1441 - ''
1442 - /tmp/main.c
1443 - Foo
1444 - dump
1445 - this
1446 debug_abbrev:
1447 - Table:
1448 - Code: 0x00000001
1449 Tag: DW_TAG_compile_unit
1450 Children: DW_CHILDREN_yes
1451 Attributes:
1452 - Attribute: DW_AT_name
1453 Form: DW_FORM_strp
1454 - Attribute: DW_AT_low_pc
1455 Form: DW_FORM_addr
1456 - Attribute: DW_AT_high_pc
1457 Form: DW_FORM_addr
1458 - Attribute: DW_AT_language
1459 Form: DW_FORM_data2
1460 - Code: 0x00000002
1461 Tag: DW_TAG_structure_type
1462 Children: DW_CHILDREN_yes
1463 Attributes:
1464 - Attribute: DW_AT_name
1465 Form: DW_FORM_strp
1466 - Code: 0x00000003
1467 Tag: DW_TAG_subprogram
1468 Children: DW_CHILDREN_yes
1469 Attributes:
1470 - Attribute: DW_AT_name
1471 Form: DW_FORM_strp
1472 - Attribute: DW_AT_low_pc
1473 Form: DW_FORM_addr
1474 - Attribute: DW_AT_high_pc
1475 Form: DW_FORM_addr
1476 - Code: 0x00000004
1477 Tag: DW_TAG_formal_parameter
1478 Children: DW_CHILDREN_no
1479 Attributes:
1480 - Attribute: DW_AT_name
1481 Form: DW_FORM_strp
1482 - Attribute: DW_AT_type
1483 Form: DW_FORM_ref4
1484 - Attribute: DW_AT_artificial
1485 Form: DW_FORM_flag_present
1486 debug_info:
1487 - Version: 4
1488 AddrSize: 8
1489 Entries:
1490 - AbbrCode: 0x00000001
1491 Values:
1492 - Value: 0x0000000000000001
1493 - Value: 0x0000000000001000
1494 - Value: 0x0000000000002000
1495 - Value: 0x0000000000000004
1496 - AbbrCode: 0x00000002
1497 Values:
1498 - Value: 0x000000000000000D
1499 - AbbrCode: 0x00000003
1500 Values:
1501 - Value: 0x0000000000000011
1502 - Value: 0x0000000000001000
1503 - Value: 0x0000000000002000
1504 - AbbrCode: 0x00000004
1505 Values:
1506 - Value: 0x0000000000000016
1507 - Value: 0x0000000000000022
1508 - Value: 0x0000000000000001
1509 - AbbrCode: 0x00000000
1510 - AbbrCode: 0x00000000
1511 - AbbrCode: 0x00000000
1512 )";
1513 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata);
1514 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded());
1515 std::unique_ptr<DWARFContext> DwarfContext =
1516 DWARFContext::create(*ErrOrSections, 8);
1517 ASSERT_TRUE(DwarfContext.get() != nullptr);
1518 auto &OS = llvm::nulls();
1519 GsymCreator GC;
1520 DwarfTransformer DT(*DwarfContext, OS, GC);
1521 const uint32_t ThreadCount = 1;
1522 ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded());
1523 ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
1524 SmallString<512> Str;
1525 raw_svector_ostream OutStrm(Str);
1526 const auto ByteOrder = support::endian::system_endianness();
1527 FileWriter FW(OutStrm, ByteOrder);
1528 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded());
1529 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
1530 ASSERT_THAT_EXPECTED(GR, Succeeded());
1531 // There should only be one function in our GSYM.
1532 EXPECT_EQ(GR->getNumAddresses(), 1u);
1533 auto ExpFI = GR->getFunctionInfo(0x1000);
1534 ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
1535 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000));
1536 EXPECT_FALSE(ExpFI->OptLineTable.has_value());
1537 EXPECT_FALSE(ExpFI->Inline.has_value());
1538 StringRef MethodName = GR->getString(ExpFI->Name);
1539 EXPECT_EQ(MethodName, "Foo::dump");
1540 }
1541
TEST(GSYMTest,TestDWARFTextRanges)1542 TEST(GSYMTest, TestDWARFTextRanges) {
1543 // Linkers don't understand DWARF, they just like to concatenate and
1544 // relocate data within the DWARF sections. This means that if a function
1545 // gets dead stripped, and if those functions use an offset as the
1546 // DW_AT_high_pc, we can end up with many functions at address zero. The
1547 // DwarfTransformer allows clients to specify valid .text address ranges
1548 // and any addresses of any functions must fall within those ranges if any
1549 // have been specified. This means that an object file can calcuate the
1550 // address ranges within the binary where code lives and set these ranges
1551 // as constraints in the DwarfTransformer. ObjectFile instances can
1552 // add a address ranges of sections that have executable permissions. This
1553 // keeps bad information from being added to a GSYM file and causing issues
1554 // when symbolicating.
1555 StringRef yamldata = R"(
1556 debug_str:
1557 - ''
1558 - /tmp/main.c
1559 - main
1560 - dead_stripped
1561 - dead_stripped2
1562 debug_abbrev:
1563 - Table:
1564 - Code: 0x00000001
1565 Tag: DW_TAG_compile_unit
1566 Children: DW_CHILDREN_yes
1567 Attributes:
1568 - Attribute: DW_AT_name
1569 Form: DW_FORM_strp
1570 - Attribute: DW_AT_low_pc
1571 Form: DW_FORM_addr
1572 - Attribute: DW_AT_high_pc
1573 Form: DW_FORM_data4
1574 - Attribute: DW_AT_language
1575 Form: DW_FORM_data2
1576 - Code: 0x00000002
1577 Tag: DW_TAG_subprogram
1578 Children: DW_CHILDREN_no
1579 Attributes:
1580 - Attribute: DW_AT_name
1581 Form: DW_FORM_strp
1582 - Attribute: DW_AT_low_pc
1583 Form: DW_FORM_addr
1584 - Attribute: DW_AT_high_pc
1585 Form: DW_FORM_data4
1586 debug_info:
1587 - Version: 4
1588 AddrSize: 8
1589 Entries:
1590 - AbbrCode: 0x00000001
1591 Values:
1592 - Value: 0x0000000000000001
1593 - Value: 0x0000000000001000
1594 - Value: 0x0000000000001000
1595 - Value: 0x0000000000000004
1596 - AbbrCode: 0x00000002
1597 Values:
1598 - Value: 0x000000000000000D
1599 - Value: 0x0000000000001000
1600 - Value: 0x0000000000001000
1601 - AbbrCode: 0x00000002
1602 Values:
1603 - Value: 0x0000000000000012
1604 - Value: 0x0000000000000000
1605 - Value: 0x0000000000000100
1606 - AbbrCode: 0x00000002
1607 Values:
1608 - Value: 0x0000000000000020
1609 - Value: 0x0000000000000000
1610 - Value: 0x0000000000000040
1611 - AbbrCode: 0x00000000
1612 )";
1613 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata);
1614 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded());
1615 std::unique_ptr<DWARFContext> DwarfContext =
1616 DWARFContext::create(*ErrOrSections, 8);
1617 ASSERT_TRUE(DwarfContext.get() != nullptr);
1618 auto &OS = llvm::nulls();
1619 GsymCreator GC;
1620 DwarfTransformer DT(*DwarfContext, OS, GC);
1621 // Only allow addresses between [0x1000 - 0x2000) to be linked into the
1622 // GSYM.
1623 AddressRanges TextRanges;
1624 TextRanges.insert(AddressRange(0x1000, 0x2000));
1625 GC.SetValidTextRanges(TextRanges);
1626 const uint32_t ThreadCount = 1;
1627 ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded());
1628 ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
1629 SmallString<512> Str;
1630 raw_svector_ostream OutStrm(Str);
1631 const auto ByteOrder = support::endian::system_endianness();
1632 FileWriter FW(OutStrm, ByteOrder);
1633 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded());
1634 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
1635 ASSERT_THAT_EXPECTED(GR, Succeeded());
1636 // There should only be one function in our GSYM.
1637 EXPECT_EQ(GR->getNumAddresses(), 1u);
1638 auto ExpFI = GR->getFunctionInfo(0x1000);
1639 ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
1640 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000));
1641 EXPECT_FALSE(ExpFI->OptLineTable.has_value());
1642 EXPECT_FALSE(ExpFI->Inline.has_value());
1643 StringRef MethodName = GR->getString(ExpFI->Name);
1644 EXPECT_EQ(MethodName, "main");
1645 }
1646
TEST(GSYMTest,TestEmptySymbolEndAddressOfTextRanges)1647 TEST(GSYMTest, TestEmptySymbolEndAddressOfTextRanges) {
1648 // Test that if we have valid text ranges and we have a symbol with no size
1649 // as the last FunctionInfo entry that the size of the symbol gets set to the
1650 // end address of the text range.
1651 GsymCreator GC;
1652 AddressRanges TextRanges;
1653 TextRanges.insert(AddressRange(0x1000, 0x2000));
1654 GC.SetValidTextRanges(TextRanges);
1655 GC.addFunctionInfo(FunctionInfo(0x1500, 0, GC.insertString("symbol")));
1656 auto &OS = llvm::nulls();
1657 ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
1658 SmallString<512> Str;
1659 raw_svector_ostream OutStrm(Str);
1660 const auto ByteOrder = support::endian::system_endianness();
1661 FileWriter FW(OutStrm, ByteOrder);
1662 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded());
1663 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
1664 ASSERT_THAT_EXPECTED(GR, Succeeded());
1665 // There should only be one function in our GSYM.
1666 EXPECT_EQ(GR->getNumAddresses(), 1u);
1667 auto ExpFI = GR->getFunctionInfo(0x1500);
1668 ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
1669 ASSERT_EQ(ExpFI->Range, AddressRange(0x1500, 0x2000));
1670 EXPECT_FALSE(ExpFI->OptLineTable.has_value());
1671 EXPECT_FALSE(ExpFI->Inline.has_value());
1672 StringRef MethodName = GR->getString(ExpFI->Name);
1673 EXPECT_EQ(MethodName, "symbol");
1674 }
1675
TEST(GSYMTest,TestDWARFInlineInfo)1676 TEST(GSYMTest, TestDWARFInlineInfo) {
1677 // Make sure we parse the line table and inline information correctly from
1678 // DWARF.
1679 StringRef yamldata = R"(
1680 debug_str:
1681 - ''
1682 - /tmp/main.c
1683 - main
1684 - inline1
1685 debug_abbrev:
1686 - Table:
1687 - Code: 0x00000001
1688 Tag: DW_TAG_compile_unit
1689 Children: DW_CHILDREN_yes
1690 Attributes:
1691 - Attribute: DW_AT_name
1692 Form: DW_FORM_strp
1693 - Attribute: DW_AT_low_pc
1694 Form: DW_FORM_addr
1695 - Attribute: DW_AT_high_pc
1696 Form: DW_FORM_data4
1697 - Attribute: DW_AT_language
1698 Form: DW_FORM_data2
1699 - Attribute: DW_AT_stmt_list
1700 Form: DW_FORM_sec_offset
1701 - Code: 0x00000002
1702 Tag: DW_TAG_subprogram
1703 Children: DW_CHILDREN_yes
1704 Attributes:
1705 - Attribute: DW_AT_name
1706 Form: DW_FORM_strp
1707 - Attribute: DW_AT_low_pc
1708 Form: DW_FORM_addr
1709 - Attribute: DW_AT_high_pc
1710 Form: DW_FORM_data4
1711 - Code: 0x00000003
1712 Tag: DW_TAG_inlined_subroutine
1713 Children: DW_CHILDREN_no
1714 Attributes:
1715 - Attribute: DW_AT_name
1716 Form: DW_FORM_strp
1717 - Attribute: DW_AT_low_pc
1718 Form: DW_FORM_addr
1719 - Attribute: DW_AT_high_pc
1720 Form: DW_FORM_data4
1721 - Attribute: DW_AT_call_file
1722 Form: DW_FORM_data4
1723 - Attribute: DW_AT_call_line
1724 Form: DW_FORM_data4
1725 debug_info:
1726 - Version: 4
1727 AddrSize: 8
1728 Entries:
1729 - AbbrCode: 0x00000001
1730 Values:
1731 - Value: 0x0000000000000001
1732 - Value: 0x0000000000001000
1733 - Value: 0x0000000000001000
1734 - Value: 0x0000000000000004
1735 - Value: 0x0000000000000000
1736 - AbbrCode: 0x00000002
1737 Values:
1738 - Value: 0x000000000000000D
1739 - Value: 0x0000000000001000
1740 - Value: 0x0000000000001000
1741 - AbbrCode: 0x00000003
1742 Values:
1743 - Value: 0x0000000000000012
1744 - Value: 0x0000000000001100
1745 - Value: 0x0000000000000100
1746 - Value: 0x0000000000000001
1747 - Value: 0x000000000000000A
1748 - AbbrCode: 0x00000000
1749 - AbbrCode: 0x00000000
1750 debug_line:
1751 - Length: 96
1752 Version: 2
1753 PrologueLength: 46
1754 MinInstLength: 1
1755 DefaultIsStmt: 1
1756 LineBase: 251
1757 LineRange: 14
1758 OpcodeBase: 13
1759 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
1760 IncludeDirs:
1761 - /tmp
1762 Files:
1763 - Name: main.c
1764 DirIdx: 1
1765 ModTime: 0
1766 Length: 0
1767 - Name: inline.h
1768 DirIdx: 1
1769 ModTime: 0
1770 Length: 0
1771 Opcodes:
1772 - Opcode: DW_LNS_extended_op
1773 ExtLen: 9
1774 SubOpcode: DW_LNE_set_address
1775 Data: 4096
1776 - Opcode: DW_LNS_advance_line
1777 SData: 9
1778 Data: 4096
1779 - Opcode: DW_LNS_copy
1780 Data: 4096
1781 - Opcode: DW_LNS_advance_pc
1782 Data: 256
1783 - Opcode: DW_LNS_set_file
1784 Data: 2
1785 - Opcode: DW_LNS_advance_line
1786 SData: 10
1787 Data: 2
1788 - Opcode: DW_LNS_copy
1789 Data: 2
1790 - Opcode: DW_LNS_advance_pc
1791 Data: 128
1792 - Opcode: DW_LNS_advance_line
1793 SData: 1
1794 Data: 128
1795 - Opcode: DW_LNS_copy
1796 Data: 128
1797 - Opcode: DW_LNS_advance_pc
1798 Data: 128
1799 - Opcode: DW_LNS_set_file
1800 Data: 1
1801 - Opcode: DW_LNS_advance_line
1802 SData: -10
1803 Data: 1
1804 - Opcode: DW_LNS_copy
1805 Data: 1
1806 - Opcode: DW_LNS_advance_pc
1807 Data: 3584
1808 - Opcode: DW_LNS_advance_line
1809 SData: 1
1810 Data: 3584
1811 - Opcode: DW_LNS_extended_op
1812 ExtLen: 1
1813 SubOpcode: DW_LNE_end_sequence
1814 Data: 3584
1815 )";
1816 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata);
1817 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded());
1818 std::unique_ptr<DWARFContext> DwarfContext =
1819 DWARFContext::create(*ErrOrSections, 8);
1820 ASSERT_TRUE(DwarfContext.get() != nullptr);
1821 auto &OS = llvm::nulls();
1822 GsymCreator GC;
1823 DwarfTransformer DT(*DwarfContext, OS, GC);
1824 const uint32_t ThreadCount = 1;
1825 ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded());
1826 ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
1827 SmallString<512> Str;
1828 raw_svector_ostream OutStrm(Str);
1829 const auto ByteOrder = support::endian::system_endianness();
1830 FileWriter FW(OutStrm, ByteOrder);
1831 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded());
1832 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
1833 ASSERT_THAT_EXPECTED(GR, Succeeded());
1834 // There should only be one function in our GSYM.
1835 EXPECT_EQ(GR->getNumAddresses(), 1u);
1836 auto ExpFI = GR->getFunctionInfo(0x1000);
1837 ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
1838 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000));
1839 EXPECT_TRUE(ExpFI->OptLineTable.has_value());
1840 EXPECT_TRUE(ExpFI->Inline.has_value());
1841 StringRef MethodName = GR->getString(ExpFI->Name);
1842 EXPECT_EQ(MethodName, "main");
1843
1844 // Verify inline info is correct when doing lookups.
1845 auto LR = GR->lookup(0x1000);
1846 ASSERT_THAT_EXPECTED(LR, Succeeded());
1847 EXPECT_THAT(LR->Locations,
1848 testing::ElementsAre(SourceLocation{"main", "/tmp", "main.c", 10}));
1849 LR = GR->lookup(0x1100-1);
1850 ASSERT_THAT_EXPECTED(LR, Succeeded());
1851 EXPECT_THAT(LR->Locations,
1852 testing::ElementsAre(SourceLocation{"main", "/tmp", "main.c", 10, 255}));
1853
1854 LR = GR->lookup(0x1100);
1855 ASSERT_THAT_EXPECTED(LR, Succeeded());
1856 EXPECT_THAT(LR->Locations,
1857 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "inline.h", 20},
1858 SourceLocation{"main", "/tmp", "main.c", 10, 256}));
1859 LR = GR->lookup(0x1180-1);
1860 ASSERT_THAT_EXPECTED(LR, Succeeded());
1861 EXPECT_THAT(LR->Locations,
1862 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "inline.h", 20, 127},
1863 SourceLocation{"main", "/tmp", "main.c", 10, 383}));
1864 LR = GR->lookup(0x1180);
1865 ASSERT_THAT_EXPECTED(LR, Succeeded());
1866 EXPECT_THAT(LR->Locations,
1867 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "inline.h", 21, 128},
1868 SourceLocation{"main", "/tmp", "main.c", 10, 384}));
1869 LR = GR->lookup(0x1200-1);
1870 ASSERT_THAT_EXPECTED(LR, Succeeded());
1871 EXPECT_THAT(LR->Locations,
1872 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "inline.h", 21, 255},
1873 SourceLocation{"main", "/tmp", "main.c", 10, 511}));
1874 LR = GR->lookup(0x1200);
1875 ASSERT_THAT_EXPECTED(LR, Succeeded());
1876 EXPECT_THAT(LR->Locations,
1877 testing::ElementsAre(SourceLocation{"main", "/tmp", "main.c", 11, 512}));
1878 }
1879
1880
TEST(GSYMTest,TestDWARFNoLines)1881 TEST(GSYMTest, TestDWARFNoLines) {
1882 // Check that if a DW_TAG_subprogram doesn't have line table entries that
1883 // we fall back and use the DW_AT_decl_file and DW_AT_decl_line to at least
1884 // point to the function definition. This DWARF file has 4 functions:
1885 // "lines_no_decl": has line table entries, no DW_AT_decl_file/line attrs.
1886 // "lines_with_decl": has line table entries and has DW_AT_decl_file/line,
1887 // make sure we don't use DW_AT_decl_file/line and make
1888 // sure there is a line table.
1889 // "no_lines_no_decl": no line table entries and no DW_AT_decl_file/line,
1890 // make sure there is no line table for this function.
1891 // "no_lines_with_decl": no line table and has DW_AT_decl_file/line, make
1892 // sure we have one line table entry that starts at
1893 // the function start address and the decl file and
1894 // line.
1895 //
1896 // 0x0000000b: DW_TAG_compile_unit
1897 // DW_AT_name ("/tmp/main.c")
1898 // DW_AT_low_pc (0x0000000000001000)
1899 // DW_AT_high_pc (0x0000000000002000)
1900 // DW_AT_language (DW_LANG_C_plus_plus)
1901 // DW_AT_stmt_list (0x00000000)
1902 //
1903 // 0x00000022: DW_TAG_subprogram
1904 // DW_AT_name ("lines_no_decl")
1905 // DW_AT_low_pc (0x0000000000001000)
1906 // DW_AT_high_pc (0x0000000000002000)
1907 //
1908 // 0x00000033: DW_TAG_subprogram
1909 // DW_AT_name ("lines_with_decl")
1910 // DW_AT_low_pc (0x0000000000002000)
1911 // DW_AT_high_pc (0x0000000000003000)
1912 // DW_AT_decl_file ("/tmp/main.c")
1913 // DW_AT_decl_line (20)
1914 //
1915 // 0x00000046: DW_TAG_subprogram
1916 // DW_AT_name ("no_lines_no_decl")
1917 // DW_AT_low_pc (0x0000000000003000)
1918 // DW_AT_high_pc (0x0000000000004000)
1919 //
1920 // 0x00000057: DW_TAG_subprogram
1921 // DW_AT_name ("no_lines_with_decl")
1922 // DW_AT_low_pc (0x0000000000004000)
1923 // DW_AT_high_pc (0x0000000000005000)
1924 // DW_AT_decl_file ("/tmp/main.c")
1925 // DW_AT_decl_line (40)
1926 //
1927 // 0x0000006a: NULL
1928
1929 StringRef yamldata = R"(
1930 debug_str:
1931 - ''
1932 - '/tmp/main.c'
1933 - lines_no_decl
1934 - lines_with_decl
1935 - no_lines_no_decl
1936 - no_lines_with_decl
1937 debug_abbrev:
1938 - Table:
1939 - Code: 0x00000001
1940 Tag: DW_TAG_compile_unit
1941 Children: DW_CHILDREN_yes
1942 Attributes:
1943 - Attribute: DW_AT_name
1944 Form: DW_FORM_strp
1945 - Attribute: DW_AT_low_pc
1946 Form: DW_FORM_addr
1947 - Attribute: DW_AT_high_pc
1948 Form: DW_FORM_data4
1949 - Attribute: DW_AT_language
1950 Form: DW_FORM_data2
1951 - Attribute: DW_AT_stmt_list
1952 Form: DW_FORM_sec_offset
1953 - Code: 0x00000002
1954 Tag: DW_TAG_subprogram
1955 Children: DW_CHILDREN_no
1956 Attributes:
1957 - Attribute: DW_AT_name
1958 Form: DW_FORM_strp
1959 - Attribute: DW_AT_low_pc
1960 Form: DW_FORM_addr
1961 - Attribute: DW_AT_high_pc
1962 Form: DW_FORM_data4
1963 - Code: 0x00000003
1964 Tag: DW_TAG_subprogram
1965 Children: DW_CHILDREN_no
1966 Attributes:
1967 - Attribute: DW_AT_name
1968 Form: DW_FORM_strp
1969 - Attribute: DW_AT_low_pc
1970 Form: DW_FORM_addr
1971 - Attribute: DW_AT_high_pc
1972 Form: DW_FORM_data4
1973 - Attribute: DW_AT_decl_file
1974 Form: DW_FORM_data1
1975 - Attribute: DW_AT_decl_line
1976 Form: DW_FORM_data1
1977 debug_info:
1978 - Version: 4
1979 AddrSize: 8
1980 Entries:
1981 - AbbrCode: 0x00000001
1982 Values:
1983 - Value: 0x0000000000000001
1984 - Value: 0x0000000000001000
1985 - Value: 0x0000000000001000
1986 - Value: 0x0000000000000004
1987 - Value: 0x0000000000000000
1988 - AbbrCode: 0x00000002
1989 Values:
1990 - Value: 0x000000000000000D
1991 - Value: 0x0000000000001000
1992 - Value: 0x0000000000001000
1993 - AbbrCode: 0x00000003
1994 Values:
1995 - Value: 0x000000000000001B
1996 - Value: 0x0000000000002000
1997 - Value: 0x0000000000001000
1998 - Value: 0x0000000000000001
1999 - Value: 0x0000000000000014
2000 - AbbrCode: 0x00000002
2001 Values:
2002 - Value: 0x000000000000002B
2003 - Value: 0x0000000000003000
2004 - Value: 0x0000000000001000
2005 - AbbrCode: 0x00000003
2006 Values:
2007 - Value: 0x000000000000003C
2008 - Value: 0x0000000000004000
2009 - Value: 0x0000000000001000
2010 - Value: 0x0000000000000001
2011 - Value: 0x0000000000000028
2012 - AbbrCode: 0x00000000
2013 debug_line:
2014 - Length: 92
2015 Version: 2
2016 PrologueLength: 34
2017 MinInstLength: 1
2018 DefaultIsStmt: 1
2019 LineBase: 251
2020 LineRange: 14
2021 OpcodeBase: 13
2022 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
2023 IncludeDirs:
2024 - '/tmp'
2025 Files:
2026 - Name: main.c
2027 DirIdx: 1
2028 ModTime: 0
2029 Length: 0
2030 Opcodes:
2031 - Opcode: DW_LNS_extended_op
2032 ExtLen: 9
2033 SubOpcode: DW_LNE_set_address
2034 Data: 4096
2035 - Opcode: DW_LNS_advance_line
2036 SData: 10
2037 Data: 0
2038 - Opcode: DW_LNS_copy
2039 Data: 0
2040 - Opcode: DW_LNS_advance_pc
2041 Data: 512
2042 - Opcode: DW_LNS_advance_line
2043 SData: 1
2044 Data: 0
2045 - Opcode: DW_LNS_copy
2046 Data: 0
2047 - Opcode: DW_LNS_advance_pc
2048 Data: 3584
2049 - Opcode: DW_LNS_extended_op
2050 ExtLen: 1
2051 SubOpcode: DW_LNE_end_sequence
2052 Data: 0
2053 - Opcode: DW_LNS_extended_op
2054 ExtLen: 9
2055 SubOpcode: DW_LNE_set_address
2056 Data: 8192
2057 - Opcode: DW_LNS_advance_line
2058 SData: 20
2059 Data: 0
2060 - Opcode: DW_LNS_copy
2061 Data: 0
2062 - Opcode: DW_LNS_advance_pc
2063 Data: 512
2064 - Opcode: DW_LNS_advance_line
2065 SData: 1
2066 Data: 0
2067 - Opcode: DW_LNS_copy
2068 Data: 0
2069 - Opcode: DW_LNS_advance_pc
2070 Data: 3584
2071 - Opcode: DW_LNS_extended_op
2072 ExtLen: 1
2073 SubOpcode: DW_LNE_end_sequence
2074 Data: 0
2075 )";
2076 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata);
2077 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded());
2078 std::unique_ptr<DWARFContext> DwarfContext =
2079 DWARFContext::create(*ErrOrSections, 8);
2080 ASSERT_TRUE(DwarfContext.get() != nullptr);
2081 auto &OS = llvm::nulls();
2082 GsymCreator GC;
2083 DwarfTransformer DT(*DwarfContext, OS, GC);
2084 const uint32_t ThreadCount = 1;
2085 ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded());
2086 ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
2087 SmallString<512> Str;
2088 raw_svector_ostream OutStrm(Str);
2089 const auto ByteOrder = support::endian::system_endianness();
2090 FileWriter FW(OutStrm, ByteOrder);
2091 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded());
2092 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
2093 ASSERT_THAT_EXPECTED(GR, Succeeded());
2094
2095 EXPECT_EQ(GR->getNumAddresses(), 4u);
2096
2097 auto ExpFI = GR->getFunctionInfo(0x1000);
2098 ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
2099 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000));
2100 EXPECT_TRUE(ExpFI->OptLineTable);
2101 StringRef MethodName = GR->getString(ExpFI->Name);
2102 EXPECT_EQ(MethodName, "lines_no_decl");
2103 // Make sure have two line table entries and that get the first line entry
2104 // correct.
2105 EXPECT_EQ(ExpFI->OptLineTable->size(), 2u);
2106 EXPECT_EQ(ExpFI->OptLineTable->first()->Addr, 0x1000u);
2107 EXPECT_EQ(ExpFI->OptLineTable->first()->Line, 11u);
2108
2109 ExpFI = GR->getFunctionInfo(0x2000);
2110 ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
2111 ASSERT_EQ(ExpFI->Range, AddressRange(0x2000, 0x3000));
2112 EXPECT_TRUE(ExpFI->OptLineTable);
2113 MethodName = GR->getString(ExpFI->Name);
2114 EXPECT_EQ(MethodName, "lines_with_decl");
2115 // Make sure have two line table entries and that we don't use line 20
2116 // from the DW_AT_decl_file/line as a line table entry.
2117 EXPECT_EQ(ExpFI->OptLineTable->size(), 2u);
2118 EXPECT_EQ(ExpFI->OptLineTable->first()->Addr, 0x2000u);
2119 EXPECT_EQ(ExpFI->OptLineTable->first()->Line, 21u);
2120
2121 ExpFI = GR->getFunctionInfo(0x3000);
2122 ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
2123 ASSERT_EQ(ExpFI->Range, AddressRange(0x3000, 0x4000));
2124 // Make sure we have no line table.
2125 EXPECT_FALSE(ExpFI->OptLineTable.has_value());
2126 MethodName = GR->getString(ExpFI->Name);
2127 EXPECT_EQ(MethodName, "no_lines_no_decl");
2128
2129 ExpFI = GR->getFunctionInfo(0x4000);
2130 ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
2131 ASSERT_EQ(ExpFI->Range, AddressRange(0x4000, 0x5000));
2132 EXPECT_TRUE(ExpFI->OptLineTable.has_value());
2133 MethodName = GR->getString(ExpFI->Name);
2134 EXPECT_EQ(MethodName, "no_lines_with_decl");
2135 // Make sure we have one line table entry that uses the DW_AT_decl_file/line
2136 // as the one and only line entry.
2137 EXPECT_EQ(ExpFI->OptLineTable->size(), 1u);
2138 EXPECT_EQ(ExpFI->OptLineTable->first()->Addr, 0x4000u);
2139 EXPECT_EQ(ExpFI->OptLineTable->first()->Line, 40u);
2140 }
2141
2142
TEST(GSYMTest,TestDWARFDeadStripAddr4)2143 TEST(GSYMTest, TestDWARFDeadStripAddr4) {
2144 // Check that various techniques that compilers use for dead code stripping
2145 // work for 4 byte addresses. Make sure we keep the good functions and
2146 // strip any functions whose name starts with "stripped".
2147 //
2148 // 1 - Compilers might set the low PC to -1 (UINT32_MAX) for compile unit
2149 // with 4 byte addresses ("stripped1")
2150 // 2 - Set the low and high PC to the same value ("stripped2")
2151 // 3 - Have the high PC lower than the low PC ("stripped3")
2152 //
2153 // 0x0000000b: DW_TAG_compile_unit
2154 // DW_AT_name ("/tmp/main.c")
2155 // DW_AT_low_pc (0x0000000000001000)
2156 // DW_AT_high_pc (0x0000000000002000)
2157 // DW_AT_language (DW_LANG_C_plus_plus)
2158 //
2159 // 0x0000001a: DW_TAG_subprogram
2160 // DW_AT_name ("main")
2161 // DW_AT_low_pc (0x0000000000001000)
2162 // DW_AT_high_pc (0x0000000000002000)
2163 //
2164 // 0x00000027: DW_TAG_subprogram
2165 // DW_AT_name ("stripped1")
2166 // DW_AT_low_pc (0x00000000ffffffff)
2167 // DW_AT_high_pc (0x0000000100000000)
2168 //
2169 // 0x00000034: DW_TAG_subprogram
2170 // DW_AT_name ("stripped2")
2171 // DW_AT_low_pc (0x0000000000003000)
2172 // DW_AT_high_pc (0x0000000000003000)
2173 //
2174 // 0x00000041: DW_TAG_subprogram
2175 // DW_AT_name ("stripped3")
2176 // DW_AT_low_pc (0x0000000000004000)
2177 // DW_AT_high_pc (0x0000000000003fff)
2178 //
2179 // 0x0000004e: NULL
2180
2181 StringRef yamldata = R"(
2182 debug_str:
2183 - ''
2184 - '/tmp/main.c'
2185 - main
2186 - stripped1
2187 - stripped2
2188 - stripped3
2189 debug_abbrev:
2190 - Table:
2191 - Code: 0x00000001
2192 Tag: DW_TAG_compile_unit
2193 Children: DW_CHILDREN_yes
2194 Attributes:
2195 - Attribute: DW_AT_name
2196 Form: DW_FORM_strp
2197 - Attribute: DW_AT_low_pc
2198 Form: DW_FORM_addr
2199 - Attribute: DW_AT_high_pc
2200 Form: DW_FORM_data4
2201 - Attribute: DW_AT_language
2202 Form: DW_FORM_data2
2203 - Code: 0x00000002
2204 Tag: DW_TAG_subprogram
2205 Children: DW_CHILDREN_no
2206 Attributes:
2207 - Attribute: DW_AT_name
2208 Form: DW_FORM_strp
2209 - Attribute: DW_AT_low_pc
2210 Form: DW_FORM_addr
2211 - Attribute: DW_AT_high_pc
2212 Form: DW_FORM_data4
2213 - Code: 0x00000003
2214 Tag: DW_TAG_subprogram
2215 Children: DW_CHILDREN_no
2216 Attributes:
2217 - Attribute: DW_AT_name
2218 Form: DW_FORM_strp
2219 - Attribute: DW_AT_low_pc
2220 Form: DW_FORM_addr
2221 - Attribute: DW_AT_high_pc
2222 Form: DW_FORM_addr
2223 debug_info:
2224 - Version: 4
2225 AddrSize: 4
2226 Entries:
2227 - AbbrCode: 0x00000001
2228 Values:
2229 - Value: 0x0000000000000001
2230 - Value: 0x0000000000001000
2231 - Value: 0x0000000000001000
2232 - Value: 0x0000000000000004
2233 - AbbrCode: 0x00000002
2234 Values:
2235 - Value: 0x000000000000000D
2236 - Value: 0x0000000000001000
2237 - Value: 0x0000000000001000
2238 - AbbrCode: 0x00000002
2239 Values:
2240 - Value: 0x0000000000000012
2241 - Value: 0x00000000FFFFFFFF
2242 - Value: 0x0000000000000001
2243 - AbbrCode: 0x00000003
2244 Values:
2245 - Value: 0x000000000000001C
2246 - Value: 0x0000000000003000
2247 - Value: 0x0000000000003000
2248 - AbbrCode: 0x00000003
2249 Values:
2250 - Value: 0x0000000000000026
2251 - Value: 0x0000000000004000
2252 - Value: 0x0000000000003FFF
2253 - AbbrCode: 0x00000000
2254 )";
2255 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata);
2256 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded());
2257 std::unique_ptr<DWARFContext> DwarfContext =
2258 DWARFContext::create(*ErrOrSections, 4);
2259 ASSERT_TRUE(DwarfContext.get() != nullptr);
2260 auto &OS = llvm::nulls();
2261 GsymCreator GC;
2262 DwarfTransformer DT(*DwarfContext, OS, GC);
2263 const uint32_t ThreadCount = 1;
2264 ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded());
2265 ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
2266 SmallString<512> Str;
2267 raw_svector_ostream OutStrm(Str);
2268 const auto ByteOrder = support::endian::system_endianness();
2269 FileWriter FW(OutStrm, ByteOrder);
2270 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded());
2271 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
2272 ASSERT_THAT_EXPECTED(GR, Succeeded());
2273
2274 // Test that the only function that made it was the "main" function.
2275 EXPECT_EQ(GR->getNumAddresses(), 1u);
2276 auto ExpFI = GR->getFunctionInfo(0x1000);
2277 ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
2278 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000));
2279 StringRef MethodName = GR->getString(ExpFI->Name);
2280 EXPECT_EQ(MethodName, "main");
2281 }
2282
TEST(GSYMTest,TestDWARFDeadStripAddr8)2283 TEST(GSYMTest, TestDWARFDeadStripAddr8) {
2284 // Check that various techniques that compilers use for dead code stripping
2285 // work for 4 byte addresses. Make sure we keep the good functions and
2286 // strip any functions whose name starts with "stripped".
2287 //
2288 // 1 - Compilers might set the low PC to -1 (UINT64_MAX) for compile unit
2289 // with 8 byte addresses ("stripped1")
2290 // 2 - Set the low and high PC to the same value ("stripped2")
2291 // 3 - Have the high PC lower than the low PC ("stripped3")
2292 //
2293 // 0x0000000b: DW_TAG_compile_unit
2294 // DW_AT_name ("/tmp/main.c")
2295 // DW_AT_low_pc (0x0000000000001000)
2296 // DW_AT_high_pc (0x0000000000002000)
2297 // DW_AT_language (DW_LANG_C_plus_plus)
2298 //
2299 // 0x0000001e: DW_TAG_subprogram
2300 // DW_AT_name ("main")
2301 // DW_AT_low_pc (0x0000000000001000)
2302 // DW_AT_high_pc (0x0000000000002000)
2303 //
2304 // 0x0000002f: DW_TAG_subprogram
2305 // DW_AT_name ("stripped1")
2306 // DW_AT_low_pc (0xffffffffffffffff)
2307 // DW_AT_high_pc (0x0000000000000000)
2308 //
2309 // 0x00000040: DW_TAG_subprogram
2310 // DW_AT_name ("stripped2")
2311 // DW_AT_low_pc (0x0000000000003000)
2312 // DW_AT_high_pc (0x0000000000003000)
2313 //
2314 // 0x00000055: DW_TAG_subprogram
2315 // DW_AT_name ("stripped3")
2316 // DW_AT_low_pc (0x0000000000004000)
2317 // DW_AT_high_pc (0x0000000000003fff)
2318 //
2319 // 0x0000006a: NULL
2320
2321 StringRef yamldata = R"(
2322 debug_str:
2323 - ''
2324 - '/tmp/main.c'
2325 - main
2326 - stripped1
2327 - stripped2
2328 - stripped3
2329 debug_abbrev:
2330 - Table:
2331 - Code: 0x00000001
2332 Tag: DW_TAG_compile_unit
2333 Children: DW_CHILDREN_yes
2334 Attributes:
2335 - Attribute: DW_AT_name
2336 Form: DW_FORM_strp
2337 - Attribute: DW_AT_low_pc
2338 Form: DW_FORM_addr
2339 - Attribute: DW_AT_high_pc
2340 Form: DW_FORM_data4
2341 - Attribute: DW_AT_language
2342 Form: DW_FORM_data2
2343 - Code: 0x00000002
2344 Tag: DW_TAG_subprogram
2345 Children: DW_CHILDREN_no
2346 Attributes:
2347 - Attribute: DW_AT_name
2348 Form: DW_FORM_strp
2349 - Attribute: DW_AT_low_pc
2350 Form: DW_FORM_addr
2351 - Attribute: DW_AT_high_pc
2352 Form: DW_FORM_data4
2353 - Code: 0x00000003
2354 Tag: DW_TAG_subprogram
2355 Children: DW_CHILDREN_no
2356 Attributes:
2357 - Attribute: DW_AT_name
2358 Form: DW_FORM_strp
2359 - Attribute: DW_AT_low_pc
2360 Form: DW_FORM_addr
2361 - Attribute: DW_AT_high_pc
2362 Form: DW_FORM_addr
2363 debug_info:
2364 - Version: 4
2365 AddrSize: 8
2366 Entries:
2367 - AbbrCode: 0x00000001
2368 Values:
2369 - Value: 0x0000000000000001
2370 - Value: 0x0000000000001000
2371 - Value: 0x0000000000001000
2372 - Value: 0x0000000000000004
2373 - AbbrCode: 0x00000002
2374 Values:
2375 - Value: 0x000000000000000D
2376 - Value: 0x0000000000001000
2377 - Value: 0x0000000000001000
2378 - AbbrCode: 0x00000002
2379 Values:
2380 - Value: 0x0000000000000012
2381 - Value: 0xFFFFFFFFFFFFFFFF
2382 - Value: 0x0000000000000001
2383 - AbbrCode: 0x00000003
2384 Values:
2385 - Value: 0x000000000000001C
2386 - Value: 0x0000000000003000
2387 - Value: 0x0000000000003000
2388 - AbbrCode: 0x00000003
2389 Values:
2390 - Value: 0x0000000000000026
2391 - Value: 0x0000000000004000
2392 - Value: 0x0000000000003FFF
2393 - AbbrCode: 0x00000000
2394 )";
2395 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata);
2396 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded());
2397 std::unique_ptr<DWARFContext> DwarfContext =
2398 DWARFContext::create(*ErrOrSections, 8);
2399 ASSERT_TRUE(DwarfContext.get() != nullptr);
2400 auto &OS = llvm::nulls();
2401 GsymCreator GC;
2402 DwarfTransformer DT(*DwarfContext, OS, GC);
2403 const uint32_t ThreadCount = 1;
2404 ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded());
2405 ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
2406 SmallString<512> Str;
2407 raw_svector_ostream OutStrm(Str);
2408 const auto ByteOrder = support::endian::system_endianness();
2409 FileWriter FW(OutStrm, ByteOrder);
2410 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded());
2411 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
2412 ASSERT_THAT_EXPECTED(GR, Succeeded());
2413
2414 // Test that the only function that made it was the "main" function.
2415 EXPECT_EQ(GR->getNumAddresses(), 1u);
2416 auto ExpFI = GR->getFunctionInfo(0x1000);
2417 ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
2418 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000));
2419 StringRef MethodName = GR->getString(ExpFI->Name);
2420 EXPECT_EQ(MethodName, "main");
2421 }
2422
TEST(GSYMTest,TestGsymCreatorMultipleSymbolsWithNoSize)2423 TEST(GSYMTest, TestGsymCreatorMultipleSymbolsWithNoSize) {
2424 // Multiple symbols at the same address with zero size were being emitted
2425 // instead of being combined into a single entry. This function tests to make
2426 // sure we only get one symbol.
2427 uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
2428 GsymCreator GC;
2429 GC.setUUID(UUID);
2430 constexpr uint64_t BaseAddr = 0x1000;
2431 constexpr uint8_t AddrOffSize = 1;
2432 const uint32_t Func1Name = GC.insertString("foo");
2433 const uint32_t Func2Name = GC.insertString("bar");
2434 GC.addFunctionInfo(FunctionInfo(BaseAddr, 0, Func1Name));
2435 GC.addFunctionInfo(FunctionInfo(BaseAddr, 0, Func2Name));
2436 Error Err = GC.finalize(llvm::nulls());
2437 ASSERT_FALSE(Err);
2438 TestEncodeDecode(GC, llvm::support::little, GSYM_VERSION, AddrOffSize,
2439 BaseAddr,
2440 1, // NumAddresses
2441 ArrayRef<uint8_t>(UUID));
2442 TestEncodeDecode(GC, llvm::support::big, GSYM_VERSION, AddrOffSize, BaseAddr,
2443 1, // NumAddresses
2444 ArrayRef<uint8_t>(UUID));
2445 }
2446