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/OutputAggregator.h" 22 #include "llvm/DebugInfo/GSYM/StringTable.h" 23 #include "llvm/ObjectYAML/DWARFEmitter.h" 24 #include "llvm/Support/DataExtractor.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 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 48 void checkError(std::string ExpectedMsg, Error Err) { 49 checkError(ArrayRef<std::string>{ExpectedMsg}, std::move(Err)); 50 } 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 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 // Test that if we have a function info without inline info and one with 144 // that the one without inline info is less than the one with. 145 FunctionInfo FIWithInlines = FISymtab; 146 FIWithInlines.Inline = InlineInfo(); 147 FIWithInlines.Inline->Ranges.insert( 148 AddressRange(StartAddr, StartAddr + 0x10)); 149 EXPECT_LT(FISymtab, FIWithInlines); 150 151 // Test that if we have a function info with inline entries and one more 152 // inline entries that the one with fewer inline functins is less than the 153 // one with more. 154 FunctionInfo FIWithMoreInlines = FIWithInlines; 155 FIWithMoreInlines.Inline->Children.push_back(InlineInfo()); 156 EXPECT_LT(FIWithInlines, FIWithMoreInlines); 157 158 FunctionInfo FIWithLinesAndInline = FIWithLines; 159 FIWithLinesAndInline.Inline = InlineInfo(); 160 FIWithLinesAndInline.Inline->Ranges.insert( 161 AddressRange(StartAddr, StartAddr + 0x10)); 162 // Test that a FunctionInfo with name, size, and line entries is less than 163 // the same one with valid inline info 164 EXPECT_LT(FIWithLines, FIWithLinesAndInline); 165 166 // Test if we have an entry with lines and one with more lines for the same 167 // range, the ones with more lines is greater than the one with less. 168 FunctionInfo FIWithMoreLines = FIWithLines; 169 FIWithMoreLines.OptLineTable->push(LineEntry(StartAddr,FileIdx,Line+5)); 170 EXPECT_LT(FIWithLines, FIWithMoreLines); 171 172 // Test that if we have the same number of lines we compare the line entries 173 // in the FunctionInfo.OptLineTable.Lines vector. 174 FunctionInfo FIWithLinesWithHigherAddress = FIWithLines; 175 FIWithLinesWithHigherAddress.OptLineTable->get(0).Addr += 0x10; 176 EXPECT_LT(FIWithLines, FIWithLinesWithHigherAddress); 177 } 178 179 static void TestFunctionInfoDecodeError(llvm::endianness ByteOrder, 180 StringRef Bytes, 181 const uint64_t BaseAddr, 182 std::string ExpectedErrorMsg) { 183 uint8_t AddressSize = 4; 184 DataExtractor Data(Bytes, ByteOrder == llvm::endianness::little, AddressSize); 185 llvm::Expected<FunctionInfo> Decoded = FunctionInfo::decode(Data, BaseAddr); 186 // Make sure decoding fails. 187 ASSERT_FALSE((bool)Decoded); 188 // Make sure decoded object is the same as the one we encoded. 189 checkError(ExpectedErrorMsg, Decoded.takeError()); 190 } 191 192 TEST(GSYMTest, TestFunctionInfoDecodeErrors) { 193 // Test decoding FunctionInfo objects that ensure we report an appropriate 194 // error message. 195 const llvm::endianness ByteOrder = llvm::endianness::little; 196 SmallString<512> Str; 197 raw_svector_ostream OutStrm(Str); 198 FileWriter FW(OutStrm, ByteOrder); 199 const uint64_t BaseAddr = 0x100; 200 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 201 "0x00000000: missing FunctionInfo Size"); 202 FW.writeU32(0x100); // Function size. 203 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 204 "0x00000004: missing FunctionInfo Name"); 205 // Write out an invalid Name string table offset of zero. 206 FW.writeU32(0); 207 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 208 "0x00000004: invalid FunctionInfo Name value 0x00000000"); 209 // Modify the Name to be 0x00000001, which is a valid value. 210 FW.fixup32(0x00000001, 4); 211 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 212 "0x00000008: missing FunctionInfo InfoType value"); 213 auto FixupOffset = FW.tell(); 214 FW.writeU32(1); // InfoType::LineTableInfo. 215 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 216 "0x0000000c: missing FunctionInfo InfoType length"); 217 FW.fixup32(7, FixupOffset); // Write an invalid InfoType enumeration value 218 FW.writeU32(0); // LineTableInfo InfoType data length. 219 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 220 "0x00000008: unsupported InfoType 7"); 221 } 222 223 static void TestFunctionInfoEncodeError(llvm::endianness ByteOrder, 224 const FunctionInfo &FI, 225 std::string ExpectedErrorMsg) { 226 SmallString<512> Str; 227 raw_svector_ostream OutStrm(Str); 228 FileWriter FW(OutStrm, ByteOrder); 229 Expected<uint64_t> ExpectedOffset = FI.encode(FW); 230 ASSERT_FALSE(ExpectedOffset); 231 checkError(ExpectedErrorMsg, ExpectedOffset.takeError()); 232 } 233 234 TEST(GSYMTest, TestFunctionInfoEncodeErrors) { 235 const uint64_t FuncAddr = 0x1000; 236 const uint64_t FuncSize = 0x100; 237 const uint32_t InvalidName = 0; 238 const uint32_t ValidName = 1; 239 FunctionInfo InvalidNameFI(FuncAddr, FuncSize, InvalidName); 240 TestFunctionInfoEncodeError( 241 llvm::endianness::little, InvalidNameFI, 242 "attempted to encode invalid FunctionInfo object"); 243 244 FunctionInfo InvalidLineTableFI(FuncAddr, FuncSize, ValidName); 245 // Empty line tables are not valid. Verify if the encoding of anything 246 // in our line table fails, that we see get the error propagated. 247 InvalidLineTableFI.OptLineTable = LineTable(); 248 TestFunctionInfoEncodeError(llvm::endianness::little, InvalidLineTableFI, 249 "attempted to encode invalid LineTable object"); 250 251 FunctionInfo InvalidInlineInfoFI(FuncAddr, FuncSize, ValidName); 252 // Empty line tables are not valid. Verify if the encoding of anything 253 // in our line table fails, that we see get the error propagated. 254 InvalidInlineInfoFI.Inline = InlineInfo(); 255 TestFunctionInfoEncodeError(llvm::endianness::little, InvalidInlineInfoFI, 256 "attempted to encode invalid InlineInfo object"); 257 } 258 259 static void TestFunctionInfoEncodeDecode(llvm::endianness ByteOrder, 260 const FunctionInfo &FI) { 261 // Test encoding and decoding FunctionInfo objects. 262 SmallString<512> Str; 263 raw_svector_ostream OutStrm(Str); 264 FileWriter FW(OutStrm, ByteOrder); 265 llvm::Expected<uint64_t> ExpectedOffset = FI.encode(FW); 266 ASSERT_TRUE(bool(ExpectedOffset)); 267 // Verify we got the encoded offset back from the encode function. 268 ASSERT_EQ(ExpectedOffset.get(), 0ULL); 269 std::string Bytes(OutStrm.str()); 270 uint8_t AddressSize = 4; 271 DataExtractor Data(Bytes, ByteOrder == llvm::endianness::little, AddressSize); 272 llvm::Expected<FunctionInfo> Decoded = 273 FunctionInfo::decode(Data, FI.Range.start()); 274 // Make sure decoding succeeded. 275 ASSERT_TRUE((bool)Decoded); 276 // Make sure decoded object is the same as the one we encoded. 277 EXPECT_EQ(FI, Decoded.get()); 278 } 279 280 static void AddLines(uint64_t FuncAddr, uint32_t FileIdx, FunctionInfo &FI) { 281 FI.OptLineTable = LineTable(); 282 LineEntry Line0(FuncAddr + 0x000, FileIdx, 10); 283 LineEntry Line1(FuncAddr + 0x010, FileIdx, 11); 284 LineEntry Line2(FuncAddr + 0x100, FileIdx, 1000); 285 FI.OptLineTable->push(Line0); 286 FI.OptLineTable->push(Line1); 287 FI.OptLineTable->push(Line2); 288 } 289 290 291 static void AddInline(uint64_t FuncAddr, uint64_t FuncSize, FunctionInfo &FI) { 292 FI.Inline = InlineInfo(); 293 FI.Inline->Ranges.insert(AddressRange(FuncAddr, FuncAddr + FuncSize)); 294 InlineInfo Inline1; 295 Inline1.Ranges.insert(AddressRange(FuncAddr + 0x10, FuncAddr + 0x30)); 296 Inline1.Name = 1; 297 Inline1.CallFile = 1; 298 Inline1.CallLine = 11; 299 FI.Inline->Children.push_back(Inline1); 300 } 301 302 TEST(GSYMTest, TestFunctionInfoEncoding) { 303 constexpr uint64_t FuncAddr = 0x1000; 304 constexpr uint64_t FuncSize = 0x100; 305 constexpr uint32_t FuncName = 1; 306 constexpr uint32_t FileIdx = 1; 307 // Make sure that we can encode and decode a FunctionInfo with no line table 308 // or inline info. 309 FunctionInfo FI(FuncAddr, FuncSize, FuncName); 310 TestFunctionInfoEncodeDecode(llvm::endianness::little, FI); 311 TestFunctionInfoEncodeDecode(llvm::endianness::big, FI); 312 313 // Make sure that we can encode and decode a FunctionInfo with a line table 314 // and no inline info. 315 FunctionInfo FILines(FuncAddr, FuncSize, FuncName); 316 AddLines(FuncAddr, FileIdx, FILines); 317 TestFunctionInfoEncodeDecode(llvm::endianness::little, FILines); 318 TestFunctionInfoEncodeDecode(llvm::endianness::big, FILines); 319 320 // Make sure that we can encode and decode a FunctionInfo with no line table 321 // and with inline info. 322 FunctionInfo FIInline(FuncAddr, FuncSize, FuncName); 323 AddInline(FuncAddr, FuncSize, FIInline); 324 TestFunctionInfoEncodeDecode(llvm::endianness::little, FIInline); 325 TestFunctionInfoEncodeDecode(llvm::endianness::big, FIInline); 326 327 // Make sure that we can encode and decode a FunctionInfo with no line table 328 // and with inline info. 329 FunctionInfo FIBoth(FuncAddr, FuncSize, FuncName); 330 AddLines(FuncAddr, FileIdx, FIBoth); 331 AddInline(FuncAddr, FuncSize, FIBoth); 332 TestFunctionInfoEncodeDecode(llvm::endianness::little, FIBoth); 333 TestFunctionInfoEncodeDecode(llvm::endianness::big, FIBoth); 334 } 335 336 static void TestInlineInfoEncodeDecode(llvm::endianness ByteOrder, 337 const InlineInfo &Inline) { 338 // Test encoding and decoding InlineInfo objects 339 SmallString<512> Str; 340 raw_svector_ostream OutStrm(Str); 341 FileWriter FW(OutStrm, ByteOrder); 342 const uint64_t BaseAddr = Inline.Ranges[0].start(); 343 llvm::Error Err = Inline.encode(FW, BaseAddr); 344 ASSERT_FALSE(Err); 345 std::string Bytes(OutStrm.str()); 346 uint8_t AddressSize = 4; 347 DataExtractor Data(Bytes, ByteOrder == llvm::endianness::little, AddressSize); 348 llvm::Expected<InlineInfo> Decoded = InlineInfo::decode(Data, BaseAddr); 349 // Make sure decoding succeeded. 350 ASSERT_TRUE((bool)Decoded); 351 // Make sure decoded object is the same as the one we encoded. 352 EXPECT_EQ(Inline, Decoded.get()); 353 } 354 355 static void TestInlineInfoDecodeError(llvm::endianness ByteOrder, 356 StringRef Bytes, const uint64_t BaseAddr, 357 std::string ExpectedErrorMsg) { 358 uint8_t AddressSize = 4; 359 DataExtractor Data(Bytes, ByteOrder == llvm::endianness::little, AddressSize); 360 llvm::Expected<InlineInfo> Decoded = InlineInfo::decode(Data, BaseAddr); 361 // Make sure decoding fails. 362 ASSERT_FALSE((bool)Decoded); 363 // Make sure decoded object is the same as the one we encoded. 364 checkError(ExpectedErrorMsg, Decoded.takeError()); 365 } 366 367 static void TestInlineInfoEncodeError(llvm::endianness ByteOrder, 368 const InlineInfo &Inline, 369 std::string ExpectedErrorMsg) { 370 SmallString<512> Str; 371 raw_svector_ostream OutStrm(Str); 372 FileWriter FW(OutStrm, ByteOrder); 373 const uint64_t BaseAddr = 374 Inline.Ranges.empty() ? 0 : Inline.Ranges[0].start(); 375 llvm::Error Err = Inline.encode(FW, BaseAddr); 376 checkError(ExpectedErrorMsg, std::move(Err)); 377 } 378 379 TEST(GSYMTest, TestInlineInfo) { 380 // Test InlineInfo structs. 381 InlineInfo II; 382 EXPECT_FALSE(II.isValid()); 383 II.Ranges.insert(AddressRange(0x1000, 0x2000)); 384 // Make sure InlineInfo in valid with just an address range since 385 // top level InlineInfo objects have ranges with no name, call file 386 // or call line 387 EXPECT_TRUE(II.isValid()); 388 // Make sure InlineInfo isn't after being cleared. 389 II.clear(); 390 EXPECT_FALSE(II.isValid()); 391 392 // Create an InlineInfo that contains the following data. The 393 // indentation of the address range indicates the parent child 394 // relationships of the InlineInfo objects: 395 // 396 // Variable Range and values 397 // =========== ==================================================== 398 // Root [0x100-0x200) (no name, file, or line) 399 // Inline1 [0x150-0x160) Name = 1, File = 1, Line = 11 400 // Inline1Sub1 [0x152-0x155) Name = 2, File = 2, Line = 22 401 // Inline1Sub2 [0x157-0x158) Name = 3, File = 3, Line = 33 402 InlineInfo Root; 403 Root.Ranges.insert(AddressRange(0x100, 0x200)); 404 InlineInfo Inline1; 405 Inline1.Ranges.insert(AddressRange(0x150, 0x160)); 406 Inline1.Name = 1; 407 Inline1.CallFile = 1; 408 Inline1.CallLine = 11; 409 InlineInfo Inline1Sub1; 410 Inline1Sub1.Ranges.insert(AddressRange(0x152, 0x155)); 411 Inline1Sub1.Name = 2; 412 Inline1Sub1.CallFile = 2; 413 Inline1Sub1.CallLine = 22; 414 InlineInfo Inline1Sub2; 415 Inline1Sub2.Ranges.insert(AddressRange(0x157, 0x158)); 416 Inline1Sub2.Name = 3; 417 Inline1Sub2.CallFile = 3; 418 Inline1Sub2.CallLine = 33; 419 Inline1.Children.push_back(Inline1Sub1); 420 Inline1.Children.push_back(Inline1Sub2); 421 Root.Children.push_back(Inline1); 422 423 // Make sure an address that is out of range won't match 424 EXPECT_FALSE(Root.getInlineStack(0x50)); 425 426 // Verify that we get no inline stacks for addresses out of [0x100-0x200) 427 EXPECT_FALSE(Root.getInlineStack(Root.Ranges[0].start() - 1)); 428 EXPECT_FALSE(Root.getInlineStack(Root.Ranges[0].end())); 429 430 // Verify we get no inline stack entries for addresses that are in 431 // [0x100-0x200) but not in [0x150-0x160) 432 EXPECT_FALSE(Root.getInlineStack(Inline1.Ranges[0].start() - 1)); 433 EXPECT_FALSE(Root.getInlineStack(Inline1.Ranges[0].end())); 434 435 // Verify we get one inline stack entry for addresses that are in 436 // [[0x150-0x160)) but not in [0x152-0x155) or [0x157-0x158) 437 auto InlineInfos = Root.getInlineStack(Inline1.Ranges[0].start()); 438 ASSERT_TRUE(InlineInfos); 439 ASSERT_EQ(InlineInfos->size(), 1u); 440 ASSERT_EQ(*InlineInfos->at(0), Inline1); 441 InlineInfos = Root.getInlineStack(Inline1.Ranges[0].end() - 1); 442 EXPECT_TRUE(InlineInfos); 443 ASSERT_EQ(InlineInfos->size(), 1u); 444 ASSERT_EQ(*InlineInfos->at(0), Inline1); 445 446 // Verify we get two inline stack entries for addresses that are in 447 // [0x152-0x155) 448 InlineInfos = Root.getInlineStack(Inline1Sub1.Ranges[0].start()); 449 EXPECT_TRUE(InlineInfos); 450 ASSERT_EQ(InlineInfos->size(), 2u); 451 ASSERT_EQ(*InlineInfos->at(0), Inline1Sub1); 452 ASSERT_EQ(*InlineInfos->at(1), Inline1); 453 InlineInfos = Root.getInlineStack(Inline1Sub1.Ranges[0].end() - 1); 454 EXPECT_TRUE(InlineInfos); 455 ASSERT_EQ(InlineInfos->size(), 2u); 456 ASSERT_EQ(*InlineInfos->at(0), Inline1Sub1); 457 ASSERT_EQ(*InlineInfos->at(1), Inline1); 458 459 // Verify we get two inline stack entries for addresses that are in 460 // [0x157-0x158) 461 InlineInfos = Root.getInlineStack(Inline1Sub2.Ranges[0].start()); 462 EXPECT_TRUE(InlineInfos); 463 ASSERT_EQ(InlineInfos->size(), 2u); 464 ASSERT_EQ(*InlineInfos->at(0), Inline1Sub2); 465 ASSERT_EQ(*InlineInfos->at(1), Inline1); 466 InlineInfos = Root.getInlineStack(Inline1Sub2.Ranges[0].end() - 1); 467 EXPECT_TRUE(InlineInfos); 468 ASSERT_EQ(InlineInfos->size(), 2u); 469 ASSERT_EQ(*InlineInfos->at(0), Inline1Sub2); 470 ASSERT_EQ(*InlineInfos->at(1), Inline1); 471 472 // Test encoding and decoding InlineInfo objects 473 TestInlineInfoEncodeDecode(llvm::endianness::little, Root); 474 TestInlineInfoEncodeDecode(llvm::endianness::big, Root); 475 } 476 477 TEST(GSYMTest, TestInlineInfoEncodeErrors) { 478 // Test InlineInfo encoding errors. 479 480 // Test that we get an error when trying to encode an InlineInfo object 481 // that has no ranges. 482 InlineInfo Empty; 483 std::string EmptyErr("attempted to encode invalid InlineInfo object"); 484 TestInlineInfoEncodeError(llvm::endianness::little, Empty, EmptyErr); 485 TestInlineInfoEncodeError(llvm::endianness::big, Empty, EmptyErr); 486 487 // Verify that we get an error trying to encode an InlineInfo object that has 488 // a child InlineInfo that has no ranges. 489 InlineInfo ContainsEmpty; 490 ContainsEmpty.Ranges.insert({0x100, 0x200}); 491 ContainsEmpty.Children.push_back(Empty); 492 TestInlineInfoEncodeError(llvm::endianness::little, ContainsEmpty, EmptyErr); 493 TestInlineInfoEncodeError(llvm::endianness::big, ContainsEmpty, EmptyErr); 494 495 // Verify that we get an error trying to encode an InlineInfo object that has 496 // a child whose address range is not contained in the parent address range. 497 InlineInfo ChildNotContained; 498 std::string ChildNotContainedErr("child range not contained in parent"); 499 ChildNotContained.Ranges.insert({0x100, 0x200}); 500 InlineInfo ChildNotContainedChild; 501 ChildNotContainedChild.Ranges.insert({0x200, 0x300}); 502 ChildNotContained.Children.push_back(ChildNotContainedChild); 503 TestInlineInfoEncodeError(llvm::endianness::little, ChildNotContained, 504 ChildNotContainedErr); 505 TestInlineInfoEncodeError(llvm::endianness::big, ChildNotContained, 506 ChildNotContainedErr); 507 } 508 509 TEST(GSYMTest, TestInlineInfoDecodeErrors) { 510 // Test decoding InlineInfo objects that ensure we report an appropriate 511 // error message. 512 const llvm::endianness ByteOrder = llvm::endianness::little; 513 SmallString<512> Str; 514 raw_svector_ostream OutStrm(Str); 515 FileWriter FW(OutStrm, ByteOrder); 516 const uint64_t BaseAddr = 0x100; 517 TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 518 "0x00000000: missing InlineInfo address ranges data"); 519 AddressRanges Ranges; 520 Ranges.insert({BaseAddr, BaseAddr+0x100}); 521 encodeRanges(Ranges, FW, BaseAddr); 522 TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 523 "0x00000004: missing InlineInfo uint8_t indicating children"); 524 FW.writeU8(0); 525 TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 526 "0x00000005: missing InlineInfo uint32_t for name"); 527 FW.writeU32(0); 528 TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 529 "0x00000009: missing ULEB128 for InlineInfo call file"); 530 FW.writeU8(0); 531 TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 532 "0x0000000a: missing ULEB128 for InlineInfo call line"); 533 } 534 535 TEST(GSYMTest, TestLineEntry) { 536 // test llvm::gsym::LineEntry structs. 537 const uint64_t ValidAddr = 0x1000; 538 const uint64_t InvalidFileIdx = 0; 539 const uint32_t ValidFileIdx = 1; 540 const uint32_t ValidLine = 5; 541 542 LineEntry Invalid; 543 EXPECT_FALSE(Invalid.isValid()); 544 // Make sure that an entry is invalid if it has a bad file index. 545 LineEntry BadFile(ValidAddr, InvalidFileIdx, ValidLine); 546 EXPECT_FALSE(BadFile.isValid()); 547 // Test operators 548 LineEntry E1(ValidAddr, ValidFileIdx, ValidLine); 549 LineEntry E2(ValidAddr, ValidFileIdx, ValidLine); 550 LineEntry DifferentAddr(ValidAddr + 1, ValidFileIdx, ValidLine); 551 LineEntry DifferentFile(ValidAddr, ValidFileIdx + 1, ValidLine); 552 LineEntry DifferentLine(ValidAddr, ValidFileIdx, ValidLine + 1); 553 EXPECT_TRUE(E1.isValid()); 554 EXPECT_EQ(E1, E2); 555 EXPECT_NE(E1, DifferentAddr); 556 EXPECT_NE(E1, DifferentFile); 557 EXPECT_NE(E1, DifferentLine); 558 EXPECT_LT(E1, DifferentAddr); 559 } 560 561 TEST(GSYMTest, TestStringTable) { 562 StringTable StrTab(StringRef("\0Hello\0World\0", 13)); 563 // Test extracting strings from a string table. 564 EXPECT_EQ(StrTab.getString(0), ""); 565 EXPECT_EQ(StrTab.getString(1), "Hello"); 566 EXPECT_EQ(StrTab.getString(7), "World"); 567 EXPECT_EQ(StrTab.getString(8), "orld"); 568 // Test pointing to last NULL terminator gets empty string. 569 EXPECT_EQ(StrTab.getString(12), ""); 570 // Test pointing to past end gets empty string. 571 EXPECT_EQ(StrTab.getString(13), ""); 572 } 573 574 static void TestFileWriterHelper(llvm::endianness ByteOrder) { 575 SmallString<512> Str; 576 raw_svector_ostream OutStrm(Str); 577 FileWriter FW(OutStrm, ByteOrder); 578 const int64_t MinSLEB = INT64_MIN; 579 const int64_t MaxSLEB = INT64_MAX; 580 const uint64_t MinULEB = 0; 581 const uint64_t MaxULEB = UINT64_MAX; 582 const uint8_t U8 = 0x10; 583 const uint16_t U16 = 0x1122; 584 const uint32_t U32 = 0x12345678; 585 const uint64_t U64 = 0x33445566778899aa; 586 const char *Hello = "hello"; 587 FW.writeU8(U8); 588 FW.writeU16(U16); 589 FW.writeU32(U32); 590 FW.writeU64(U64); 591 FW.alignTo(16); 592 const off_t FixupOffset = FW.tell(); 593 FW.writeU32(0); 594 FW.writeSLEB(MinSLEB); 595 FW.writeSLEB(MaxSLEB); 596 FW.writeULEB(MinULEB); 597 FW.writeULEB(MaxULEB); 598 FW.writeNullTerminated(Hello); 599 // Test Seek, Tell using Fixup32. 600 FW.fixup32(U32, FixupOffset); 601 602 std::string Bytes(OutStrm.str()); 603 uint8_t AddressSize = 4; 604 DataExtractor Data(Bytes, ByteOrder == llvm::endianness::little, AddressSize); 605 uint64_t Offset = 0; 606 EXPECT_EQ(Data.getU8(&Offset), U8); 607 EXPECT_EQ(Data.getU16(&Offset), U16); 608 EXPECT_EQ(Data.getU32(&Offset), U32); 609 EXPECT_EQ(Data.getU64(&Offset), U64); 610 Offset = alignTo(Offset, 16); 611 EXPECT_EQ(Data.getU32(&Offset), U32); 612 EXPECT_EQ(Data.getSLEB128(&Offset), MinSLEB); 613 EXPECT_EQ(Data.getSLEB128(&Offset), MaxSLEB); 614 EXPECT_EQ(Data.getULEB128(&Offset), MinULEB); 615 EXPECT_EQ(Data.getULEB128(&Offset), MaxULEB); 616 EXPECT_EQ(Data.getCStrRef(&Offset), StringRef(Hello)); 617 } 618 619 TEST(GSYMTest, TestFileWriter) { 620 TestFileWriterHelper(llvm::endianness::little); 621 TestFileWriterHelper(llvm::endianness::big); 622 } 623 624 TEST(GSYMTest, TestAddressRangeEncodeDecode) { 625 // Test encoding and decoding AddressRange objects. AddressRange objects 626 // are always stored as offsets from the a base address. The base address 627 // is the FunctionInfo's base address for function level ranges, and is 628 // the base address of the parent range for subranges. 629 SmallString<512> Str; 630 raw_svector_ostream OutStrm(Str); 631 const auto ByteOrder = llvm::endianness::native; 632 FileWriter FW(OutStrm, ByteOrder); 633 const uint64_t BaseAddr = 0x1000; 634 const AddressRange Range1(0x1000, 0x1010); 635 const AddressRange Range2(0x1020, 0x1030); 636 encodeRange(Range1, FW, BaseAddr); 637 encodeRange(Range2, FW, BaseAddr); 638 std::string Bytes(OutStrm.str()); 639 uint8_t AddressSize = 4; 640 DataExtractor Data(Bytes, ByteOrder == llvm::endianness::little, AddressSize); 641 642 AddressRange DecodedRange1, DecodedRange2; 643 uint64_t Offset = 0; 644 DecodedRange1 = decodeRange(Data, BaseAddr, Offset); 645 DecodedRange2 = decodeRange(Data, BaseAddr, Offset); 646 EXPECT_EQ(Range1, DecodedRange1); 647 EXPECT_EQ(Range2, DecodedRange2); 648 } 649 650 static void TestAddressRangeEncodeDecodeHelper(const AddressRanges &Ranges, 651 const uint64_t BaseAddr) { 652 SmallString<512> Str; 653 raw_svector_ostream OutStrm(Str); 654 const auto ByteOrder = llvm::endianness::native; 655 FileWriter FW(OutStrm, ByteOrder); 656 encodeRanges(Ranges, FW, BaseAddr); 657 658 std::string Bytes(OutStrm.str()); 659 uint8_t AddressSize = 4; 660 DataExtractor Data(Bytes, ByteOrder == llvm::endianness::little, AddressSize); 661 662 AddressRanges DecodedRanges; 663 uint64_t Offset = 0; 664 decodeRanges(DecodedRanges, Data, BaseAddr, Offset); 665 EXPECT_EQ(Ranges, DecodedRanges); 666 } 667 668 TEST(GSYMTest, TestAddressRangesEncodeDecode) { 669 // Test encoding and decoding AddressRanges. AddressRanges objects contain 670 // ranges that are stored as offsets from the a base address. The base address 671 // is the FunctionInfo's base address for function level ranges, and is the 672 // base address of the parent range for subranges. 673 const uint64_t BaseAddr = 0x1000; 674 675 // Test encoding and decoding with no ranges. 676 AddressRanges Ranges; 677 TestAddressRangeEncodeDecodeHelper(Ranges, BaseAddr); 678 679 // Test encoding and decoding with 1 range. 680 Ranges.insert(AddressRange(0x1000, 0x1010)); 681 TestAddressRangeEncodeDecodeHelper(Ranges, BaseAddr); 682 683 // Test encoding and decoding with multiple ranges. 684 Ranges.insert(AddressRange(0x1020, 0x1030)); 685 Ranges.insert(AddressRange(0x1050, 0x1070)); 686 TestAddressRangeEncodeDecodeHelper(Ranges, BaseAddr); 687 } 688 689 static void TestLineTableHelper(llvm::endianness ByteOrder, 690 const LineTable <) { 691 SmallString<512> Str; 692 raw_svector_ostream OutStrm(Str); 693 FileWriter FW(OutStrm, ByteOrder); 694 const uint64_t BaseAddr = LT[0].Addr; 695 llvm::Error Err = LT.encode(FW, BaseAddr); 696 ASSERT_FALSE(Err); 697 std::string Bytes(OutStrm.str()); 698 uint8_t AddressSize = 4; 699 DataExtractor Data(Bytes, ByteOrder == llvm::endianness::little, AddressSize); 700 llvm::Expected<LineTable> Decoded = LineTable::decode(Data, BaseAddr); 701 // Make sure decoding succeeded. 702 ASSERT_TRUE((bool)Decoded); 703 // Make sure decoded object is the same as the one we encoded. 704 EXPECT_EQ(LT, Decoded.get()); 705 } 706 707 TEST(GSYMTest, TestLineTable) { 708 const uint64_t StartAddr = 0x1000; 709 const uint32_t FileIdx = 1; 710 LineTable LT; 711 LineEntry Line0(StartAddr+0x000, FileIdx, 10); 712 LineEntry Line1(StartAddr+0x010, FileIdx, 11); 713 LineEntry Line2(StartAddr+0x100, FileIdx, 1000); 714 ASSERT_TRUE(LT.empty()); 715 ASSERT_EQ(LT.size(), (size_t)0); 716 LT.push(Line0); 717 ASSERT_EQ(LT.size(), (size_t)1); 718 LT.push(Line1); 719 LT.push(Line2); 720 LT.push(LineEntry(StartAddr+0x120, FileIdx, 900)); 721 LT.push(LineEntry(StartAddr+0x120, FileIdx, 2000)); 722 LT.push(LineEntry(StartAddr+0x121, FileIdx, 2001)); 723 LT.push(LineEntry(StartAddr+0x122, FileIdx, 2002)); 724 LT.push(LineEntry(StartAddr+0x123, FileIdx, 2003)); 725 ASSERT_FALSE(LT.empty()); 726 ASSERT_EQ(LT.size(), (size_t)8); 727 // Test operator[]. 728 ASSERT_EQ(LT[0], Line0); 729 ASSERT_EQ(LT[1], Line1); 730 ASSERT_EQ(LT[2], Line2); 731 732 // Test encoding and decoding line tables. 733 TestLineTableHelper(llvm::endianness::little, LT); 734 TestLineTableHelper(llvm::endianness::big, LT); 735 736 // Verify the clear method works as expected. 737 LT.clear(); 738 ASSERT_TRUE(LT.empty()); 739 ASSERT_EQ(LT.size(), (size_t)0); 740 741 LineTable LT1; 742 LineTable LT2; 743 744 // Test that two empty line tables are equal and neither are less than 745 // each other. 746 ASSERT_EQ(LT1, LT2); 747 ASSERT_FALSE(LT1 < LT1); 748 ASSERT_FALSE(LT1 < LT2); 749 ASSERT_FALSE(LT2 < LT1); 750 ASSERT_FALSE(LT2 < LT2); 751 752 // Test that a line table with less number of line entries is less than a 753 // line table with more line entries and that they are not equal. 754 LT2.push(Line0); 755 ASSERT_LT(LT1, LT2); 756 ASSERT_NE(LT1, LT2); 757 758 // Test that two line tables with the same entries are equal. 759 LT1.push(Line0); 760 ASSERT_EQ(LT1, LT2); 761 ASSERT_FALSE(LT1 < LT2); 762 ASSERT_FALSE(LT2 < LT2); 763 } 764 765 static void TestLineTableDecodeError(llvm::endianness ByteOrder, 766 StringRef Bytes, const uint64_t BaseAddr, 767 std::string ExpectedErrorMsg) { 768 uint8_t AddressSize = 4; 769 DataExtractor Data(Bytes, ByteOrder == llvm::endianness::little, AddressSize); 770 llvm::Expected<LineTable> Decoded = LineTable::decode(Data, BaseAddr); 771 // Make sure decoding fails. 772 ASSERT_FALSE((bool)Decoded); 773 // Make sure decoded object is the same as the one we encoded. 774 checkError(ExpectedErrorMsg, Decoded.takeError()); 775 } 776 777 TEST(GSYMTest, TestLineTableDecodeErrors) { 778 // Test decoding InlineInfo objects that ensure we report an appropriate 779 // error message. 780 const llvm::endianness ByteOrder = llvm::endianness::little; 781 SmallString<512> Str; 782 raw_svector_ostream OutStrm(Str); 783 FileWriter FW(OutStrm, ByteOrder); 784 const uint64_t BaseAddr = 0x100; 785 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 786 "0x00000000: missing LineTable MinDelta"); 787 FW.writeU8(1); // MinDelta (ULEB) 788 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 789 "0x00000001: missing LineTable MaxDelta"); 790 FW.writeU8(10); // MaxDelta (ULEB) 791 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 792 "0x00000002: missing LineTable FirstLine"); 793 FW.writeU8(20); // FirstLine (ULEB) 794 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 795 "0x00000003: EOF found before EndSequence"); 796 // Test a SetFile with the argument missing from the stream 797 FW.writeU8(1); // SetFile opcode (uint8_t) 798 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 799 "0x00000004: EOF found before SetFile value"); 800 FW.writeU8(5); // SetFile value as index (ULEB) 801 // Test a AdvancePC with the argument missing from the stream 802 FW.writeU8(2); // AdvancePC opcode (uint8_t) 803 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 804 "0x00000006: EOF found before AdvancePC value"); 805 FW.writeU8(20); // AdvancePC value as offset (ULEB) 806 // Test a AdvancePC with the argument missing from the stream 807 FW.writeU8(3); // AdvanceLine opcode (uint8_t) 808 TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr, 809 "0x00000008: EOF found before AdvanceLine value"); 810 FW.writeU8(20); // AdvanceLine value as offset (LLEB) 811 } 812 813 TEST(GSYMTest, TestLineTableEncodeErrors) { 814 const uint64_t BaseAddr = 0x1000; 815 const uint32_t FileIdx = 1; 816 const llvm::endianness ByteOrder = llvm::endianness::little; 817 SmallString<512> Str; 818 raw_svector_ostream OutStrm(Str); 819 FileWriter FW(OutStrm, ByteOrder); 820 LineTable LT; 821 checkError("attempted to encode invalid LineTable object", 822 LT.encode(FW, BaseAddr)); 823 824 // Try to encode a line table where a line entry has an address that is less 825 // than BaseAddr and verify we get an appropriate error. 826 LineEntry Line0(BaseAddr+0x000, FileIdx, 10); 827 LineEntry Line1(BaseAddr+0x010, FileIdx, 11); 828 LT.push(Line0); 829 LT.push(Line1); 830 checkError("LineEntry has address 0x1000 which is less than the function " 831 "start address 0x1010", LT.encode(FW, BaseAddr+0x10)); 832 LT.clear(); 833 834 // Try to encode a line table where a line entries has an address that is less 835 // than BaseAddr and verify we get an appropriate error. 836 LT.push(Line1); 837 LT.push(Line0); 838 checkError("LineEntry in LineTable not in ascending order", 839 LT.encode(FW, BaseAddr)); 840 LT.clear(); 841 } 842 843 static void TestHeaderEncodeError(const Header &H, 844 std::string ExpectedErrorMsg) { 845 const llvm::endianness ByteOrder = llvm::endianness::little; 846 SmallString<512> Str; 847 raw_svector_ostream OutStrm(Str); 848 FileWriter FW(OutStrm, ByteOrder); 849 llvm::Error Err = H.encode(FW); 850 checkError(ExpectedErrorMsg, std::move(Err)); 851 } 852 853 static void TestHeaderDecodeError(StringRef Bytes, 854 std::string ExpectedErrorMsg) { 855 const llvm::endianness ByteOrder = llvm::endianness::little; 856 uint8_t AddressSize = 4; 857 DataExtractor Data(Bytes, ByteOrder == llvm::endianness::little, AddressSize); 858 llvm::Expected<Header> Decoded = Header::decode(Data); 859 // Make sure decoding fails. 860 ASSERT_FALSE((bool)Decoded); 861 // Make sure decoded object is the same as the one we encoded. 862 checkError(ExpectedErrorMsg, Decoded.takeError()); 863 } 864 865 // Populate a GSYM header with valid values. 866 static void InitHeader(Header &H) { 867 H.Magic = GSYM_MAGIC; 868 H.Version = GSYM_VERSION; 869 H.AddrOffSize = 4; 870 H.UUIDSize = 16; 871 H.BaseAddress = 0x1000; 872 H.NumAddresses = 1; 873 H.StrtabOffset= 0x2000; 874 H.StrtabSize = 0x1000; 875 for (size_t i=0; i<GSYM_MAX_UUID_SIZE; ++i) { 876 if (i < H.UUIDSize) 877 H.UUID[i] = i; 878 else 879 H.UUID[i] = 0; 880 } 881 } 882 883 TEST(GSYMTest, TestHeaderEncodeErrors) { 884 Header H; 885 InitHeader(H); 886 H.Magic = 12; 887 TestHeaderEncodeError(H, "invalid GSYM magic 0x0000000c"); 888 InitHeader(H); 889 H.Version = 12; 890 TestHeaderEncodeError(H, "unsupported GSYM version 12"); 891 InitHeader(H); 892 H.AddrOffSize = 12; 893 TestHeaderEncodeError(H, "invalid address offset size 12"); 894 InitHeader(H); 895 H.UUIDSize = 128; 896 TestHeaderEncodeError(H, "invalid UUID size 128"); 897 } 898 899 TEST(GSYMTest, TestHeaderDecodeErrors) { 900 const llvm::endianness ByteOrder = llvm::endianness::little; 901 SmallString<512> Str; 902 raw_svector_ostream OutStrm(Str); 903 FileWriter FW(OutStrm, ByteOrder); 904 Header H; 905 InitHeader(H); 906 llvm::Error Err = H.encode(FW); 907 ASSERT_FALSE(Err); 908 FW.fixup32(12, offsetof(Header, Magic)); 909 TestHeaderDecodeError(OutStrm.str(), "invalid GSYM magic 0x0000000c"); 910 FW.fixup32(GSYM_MAGIC, offsetof(Header, Magic)); 911 FW.fixup32(12, offsetof(Header, Version)); 912 TestHeaderDecodeError(OutStrm.str(), "unsupported GSYM version 12"); 913 FW.fixup32(GSYM_VERSION, offsetof(Header, Version)); 914 FW.fixup32(12, offsetof(Header, AddrOffSize)); 915 TestHeaderDecodeError(OutStrm.str(), "invalid address offset size 12"); 916 FW.fixup32(4, offsetof(Header, AddrOffSize)); 917 FW.fixup32(128, offsetof(Header, UUIDSize)); 918 TestHeaderDecodeError(OutStrm.str(), "invalid UUID size 128"); 919 } 920 921 static void TestHeaderEncodeDecode(const Header &H, 922 llvm::endianness ByteOrder) { 923 uint8_t AddressSize = 4; 924 SmallString<512> Str; 925 raw_svector_ostream OutStrm(Str); 926 FileWriter FW(OutStrm, ByteOrder); 927 llvm::Error Err = H.encode(FW); 928 ASSERT_FALSE(Err); 929 std::string Bytes(OutStrm.str()); 930 DataExtractor Data(Bytes, ByteOrder == llvm::endianness::little, AddressSize); 931 llvm::Expected<Header> Decoded = Header::decode(Data); 932 // Make sure decoding succeeded. 933 ASSERT_TRUE((bool)Decoded); 934 EXPECT_EQ(H, Decoded.get()); 935 } 936 TEST(GSYMTest, TestHeaderEncodeDecode) { 937 Header H; 938 InitHeader(H); 939 TestHeaderEncodeDecode(H, llvm::endianness::little); 940 TestHeaderEncodeDecode(H, llvm::endianness::big); 941 } 942 943 static void TestGsymCreatorEncodeError(llvm::endianness ByteOrder, 944 const GsymCreator &GC, 945 std::string ExpectedErrorMsg) { 946 SmallString<512> Str; 947 raw_svector_ostream OutStrm(Str); 948 FileWriter FW(OutStrm, ByteOrder); 949 llvm::Error Err = GC.encode(FW); 950 ASSERT_TRUE(bool(Err)); 951 checkError(ExpectedErrorMsg, std::move(Err)); 952 } 953 954 TEST(GSYMTest, TestGsymCreatorEncodeErrors) { 955 const uint8_t ValidUUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 956 14, 15, 16}; 957 const uint8_t InvalidUUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 958 14, 15, 16, 17, 18, 19, 20, 21}; 959 // Verify we get an error when trying to encode an GsymCreator with no 960 // function infos. We shouldn't be saving a GSYM file in this case since 961 // there is nothing inside of it. 962 GsymCreator GC; 963 TestGsymCreatorEncodeError(llvm::endianness::little, GC, 964 "no functions to encode"); 965 const uint64_t FuncAddr = 0x1000; 966 const uint64_t FuncSize = 0x100; 967 const uint32_t FuncName = GC.insertString("foo"); 968 // Verify we get an error trying to encode a GsymCreator that isn't 969 // finalized. 970 GC.addFunctionInfo(FunctionInfo(FuncAddr, FuncSize, FuncName)); 971 TestGsymCreatorEncodeError(llvm::endianness::little, GC, 972 "GsymCreator wasn't finalized prior to encoding"); 973 std::string finalizeIssues; 974 raw_string_ostream OS(finalizeIssues); 975 OutputAggregator Agg(&OS); 976 llvm::Error finalizeErr = GC.finalize(Agg); 977 ASSERT_FALSE(bool(finalizeErr)); 978 finalizeErr = GC.finalize(Agg); 979 ASSERT_TRUE(bool(finalizeErr)); 980 checkError("already finalized", std::move(finalizeErr)); 981 // Verify we get an error trying to encode a GsymCreator with a UUID that is 982 // too long. 983 GC.setUUID(InvalidUUID); 984 TestGsymCreatorEncodeError(llvm::endianness::little, GC, 985 "invalid UUID size 21"); 986 GC.setUUID(ValidUUID); 987 // Verify errors are propagated when we try to encoding an invalid line 988 // table. 989 GC.forEachFunctionInfo([](FunctionInfo &FI) -> bool { 990 FI.OptLineTable = LineTable(); // Invalid line table. 991 return false; // Stop iterating 992 }); 993 TestGsymCreatorEncodeError(llvm::endianness::little, GC, 994 "attempted to encode invalid LineTable object"); 995 // Verify errors are propagated when we try to encoding an invalid inline 996 // info. 997 GC.forEachFunctionInfo([](FunctionInfo &FI) -> bool { 998 FI.OptLineTable = std::nullopt; 999 FI.Inline = InlineInfo(); // Invalid InlineInfo. 1000 return false; // Stop iterating 1001 }); 1002 TestGsymCreatorEncodeError(llvm::endianness::little, GC, 1003 "attempted to encode invalid InlineInfo object"); 1004 } 1005 1006 static void Compare(const GsymCreator &GC, const GsymReader &GR) { 1007 // Verify that all of the data in a GsymCreator is correctly decoded from 1008 // a GsymReader. To do this, we iterator over 1009 GC.forEachFunctionInfo([&](const FunctionInfo &FI) -> bool { 1010 auto DecodedFI = GR.getFunctionInfo(FI.Range.start()); 1011 EXPECT_TRUE(bool(DecodedFI)); 1012 EXPECT_EQ(FI, *DecodedFI); 1013 return true; // Keep iterating over all FunctionInfo objects. 1014 }); 1015 } 1016 1017 static void TestEncodeDecode(const GsymCreator &GC, llvm::endianness ByteOrder, 1018 uint16_t Version, uint8_t AddrOffSize, 1019 uint64_t BaseAddress, uint32_t NumAddresses, 1020 ArrayRef<uint8_t> UUID) { 1021 SmallString<512> Str; 1022 raw_svector_ostream OutStrm(Str); 1023 FileWriter FW(OutStrm, ByteOrder); 1024 llvm::Error Err = GC.encode(FW); 1025 ASSERT_FALSE((bool)Err); 1026 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 1027 ASSERT_TRUE(bool(GR)); 1028 const Header &Hdr = GR->getHeader(); 1029 EXPECT_EQ(Hdr.Version, Version); 1030 EXPECT_EQ(Hdr.AddrOffSize, AddrOffSize); 1031 EXPECT_EQ(Hdr.UUIDSize, UUID.size()); 1032 EXPECT_EQ(Hdr.BaseAddress, BaseAddress); 1033 EXPECT_EQ(Hdr.NumAddresses, NumAddresses); 1034 EXPECT_EQ(ArrayRef<uint8_t>(Hdr.UUID, Hdr.UUIDSize), UUID); 1035 Compare(GC, GR.get()); 1036 } 1037 1038 TEST(GSYMTest, TestGsymCreator1ByteAddrOffsets) { 1039 uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; 1040 GsymCreator GC; 1041 GC.setUUID(UUID); 1042 constexpr uint64_t BaseAddr = 0x1000; 1043 constexpr uint8_t AddrOffSize = 1; 1044 const uint32_t Func1Name = GC.insertString("foo"); 1045 const uint32_t Func2Name = GC.insertString("bar"); 1046 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x00, 0x10, Func1Name)); 1047 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x20, 0x10, Func2Name)); 1048 OutputAggregator Null(nullptr); 1049 Error Err = GC.finalize(Null); 1050 ASSERT_FALSE(Err); 1051 TestEncodeDecode(GC, llvm::endianness::little, GSYM_VERSION, AddrOffSize, 1052 BaseAddr, 1053 2, // NumAddresses 1054 ArrayRef<uint8_t>(UUID)); 1055 TestEncodeDecode(GC, llvm::endianness::big, GSYM_VERSION, AddrOffSize, 1056 BaseAddr, 1057 2, // NumAddresses 1058 ArrayRef<uint8_t>(UUID)); 1059 } 1060 1061 TEST(GSYMTest, TestGsymCreator2ByteAddrOffsets) { 1062 uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; 1063 GsymCreator GC; 1064 GC.setUUID(UUID); 1065 constexpr uint64_t BaseAddr = 0x1000; 1066 constexpr uint8_t AddrOffSize = 2; 1067 const uint32_t Func1Name = GC.insertString("foo"); 1068 const uint32_t Func2Name = GC.insertString("bar"); 1069 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name)); 1070 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x200, 0x100, Func2Name)); 1071 OutputAggregator Null(nullptr); 1072 Error Err = GC.finalize(Null); 1073 ASSERT_FALSE(Err); 1074 TestEncodeDecode(GC, llvm::endianness::little, GSYM_VERSION, AddrOffSize, 1075 BaseAddr, 1076 2, // NumAddresses 1077 ArrayRef<uint8_t>(UUID)); 1078 TestEncodeDecode(GC, llvm::endianness::big, GSYM_VERSION, AddrOffSize, 1079 BaseAddr, 1080 2, // NumAddresses 1081 ArrayRef<uint8_t>(UUID)); 1082 } 1083 1084 TEST(GSYMTest, TestGsymCreator4ByteAddrOffsets) { 1085 uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; 1086 GsymCreator GC; 1087 GC.setUUID(UUID); 1088 constexpr uint64_t BaseAddr = 0x1000; 1089 constexpr uint8_t AddrOffSize = 4; 1090 const uint32_t Func1Name = GC.insertString("foo"); 1091 const uint32_t Func2Name = GC.insertString("bar"); 1092 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name)); 1093 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x20000, 0x100, Func2Name)); 1094 OutputAggregator Null(nullptr); 1095 Error Err = GC.finalize(Null); 1096 ASSERT_FALSE(Err); 1097 TestEncodeDecode(GC, llvm::endianness::little, GSYM_VERSION, AddrOffSize, 1098 BaseAddr, 1099 2, // NumAddresses 1100 ArrayRef<uint8_t>(UUID)); 1101 TestEncodeDecode(GC, llvm::endianness::big, GSYM_VERSION, AddrOffSize, 1102 BaseAddr, 1103 2, // NumAddresses 1104 ArrayRef<uint8_t>(UUID)); 1105 } 1106 1107 TEST(GSYMTest, TestGsymCreator8ByteAddrOffsets) { 1108 uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; 1109 GsymCreator GC; 1110 GC.setUUID(UUID); 1111 constexpr uint64_t BaseAddr = 0x1000; 1112 constexpr uint8_t AddrOffSize = 8; 1113 const uint32_t Func1Name = GC.insertString("foo"); 1114 const uint32_t Func2Name = GC.insertString("bar"); 1115 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name)); 1116 GC.addFunctionInfo(FunctionInfo(BaseAddr+0x100000000, 0x100, Func2Name)); 1117 OutputAggregator Null(nullptr); 1118 Error Err = GC.finalize(Null); 1119 ASSERT_FALSE(Err); 1120 TestEncodeDecode(GC, llvm::endianness::little, GSYM_VERSION, AddrOffSize, 1121 BaseAddr, 1122 2, // NumAddresses 1123 ArrayRef<uint8_t>(UUID)); 1124 TestEncodeDecode(GC, llvm::endianness::big, GSYM_VERSION, AddrOffSize, 1125 BaseAddr, 1126 2, // NumAddresses 1127 ArrayRef<uint8_t>(UUID)); 1128 } 1129 1130 static void VerifyFunctionInfo(const GsymReader &GR, uint64_t Addr, 1131 const FunctionInfo &FI) { 1132 auto ExpFI = GR.getFunctionInfo(Addr); 1133 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 1134 ASSERT_EQ(FI, ExpFI.get()); 1135 } 1136 1137 static void VerifyFunctionInfoError(const GsymReader &GR, uint64_t Addr, 1138 std::string ErrMessage) { 1139 auto ExpFI = GR.getFunctionInfo(Addr); 1140 ASSERT_FALSE(bool(ExpFI)); 1141 checkError(ErrMessage, ExpFI.takeError()); 1142 } 1143 1144 TEST(GSYMTest, TestGsymReader) { 1145 uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; 1146 GsymCreator GC; 1147 GC.setUUID(UUID); 1148 constexpr uint64_t BaseAddr = 0x1000; 1149 constexpr uint64_t Func1Addr = BaseAddr; 1150 constexpr uint64_t Func2Addr = BaseAddr+0x20; 1151 constexpr uint64_t FuncSize = 0x10; 1152 const uint32_t Func1Name = GC.insertString("foo"); 1153 const uint32_t Func2Name = GC.insertString("bar"); 1154 const auto ByteOrder = llvm::endianness::native; 1155 GC.addFunctionInfo(FunctionInfo(Func1Addr, FuncSize, Func1Name)); 1156 GC.addFunctionInfo(FunctionInfo(Func2Addr, FuncSize, Func2Name)); 1157 OutputAggregator Null(nullptr); 1158 Error FinalizeErr = GC.finalize(Null); 1159 ASSERT_FALSE(FinalizeErr); 1160 SmallString<512> Str; 1161 raw_svector_ostream OutStrm(Str); 1162 FileWriter FW(OutStrm, ByteOrder); 1163 llvm::Error Err = GC.encode(FW); 1164 ASSERT_FALSE((bool)Err); 1165 if (auto ExpectedGR = GsymReader::copyBuffer(OutStrm.str())) { 1166 const GsymReader &GR = ExpectedGR.get(); 1167 VerifyFunctionInfoError(GR, Func1Addr-1, "address 0xfff is not in GSYM"); 1168 1169 FunctionInfo Func1(Func1Addr, FuncSize, Func1Name); 1170 VerifyFunctionInfo(GR, Func1Addr, Func1); 1171 VerifyFunctionInfo(GR, Func1Addr+1, Func1); 1172 VerifyFunctionInfo(GR, Func1Addr+FuncSize-1, Func1); 1173 VerifyFunctionInfoError(GR, Func1Addr+FuncSize, 1174 "address 0x1010 is not in GSYM"); 1175 VerifyFunctionInfoError(GR, Func2Addr-1, "address 0x101f is not in GSYM"); 1176 FunctionInfo Func2(Func2Addr, FuncSize, Func2Name); 1177 VerifyFunctionInfo(GR, Func2Addr, Func2); 1178 VerifyFunctionInfo(GR, Func2Addr+1, Func2); 1179 VerifyFunctionInfo(GR, Func2Addr+FuncSize-1, Func2); 1180 VerifyFunctionInfoError(GR, Func2Addr+FuncSize, 1181 "address 0x1030 is not in GSYM"); 1182 } 1183 } 1184 1185 TEST(GSYMTest, TestGsymLookups) { 1186 // Test creating a GSYM file with a function that has a inline information. 1187 // Verify that lookups work correctly. Lookups do not decode the entire 1188 // FunctionInfo or InlineInfo, they only extract information needed for the 1189 // lookup to happen which avoids allocations which can slow down 1190 // symbolication. 1191 GsymCreator GC; 1192 FunctionInfo FI(0x1000, 0x100, GC.insertString("main")); 1193 const auto ByteOrder = llvm::endianness::native; 1194 FI.OptLineTable = LineTable(); 1195 const uint32_t MainFileIndex = GC.insertFile("/tmp/main.c"); 1196 const uint32_t FooFileIndex = GC.insertFile("/tmp/foo.h"); 1197 FI.OptLineTable->push(LineEntry(0x1000, MainFileIndex, 5)); 1198 FI.OptLineTable->push(LineEntry(0x1010, FooFileIndex, 10)); 1199 FI.OptLineTable->push(LineEntry(0x1012, FooFileIndex, 20)); 1200 FI.OptLineTable->push(LineEntry(0x1014, FooFileIndex, 11)); 1201 FI.OptLineTable->push(LineEntry(0x1016, FooFileIndex, 30)); 1202 FI.OptLineTable->push(LineEntry(0x1018, FooFileIndex, 12)); 1203 FI.OptLineTable->push(LineEntry(0x1020, MainFileIndex, 8)); 1204 FI.Inline = InlineInfo(); 1205 1206 FI.Inline->Name = GC.insertString("inline1"); 1207 FI.Inline->CallFile = MainFileIndex; 1208 FI.Inline->CallLine = 6; 1209 FI.Inline->Ranges.insert(AddressRange(0x1010, 0x1020)); 1210 InlineInfo Inline2; 1211 Inline2.Name = GC.insertString("inline2"); 1212 Inline2.CallFile = FooFileIndex; 1213 Inline2.CallLine = 33; 1214 Inline2.Ranges.insert(AddressRange(0x1012, 0x1014)); 1215 FI.Inline->Children.emplace_back(Inline2); 1216 InlineInfo Inline3; 1217 Inline3.Name = GC.insertString("inline3"); 1218 Inline3.CallFile = FooFileIndex; 1219 Inline3.CallLine = 35; 1220 Inline3.Ranges.insert(AddressRange(0x1016, 0x1018)); 1221 FI.Inline->Children.emplace_back(Inline3); 1222 GC.addFunctionInfo(std::move(FI)); 1223 OutputAggregator Null(nullptr); 1224 Error FinalizeErr = GC.finalize(Null); 1225 ASSERT_FALSE(FinalizeErr); 1226 SmallString<512> Str; 1227 raw_svector_ostream OutStrm(Str); 1228 FileWriter FW(OutStrm, ByteOrder); 1229 llvm::Error Err = GC.encode(FW); 1230 ASSERT_FALSE((bool)Err); 1231 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 1232 ASSERT_TRUE(bool(GR)); 1233 1234 // Verify inline info is correct when doing lookups. 1235 auto LR = GR->lookup(0x1000); 1236 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1237 EXPECT_THAT(LR->Locations, 1238 testing::ElementsAre(SourceLocation{"main", "/tmp", "main.c", 5})); 1239 LR = GR->lookup(0x100F); 1240 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1241 EXPECT_THAT(LR->Locations, 1242 testing::ElementsAre(SourceLocation{"main", "/tmp", "main.c", 5, 15})); 1243 1244 LR = GR->lookup(0x1010); 1245 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1246 1247 EXPECT_THAT(LR->Locations, 1248 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "foo.h", 10}, 1249 SourceLocation{"main", "/tmp", "main.c", 6, 16})); 1250 1251 LR = GR->lookup(0x1012); 1252 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1253 EXPECT_THAT(LR->Locations, 1254 testing::ElementsAre(SourceLocation{"inline2", "/tmp", "foo.h", 20}, 1255 SourceLocation{"inline1", "/tmp", "foo.h", 33, 2}, 1256 SourceLocation{"main", "/tmp", "main.c", 6, 18})); 1257 1258 LR = GR->lookup(0x1014); 1259 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1260 EXPECT_THAT(LR->Locations, 1261 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "foo.h", 11, 4}, 1262 SourceLocation{"main", "/tmp", "main.c", 6, 20})); 1263 1264 LR = GR->lookup(0x1016); 1265 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1266 EXPECT_THAT(LR->Locations, 1267 testing::ElementsAre(SourceLocation{"inline3", "/tmp", "foo.h", 30}, 1268 SourceLocation{"inline1", "/tmp", "foo.h", 35, 6}, 1269 SourceLocation{"main", "/tmp", "main.c", 6, 22})); 1270 1271 LR = GR->lookup(0x1018); 1272 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1273 EXPECT_THAT(LR->Locations, 1274 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "foo.h", 12, 8}, 1275 SourceLocation{"main", "/tmp", "main.c", 6, 24})); 1276 1277 LR = GR->lookup(0x1020); 1278 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1279 EXPECT_THAT(LR->Locations, 1280 testing::ElementsAre(SourceLocation{"main", "/tmp", "main.c", 8, 32})); 1281 } 1282 1283 1284 TEST(GSYMTest, TestDWARFFunctionWithAddresses) { 1285 // Create a single compile unit with a single function and make sure it gets 1286 // converted to DWARF correctly. The function's address range is in where 1287 // DW_AT_low_pc and DW_AT_high_pc are both addresses. 1288 StringRef yamldata = R"( 1289 debug_str: 1290 - '' 1291 - /tmp/main.c 1292 - main 1293 debug_abbrev: 1294 - Table: 1295 - Code: 0x00000001 1296 Tag: DW_TAG_compile_unit 1297 Children: DW_CHILDREN_yes 1298 Attributes: 1299 - Attribute: DW_AT_name 1300 Form: DW_FORM_strp 1301 - Attribute: DW_AT_low_pc 1302 Form: DW_FORM_addr 1303 - Attribute: DW_AT_high_pc 1304 Form: DW_FORM_addr 1305 - Attribute: DW_AT_language 1306 Form: DW_FORM_data2 1307 - Code: 0x00000002 1308 Tag: DW_TAG_subprogram 1309 Children: DW_CHILDREN_no 1310 Attributes: 1311 - Attribute: DW_AT_name 1312 Form: DW_FORM_strp 1313 - Attribute: DW_AT_low_pc 1314 Form: DW_FORM_addr 1315 - Attribute: DW_AT_high_pc 1316 Form: DW_FORM_addr 1317 debug_info: 1318 - Version: 4 1319 AddrSize: 8 1320 Entries: 1321 - AbbrCode: 0x00000001 1322 Values: 1323 - Value: 0x0000000000000001 1324 - Value: 0x0000000000001000 1325 - Value: 0x0000000000002000 1326 - Value: 0x0000000000000004 1327 - AbbrCode: 0x00000002 1328 Values: 1329 - Value: 0x000000000000000D 1330 - Value: 0x0000000000001000 1331 - Value: 0x0000000000002000 1332 - AbbrCode: 0x00000000 1333 )"; 1334 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 1335 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 1336 std::unique_ptr<DWARFContext> DwarfContext = 1337 DWARFContext::create(*ErrOrSections, 8); 1338 ASSERT_TRUE(DwarfContext.get() != nullptr); 1339 auto &OS = llvm::nulls(); 1340 OutputAggregator OSAgg(&OS); 1341 GsymCreator GC; 1342 DwarfTransformer DT(*DwarfContext, GC); 1343 const uint32_t ThreadCount = 1; 1344 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 1345 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 1346 SmallString<512> Str; 1347 raw_svector_ostream OutStrm(Str); 1348 const auto ByteOrder = llvm::endianness::native; 1349 FileWriter FW(OutStrm, ByteOrder); 1350 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 1351 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 1352 ASSERT_THAT_EXPECTED(GR, Succeeded()); 1353 // There should only be one function in our GSYM. 1354 EXPECT_EQ(GR->getNumAddresses(), 1u); 1355 auto ExpFI = GR->getFunctionInfo(0x1000); 1356 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 1357 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000)); 1358 EXPECT_FALSE(ExpFI->OptLineTable.has_value()); 1359 EXPECT_FALSE(ExpFI->Inline.has_value()); 1360 } 1361 1362 TEST(GSYMTest, TestDWARFFunctionWithAddressAndOffset) { 1363 // Create a single compile unit with a single function and make sure it gets 1364 // converted to DWARF correctly. The function's address range is in where 1365 // DW_AT_low_pc is an address and the DW_AT_high_pc is an offset. 1366 StringRef yamldata = R"( 1367 debug_str: 1368 - '' 1369 - /tmp/main.c 1370 - main 1371 debug_abbrev: 1372 - Table: 1373 - Code: 0x00000001 1374 Tag: DW_TAG_compile_unit 1375 Children: DW_CHILDREN_yes 1376 Attributes: 1377 - Attribute: DW_AT_name 1378 Form: DW_FORM_strp 1379 - Attribute: DW_AT_low_pc 1380 Form: DW_FORM_addr 1381 - Attribute: DW_AT_high_pc 1382 Form: DW_FORM_data4 1383 - Attribute: DW_AT_language 1384 Form: DW_FORM_data2 1385 - Code: 0x00000002 1386 Tag: DW_TAG_subprogram 1387 Children: DW_CHILDREN_no 1388 Attributes: 1389 - Attribute: DW_AT_name 1390 Form: DW_FORM_strp 1391 - Attribute: DW_AT_low_pc 1392 Form: DW_FORM_addr 1393 - Attribute: DW_AT_high_pc 1394 Form: DW_FORM_data4 1395 debug_info: 1396 - Version: 4 1397 AddrSize: 8 1398 Entries: 1399 - AbbrCode: 0x00000001 1400 Values: 1401 - Value: 0x0000000000000001 1402 - Value: 0x0000000000001000 1403 - Value: 0x0000000000001000 1404 - Value: 0x0000000000000004 1405 - AbbrCode: 0x00000002 1406 Values: 1407 - Value: 0x000000000000000D 1408 - Value: 0x0000000000001000 1409 - Value: 0x0000000000001000 1410 - AbbrCode: 0x00000000 1411 )"; 1412 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 1413 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 1414 std::unique_ptr<DWARFContext> DwarfContext = 1415 DWARFContext::create(*ErrOrSections, 8); 1416 ASSERT_TRUE(DwarfContext.get() != nullptr); 1417 auto &OS = llvm::nulls(); 1418 OutputAggregator OSAgg(&OS); 1419 GsymCreator GC; 1420 DwarfTransformer DT(*DwarfContext, GC); 1421 const uint32_t ThreadCount = 1; 1422 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 1423 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 1424 SmallString<512> Str; 1425 raw_svector_ostream OutStrm(Str); 1426 const auto ByteOrder = llvm::endianness::native; 1427 FileWriter FW(OutStrm, ByteOrder); 1428 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 1429 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 1430 ASSERT_THAT_EXPECTED(GR, Succeeded()); 1431 // There should only be one function in our GSYM. 1432 EXPECT_EQ(GR->getNumAddresses(), 1u); 1433 auto ExpFI = GR->getFunctionInfo(0x1000); 1434 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 1435 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000)); 1436 EXPECT_FALSE(ExpFI->OptLineTable.has_value()); 1437 EXPECT_FALSE(ExpFI->Inline.has_value()); 1438 } 1439 1440 TEST(GSYMTest, TestDWARFStructMethodNoMangled) { 1441 // Sometimes the compiler will omit the mangled name in the DWARF for static 1442 // and member functions of classes and structs. This test verifies that the 1443 // fully qualified name of the method is computed and used as the string for 1444 // the function in the GSYM in these cases. Otherwise we might just get a 1445 // function name like "erase" instead of "std::vector<int>::erase". 1446 StringRef yamldata = R"( 1447 debug_str: 1448 - '' 1449 - /tmp/main.c 1450 - Foo 1451 - dump 1452 - this 1453 debug_abbrev: 1454 - Table: 1455 - Code: 0x00000001 1456 Tag: DW_TAG_compile_unit 1457 Children: DW_CHILDREN_yes 1458 Attributes: 1459 - Attribute: DW_AT_name 1460 Form: DW_FORM_strp 1461 - Attribute: DW_AT_low_pc 1462 Form: DW_FORM_addr 1463 - Attribute: DW_AT_high_pc 1464 Form: DW_FORM_addr 1465 - Attribute: DW_AT_language 1466 Form: DW_FORM_data2 1467 - Code: 0x00000002 1468 Tag: DW_TAG_structure_type 1469 Children: DW_CHILDREN_yes 1470 Attributes: 1471 - Attribute: DW_AT_name 1472 Form: DW_FORM_strp 1473 - Code: 0x00000003 1474 Tag: DW_TAG_subprogram 1475 Children: DW_CHILDREN_yes 1476 Attributes: 1477 - Attribute: DW_AT_name 1478 Form: DW_FORM_strp 1479 - Attribute: DW_AT_low_pc 1480 Form: DW_FORM_addr 1481 - Attribute: DW_AT_high_pc 1482 Form: DW_FORM_addr 1483 - Code: 0x00000004 1484 Tag: DW_TAG_formal_parameter 1485 Children: DW_CHILDREN_no 1486 Attributes: 1487 - Attribute: DW_AT_name 1488 Form: DW_FORM_strp 1489 - Attribute: DW_AT_type 1490 Form: DW_FORM_ref4 1491 - Attribute: DW_AT_artificial 1492 Form: DW_FORM_flag_present 1493 debug_info: 1494 - Version: 4 1495 AddrSize: 8 1496 Entries: 1497 - AbbrCode: 0x00000001 1498 Values: 1499 - Value: 0x0000000000000001 1500 - Value: 0x0000000000001000 1501 - Value: 0x0000000000002000 1502 - Value: 0x0000000000000004 1503 - AbbrCode: 0x00000002 1504 Values: 1505 - Value: 0x000000000000000D 1506 - AbbrCode: 0x00000003 1507 Values: 1508 - Value: 0x0000000000000011 1509 - Value: 0x0000000000001000 1510 - Value: 0x0000000000002000 1511 - AbbrCode: 0x00000004 1512 Values: 1513 - Value: 0x0000000000000016 1514 - Value: 0x0000000000000022 1515 - Value: 0x0000000000000001 1516 - AbbrCode: 0x00000000 1517 - AbbrCode: 0x00000000 1518 - AbbrCode: 0x00000000 1519 )"; 1520 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 1521 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 1522 std::unique_ptr<DWARFContext> DwarfContext = 1523 DWARFContext::create(*ErrOrSections, 8); 1524 ASSERT_TRUE(DwarfContext.get() != nullptr); 1525 auto &OS = llvm::nulls(); 1526 OutputAggregator OSAgg(&OS); 1527 GsymCreator GC; 1528 DwarfTransformer DT(*DwarfContext, GC); 1529 const uint32_t ThreadCount = 1; 1530 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 1531 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 1532 SmallString<512> Str; 1533 raw_svector_ostream OutStrm(Str); 1534 const auto ByteOrder = llvm::endianness::native; 1535 FileWriter FW(OutStrm, ByteOrder); 1536 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 1537 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 1538 ASSERT_THAT_EXPECTED(GR, Succeeded()); 1539 // There should only be one function in our GSYM. 1540 EXPECT_EQ(GR->getNumAddresses(), 1u); 1541 auto ExpFI = GR->getFunctionInfo(0x1000); 1542 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 1543 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000)); 1544 EXPECT_FALSE(ExpFI->OptLineTable.has_value()); 1545 EXPECT_FALSE(ExpFI->Inline.has_value()); 1546 StringRef MethodName = GR->getString(ExpFI->Name); 1547 EXPECT_EQ(MethodName, "Foo::dump"); 1548 } 1549 1550 TEST(GSYMTest, TestDWARFTextRanges) { 1551 // Linkers don't understand DWARF, they just like to concatenate and 1552 // relocate data within the DWARF sections. This means that if a function 1553 // gets dead stripped, and if those functions use an offset as the 1554 // DW_AT_high_pc, we can end up with many functions at address zero. The 1555 // DwarfTransformer allows clients to specify valid .text address ranges 1556 // and any addresses of any functions must fall within those ranges if any 1557 // have been specified. This means that an object file can calcuate the 1558 // address ranges within the binary where code lives and set these ranges 1559 // as constraints in the DwarfTransformer. ObjectFile instances can 1560 // add a address ranges of sections that have executable permissions. This 1561 // keeps bad information from being added to a GSYM file and causing issues 1562 // when symbolicating. 1563 StringRef yamldata = R"( 1564 debug_str: 1565 - '' 1566 - /tmp/main.c 1567 - main 1568 - dead_stripped 1569 - dead_stripped2 1570 debug_abbrev: 1571 - Table: 1572 - Code: 0x00000001 1573 Tag: DW_TAG_compile_unit 1574 Children: DW_CHILDREN_yes 1575 Attributes: 1576 - Attribute: DW_AT_name 1577 Form: DW_FORM_strp 1578 - Attribute: DW_AT_low_pc 1579 Form: DW_FORM_addr 1580 - Attribute: DW_AT_high_pc 1581 Form: DW_FORM_data4 1582 - Attribute: DW_AT_language 1583 Form: DW_FORM_data2 1584 - Code: 0x00000002 1585 Tag: DW_TAG_subprogram 1586 Children: DW_CHILDREN_no 1587 Attributes: 1588 - Attribute: DW_AT_name 1589 Form: DW_FORM_strp 1590 - Attribute: DW_AT_low_pc 1591 Form: DW_FORM_addr 1592 - Attribute: DW_AT_high_pc 1593 Form: DW_FORM_data4 1594 debug_info: 1595 - Version: 4 1596 AddrSize: 8 1597 Entries: 1598 - AbbrCode: 0x00000001 1599 Values: 1600 - Value: 0x0000000000000001 1601 - Value: 0x0000000000001000 1602 - Value: 0x0000000000001000 1603 - Value: 0x0000000000000004 1604 - AbbrCode: 0x00000002 1605 Values: 1606 - Value: 0x000000000000000D 1607 - Value: 0x0000000000001000 1608 - Value: 0x0000000000001000 1609 - AbbrCode: 0x00000002 1610 Values: 1611 - Value: 0x0000000000000012 1612 - Value: 0x0000000000000000 1613 - Value: 0x0000000000000100 1614 - AbbrCode: 0x00000002 1615 Values: 1616 - Value: 0x0000000000000020 1617 - Value: 0x0000000000000000 1618 - Value: 0x0000000000000040 1619 - AbbrCode: 0x00000000 1620 )"; 1621 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 1622 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 1623 std::unique_ptr<DWARFContext> DwarfContext = 1624 DWARFContext::create(*ErrOrSections, 8); 1625 ASSERT_TRUE(DwarfContext.get() != nullptr); 1626 auto &OS = llvm::nulls(); 1627 OutputAggregator OSAgg(&OS); 1628 GsymCreator GC; 1629 DwarfTransformer DT(*DwarfContext, GC); 1630 // Only allow addresses between [0x1000 - 0x2000) to be linked into the 1631 // GSYM. 1632 AddressRanges TextRanges; 1633 TextRanges.insert(AddressRange(0x1000, 0x2000)); 1634 GC.SetValidTextRanges(TextRanges); 1635 const uint32_t ThreadCount = 1; 1636 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 1637 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 1638 SmallString<512> Str; 1639 raw_svector_ostream OutStrm(Str); 1640 const auto ByteOrder = llvm::endianness::native; 1641 FileWriter FW(OutStrm, ByteOrder); 1642 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 1643 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 1644 ASSERT_THAT_EXPECTED(GR, Succeeded()); 1645 // There should only be one function in our GSYM. 1646 EXPECT_EQ(GR->getNumAddresses(), 1u); 1647 auto ExpFI = GR->getFunctionInfo(0x1000); 1648 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 1649 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000)); 1650 EXPECT_FALSE(ExpFI->OptLineTable.has_value()); 1651 EXPECT_FALSE(ExpFI->Inline.has_value()); 1652 StringRef MethodName = GR->getString(ExpFI->Name); 1653 EXPECT_EQ(MethodName, "main"); 1654 } 1655 1656 TEST(GSYMTest, TestEmptySymbolEndAddressOfTextRanges) { 1657 // Test that if we have valid text ranges and we have a symbol with no size 1658 // as the last FunctionInfo entry that the size of the symbol gets set to the 1659 // end address of the text range. 1660 GsymCreator GC; 1661 AddressRanges TextRanges; 1662 TextRanges.insert(AddressRange(0x1000, 0x2000)); 1663 GC.SetValidTextRanges(TextRanges); 1664 GC.addFunctionInfo(FunctionInfo(0x1500, 0, GC.insertString("symbol"))); 1665 OutputAggregator Null(nullptr); 1666 ASSERT_THAT_ERROR(GC.finalize(Null), Succeeded()); 1667 SmallString<512> Str; 1668 raw_svector_ostream OutStrm(Str); 1669 const auto ByteOrder = llvm::endianness::native; 1670 FileWriter FW(OutStrm, ByteOrder); 1671 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 1672 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 1673 ASSERT_THAT_EXPECTED(GR, Succeeded()); 1674 // There should only be one function in our GSYM. 1675 EXPECT_EQ(GR->getNumAddresses(), 1u); 1676 auto ExpFI = GR->getFunctionInfo(0x1500); 1677 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 1678 ASSERT_EQ(ExpFI->Range, AddressRange(0x1500, 0x2000)); 1679 EXPECT_FALSE(ExpFI->OptLineTable.has_value()); 1680 EXPECT_FALSE(ExpFI->Inline.has_value()); 1681 StringRef MethodName = GR->getString(ExpFI->Name); 1682 EXPECT_EQ(MethodName, "symbol"); 1683 } 1684 1685 TEST(GSYMTest, TestDWARFInlineInfo) { 1686 // Make sure we parse the line table and inline information correctly from 1687 // DWARF. 1688 StringRef yamldata = R"( 1689 debug_str: 1690 - '' 1691 - /tmp/main.c 1692 - main 1693 - inline1 1694 debug_abbrev: 1695 - Table: 1696 - Code: 0x00000001 1697 Tag: DW_TAG_compile_unit 1698 Children: DW_CHILDREN_yes 1699 Attributes: 1700 - Attribute: DW_AT_name 1701 Form: DW_FORM_strp 1702 - Attribute: DW_AT_low_pc 1703 Form: DW_FORM_addr 1704 - Attribute: DW_AT_high_pc 1705 Form: DW_FORM_data4 1706 - Attribute: DW_AT_language 1707 Form: DW_FORM_data2 1708 - Attribute: DW_AT_stmt_list 1709 Form: DW_FORM_sec_offset 1710 - Code: 0x00000002 1711 Tag: DW_TAG_subprogram 1712 Children: DW_CHILDREN_yes 1713 Attributes: 1714 - Attribute: DW_AT_name 1715 Form: DW_FORM_strp 1716 - Attribute: DW_AT_low_pc 1717 Form: DW_FORM_addr 1718 - Attribute: DW_AT_high_pc 1719 Form: DW_FORM_data4 1720 - Code: 0x00000003 1721 Tag: DW_TAG_inlined_subroutine 1722 Children: DW_CHILDREN_no 1723 Attributes: 1724 - Attribute: DW_AT_name 1725 Form: DW_FORM_strp 1726 - Attribute: DW_AT_low_pc 1727 Form: DW_FORM_addr 1728 - Attribute: DW_AT_high_pc 1729 Form: DW_FORM_data4 1730 - Attribute: DW_AT_call_file 1731 Form: DW_FORM_data4 1732 - Attribute: DW_AT_call_line 1733 Form: DW_FORM_data4 1734 debug_info: 1735 - Version: 4 1736 AddrSize: 8 1737 Entries: 1738 - AbbrCode: 0x00000001 1739 Values: 1740 - Value: 0x0000000000000001 1741 - Value: 0x0000000000001000 1742 - Value: 0x0000000000001000 1743 - Value: 0x0000000000000004 1744 - Value: 0x0000000000000000 1745 - AbbrCode: 0x00000002 1746 Values: 1747 - Value: 0x000000000000000D 1748 - Value: 0x0000000000001000 1749 - Value: 0x0000000000001000 1750 - AbbrCode: 0x00000003 1751 Values: 1752 - Value: 0x0000000000000012 1753 - Value: 0x0000000000001100 1754 - Value: 0x0000000000000100 1755 - Value: 0x0000000000000001 1756 - Value: 0x000000000000000A 1757 - AbbrCode: 0x00000000 1758 - AbbrCode: 0x00000000 1759 debug_line: 1760 - Length: 96 1761 Version: 2 1762 PrologueLength: 46 1763 MinInstLength: 1 1764 DefaultIsStmt: 1 1765 LineBase: 251 1766 LineRange: 14 1767 OpcodeBase: 13 1768 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 1769 IncludeDirs: 1770 - /tmp 1771 Files: 1772 - Name: main.c 1773 DirIdx: 1 1774 ModTime: 0 1775 Length: 0 1776 - Name: inline.h 1777 DirIdx: 1 1778 ModTime: 0 1779 Length: 0 1780 Opcodes: 1781 - Opcode: DW_LNS_extended_op 1782 ExtLen: 9 1783 SubOpcode: DW_LNE_set_address 1784 Data: 4096 1785 - Opcode: DW_LNS_advance_line 1786 SData: 9 1787 Data: 4096 1788 - Opcode: DW_LNS_copy 1789 Data: 4096 1790 - Opcode: DW_LNS_advance_pc 1791 Data: 256 1792 - Opcode: DW_LNS_set_file 1793 Data: 2 1794 - Opcode: DW_LNS_advance_line 1795 SData: 10 1796 Data: 2 1797 - Opcode: DW_LNS_copy 1798 Data: 2 1799 - Opcode: DW_LNS_advance_pc 1800 Data: 128 1801 - Opcode: DW_LNS_advance_line 1802 SData: 1 1803 Data: 128 1804 - Opcode: DW_LNS_copy 1805 Data: 128 1806 - Opcode: DW_LNS_advance_pc 1807 Data: 128 1808 - Opcode: DW_LNS_set_file 1809 Data: 1 1810 - Opcode: DW_LNS_advance_line 1811 SData: -10 1812 Data: 1 1813 - Opcode: DW_LNS_copy 1814 Data: 1 1815 - Opcode: DW_LNS_advance_pc 1816 Data: 3584 1817 - Opcode: DW_LNS_advance_line 1818 SData: 1 1819 Data: 3584 1820 - Opcode: DW_LNS_extended_op 1821 ExtLen: 1 1822 SubOpcode: DW_LNE_end_sequence 1823 Data: 3584 1824 )"; 1825 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 1826 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 1827 std::unique_ptr<DWARFContext> DwarfContext = 1828 DWARFContext::create(*ErrOrSections, 8); 1829 ASSERT_TRUE(DwarfContext.get() != nullptr); 1830 auto &OS = llvm::nulls(); 1831 OutputAggregator OSAgg(&OS); 1832 GsymCreator GC; 1833 DwarfTransformer DT(*DwarfContext, GC); 1834 const uint32_t ThreadCount = 1; 1835 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 1836 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 1837 SmallString<512> Str; 1838 raw_svector_ostream OutStrm(Str); 1839 const auto ByteOrder = llvm::endianness::native; 1840 FileWriter FW(OutStrm, ByteOrder); 1841 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 1842 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 1843 ASSERT_THAT_EXPECTED(GR, Succeeded()); 1844 // There should only be one function in our GSYM. 1845 EXPECT_EQ(GR->getNumAddresses(), 1u); 1846 auto ExpFI = GR->getFunctionInfo(0x1000); 1847 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 1848 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000)); 1849 EXPECT_TRUE(ExpFI->OptLineTable.has_value()); 1850 EXPECT_TRUE(ExpFI->Inline.has_value()); 1851 StringRef MethodName = GR->getString(ExpFI->Name); 1852 EXPECT_EQ(MethodName, "main"); 1853 1854 // Verify inline info is correct when doing lookups. 1855 auto LR = GR->lookup(0x1000); 1856 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1857 EXPECT_THAT(LR->Locations, 1858 testing::ElementsAre(SourceLocation{"main", "/tmp", "main.c", 10})); 1859 LR = GR->lookup(0x1100-1); 1860 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1861 EXPECT_THAT(LR->Locations, 1862 testing::ElementsAre(SourceLocation{"main", "/tmp", "main.c", 10, 255})); 1863 1864 LR = GR->lookup(0x1100); 1865 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1866 EXPECT_THAT(LR->Locations, 1867 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "inline.h", 20}, 1868 SourceLocation{"main", "/tmp", "main.c", 10, 256})); 1869 LR = GR->lookup(0x1180-1); 1870 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1871 EXPECT_THAT(LR->Locations, 1872 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "inline.h", 20, 127}, 1873 SourceLocation{"main", "/tmp", "main.c", 10, 383})); 1874 LR = GR->lookup(0x1180); 1875 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1876 EXPECT_THAT(LR->Locations, 1877 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "inline.h", 21, 128}, 1878 SourceLocation{"main", "/tmp", "main.c", 10, 384})); 1879 LR = GR->lookup(0x1200-1); 1880 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1881 EXPECT_THAT(LR->Locations, 1882 testing::ElementsAre(SourceLocation{"inline1", "/tmp", "inline.h", 21, 255}, 1883 SourceLocation{"main", "/tmp", "main.c", 10, 511})); 1884 LR = GR->lookup(0x1200); 1885 ASSERT_THAT_EXPECTED(LR, Succeeded()); 1886 EXPECT_THAT(LR->Locations, 1887 testing::ElementsAre(SourceLocation{"main", "/tmp", "main.c", 11, 512})); 1888 } 1889 1890 1891 TEST(GSYMTest, TestDWARFNoLines) { 1892 // Check that if a DW_TAG_subprogram doesn't have line table entries that 1893 // we fall back and use the DW_AT_decl_file and DW_AT_decl_line to at least 1894 // point to the function definition. This DWARF file has 4 functions: 1895 // "lines_no_decl": has line table entries, no DW_AT_decl_file/line attrs. 1896 // "lines_with_decl": has line table entries and has DW_AT_decl_file/line, 1897 // make sure we don't use DW_AT_decl_file/line and make 1898 // sure there is a line table. 1899 // "no_lines_no_decl": no line table entries and no DW_AT_decl_file/line, 1900 // make sure there is no line table for this function. 1901 // "no_lines_with_decl": no line table and has DW_AT_decl_file/line, make 1902 // sure we have one line table entry that starts at 1903 // the function start address and the decl file and 1904 // line. 1905 // 1906 // 0x0000000b: DW_TAG_compile_unit 1907 // DW_AT_name ("/tmp/main.c") 1908 // DW_AT_low_pc (0x0000000000001000) 1909 // DW_AT_high_pc (0x0000000000002000) 1910 // DW_AT_language (DW_LANG_C_plus_plus) 1911 // DW_AT_stmt_list (0x00000000) 1912 // 1913 // 0x00000022: DW_TAG_subprogram 1914 // DW_AT_name ("lines_no_decl") 1915 // DW_AT_low_pc (0x0000000000001000) 1916 // DW_AT_high_pc (0x0000000000002000) 1917 // 1918 // 0x00000033: DW_TAG_subprogram 1919 // DW_AT_name ("lines_with_decl") 1920 // DW_AT_low_pc (0x0000000000002000) 1921 // DW_AT_high_pc (0x0000000000003000) 1922 // DW_AT_decl_file ("/tmp/main.c") 1923 // DW_AT_decl_line (20) 1924 // 1925 // 0x00000046: DW_TAG_subprogram 1926 // DW_AT_name ("no_lines_no_decl") 1927 // DW_AT_low_pc (0x0000000000003000) 1928 // DW_AT_high_pc (0x0000000000004000) 1929 // 1930 // 0x00000057: DW_TAG_subprogram 1931 // DW_AT_name ("no_lines_with_decl") 1932 // DW_AT_low_pc (0x0000000000004000) 1933 // DW_AT_high_pc (0x0000000000005000) 1934 // DW_AT_decl_file ("/tmp/main.c") 1935 // DW_AT_decl_line (40) 1936 // 1937 // 0x0000006a: NULL 1938 1939 StringRef yamldata = R"( 1940 debug_str: 1941 - '' 1942 - '/tmp/main.c' 1943 - lines_no_decl 1944 - lines_with_decl 1945 - no_lines_no_decl 1946 - no_lines_with_decl 1947 debug_abbrev: 1948 - Table: 1949 - Code: 0x00000001 1950 Tag: DW_TAG_compile_unit 1951 Children: DW_CHILDREN_yes 1952 Attributes: 1953 - Attribute: DW_AT_name 1954 Form: DW_FORM_strp 1955 - Attribute: DW_AT_low_pc 1956 Form: DW_FORM_addr 1957 - Attribute: DW_AT_high_pc 1958 Form: DW_FORM_data4 1959 - Attribute: DW_AT_language 1960 Form: DW_FORM_data2 1961 - Attribute: DW_AT_stmt_list 1962 Form: DW_FORM_sec_offset 1963 - Code: 0x00000002 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 - Code: 0x00000003 1974 Tag: DW_TAG_subprogram 1975 Children: DW_CHILDREN_no 1976 Attributes: 1977 - Attribute: DW_AT_name 1978 Form: DW_FORM_strp 1979 - Attribute: DW_AT_low_pc 1980 Form: DW_FORM_addr 1981 - Attribute: DW_AT_high_pc 1982 Form: DW_FORM_data4 1983 - Attribute: DW_AT_decl_file 1984 Form: DW_FORM_data1 1985 - Attribute: DW_AT_decl_line 1986 Form: DW_FORM_data1 1987 debug_info: 1988 - Version: 4 1989 AddrSize: 8 1990 Entries: 1991 - AbbrCode: 0x00000001 1992 Values: 1993 - Value: 0x0000000000000001 1994 - Value: 0x0000000000001000 1995 - Value: 0x0000000000001000 1996 - Value: 0x0000000000000004 1997 - Value: 0x0000000000000000 1998 - AbbrCode: 0x00000002 1999 Values: 2000 - Value: 0x000000000000000D 2001 - Value: 0x0000000000001000 2002 - Value: 0x0000000000001000 2003 - AbbrCode: 0x00000003 2004 Values: 2005 - Value: 0x000000000000001B 2006 - Value: 0x0000000000002000 2007 - Value: 0x0000000000001000 2008 - Value: 0x0000000000000001 2009 - Value: 0x0000000000000014 2010 - AbbrCode: 0x00000002 2011 Values: 2012 - Value: 0x000000000000002B 2013 - Value: 0x0000000000003000 2014 - Value: 0x0000000000001000 2015 - AbbrCode: 0x00000003 2016 Values: 2017 - Value: 0x000000000000003C 2018 - Value: 0x0000000000004000 2019 - Value: 0x0000000000001000 2020 - Value: 0x0000000000000001 2021 - Value: 0x0000000000000028 2022 - AbbrCode: 0x00000000 2023 debug_line: 2024 - Length: 92 2025 Version: 2 2026 PrologueLength: 34 2027 MinInstLength: 1 2028 DefaultIsStmt: 1 2029 LineBase: 251 2030 LineRange: 14 2031 OpcodeBase: 13 2032 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 2033 IncludeDirs: 2034 - '/tmp' 2035 Files: 2036 - Name: main.c 2037 DirIdx: 1 2038 ModTime: 0 2039 Length: 0 2040 Opcodes: 2041 - Opcode: DW_LNS_extended_op 2042 ExtLen: 9 2043 SubOpcode: DW_LNE_set_address 2044 Data: 4096 2045 - Opcode: DW_LNS_advance_line 2046 SData: 10 2047 Data: 0 2048 - Opcode: DW_LNS_copy 2049 Data: 0 2050 - Opcode: DW_LNS_advance_pc 2051 Data: 512 2052 - Opcode: DW_LNS_advance_line 2053 SData: 1 2054 Data: 0 2055 - Opcode: DW_LNS_copy 2056 Data: 0 2057 - Opcode: DW_LNS_advance_pc 2058 Data: 3584 2059 - Opcode: DW_LNS_extended_op 2060 ExtLen: 1 2061 SubOpcode: DW_LNE_end_sequence 2062 Data: 0 2063 - Opcode: DW_LNS_extended_op 2064 ExtLen: 9 2065 SubOpcode: DW_LNE_set_address 2066 Data: 8192 2067 - Opcode: DW_LNS_advance_line 2068 SData: 20 2069 Data: 0 2070 - Opcode: DW_LNS_copy 2071 Data: 0 2072 - Opcode: DW_LNS_advance_pc 2073 Data: 512 2074 - Opcode: DW_LNS_advance_line 2075 SData: 1 2076 Data: 0 2077 - Opcode: DW_LNS_copy 2078 Data: 0 2079 - Opcode: DW_LNS_advance_pc 2080 Data: 3584 2081 - Opcode: DW_LNS_extended_op 2082 ExtLen: 1 2083 SubOpcode: DW_LNE_end_sequence 2084 Data: 0 2085 )"; 2086 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 2087 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 2088 std::unique_ptr<DWARFContext> DwarfContext = 2089 DWARFContext::create(*ErrOrSections, 8); 2090 ASSERT_TRUE(DwarfContext.get() != nullptr); 2091 auto &OS = llvm::nulls(); 2092 OutputAggregator OSAgg(&OS); 2093 GsymCreator GC; 2094 DwarfTransformer DT(*DwarfContext, GC); 2095 const uint32_t ThreadCount = 1; 2096 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 2097 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 2098 SmallString<512> Str; 2099 raw_svector_ostream OutStrm(Str); 2100 const auto ByteOrder = llvm::endianness::native; 2101 FileWriter FW(OutStrm, ByteOrder); 2102 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 2103 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 2104 ASSERT_THAT_EXPECTED(GR, Succeeded()); 2105 2106 EXPECT_EQ(GR->getNumAddresses(), 4u); 2107 2108 auto ExpFI = GR->getFunctionInfo(0x1000); 2109 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 2110 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000)); 2111 EXPECT_TRUE(ExpFI->OptLineTable); 2112 StringRef MethodName = GR->getString(ExpFI->Name); 2113 EXPECT_EQ(MethodName, "lines_no_decl"); 2114 // Make sure have two line table entries and that get the first line entry 2115 // correct. 2116 EXPECT_EQ(ExpFI->OptLineTable->size(), 2u); 2117 EXPECT_EQ(ExpFI->OptLineTable->first()->Addr, 0x1000u); 2118 EXPECT_EQ(ExpFI->OptLineTable->first()->Line, 11u); 2119 2120 ExpFI = GR->getFunctionInfo(0x2000); 2121 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 2122 ASSERT_EQ(ExpFI->Range, AddressRange(0x2000, 0x3000)); 2123 EXPECT_TRUE(ExpFI->OptLineTable); 2124 MethodName = GR->getString(ExpFI->Name); 2125 EXPECT_EQ(MethodName, "lines_with_decl"); 2126 // Make sure have two line table entries and that we don't use line 20 2127 // from the DW_AT_decl_file/line as a line table entry. 2128 EXPECT_EQ(ExpFI->OptLineTable->size(), 2u); 2129 EXPECT_EQ(ExpFI->OptLineTable->first()->Addr, 0x2000u); 2130 EXPECT_EQ(ExpFI->OptLineTable->first()->Line, 21u); 2131 2132 ExpFI = GR->getFunctionInfo(0x3000); 2133 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 2134 ASSERT_EQ(ExpFI->Range, AddressRange(0x3000, 0x4000)); 2135 // Make sure we have no line table. 2136 EXPECT_FALSE(ExpFI->OptLineTable.has_value()); 2137 MethodName = GR->getString(ExpFI->Name); 2138 EXPECT_EQ(MethodName, "no_lines_no_decl"); 2139 2140 ExpFI = GR->getFunctionInfo(0x4000); 2141 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 2142 ASSERT_EQ(ExpFI->Range, AddressRange(0x4000, 0x5000)); 2143 EXPECT_TRUE(ExpFI->OptLineTable.has_value()); 2144 MethodName = GR->getString(ExpFI->Name); 2145 EXPECT_EQ(MethodName, "no_lines_with_decl"); 2146 // Make sure we have one line table entry that uses the DW_AT_decl_file/line 2147 // as the one and only line entry. 2148 EXPECT_EQ(ExpFI->OptLineTable->size(), 1u); 2149 EXPECT_EQ(ExpFI->OptLineTable->first()->Addr, 0x4000u); 2150 EXPECT_EQ(ExpFI->OptLineTable->first()->Line, 40u); 2151 } 2152 2153 2154 TEST(GSYMTest, TestDWARFDeadStripAddr4) { 2155 // Check that various techniques that compilers use for dead code stripping 2156 // work for 4 byte addresses. Make sure we keep the good functions and 2157 // strip any functions whose name starts with "stripped". 2158 // 2159 // 1 - Compilers might set the low PC to -1 (UINT32_MAX) for compile unit 2160 // with 4 byte addresses ("stripped1") 2161 // 2 - Set the low and high PC to the same value ("stripped2") 2162 // 3 - Have the high PC lower than the low PC ("stripped3") 2163 // 2164 // 0x0000000b: DW_TAG_compile_unit 2165 // DW_AT_name ("/tmp/main.c") 2166 // DW_AT_low_pc (0x0000000000001000) 2167 // DW_AT_high_pc (0x0000000000002000) 2168 // DW_AT_language (DW_LANG_C_plus_plus) 2169 // 2170 // 0x0000001a: DW_TAG_subprogram 2171 // DW_AT_name ("main") 2172 // DW_AT_low_pc (0x0000000000001000) 2173 // DW_AT_high_pc (0x0000000000002000) 2174 // 2175 // 0x00000027: DW_TAG_subprogram 2176 // DW_AT_name ("stripped1") 2177 // DW_AT_low_pc (0x00000000ffffffff) 2178 // DW_AT_high_pc (0x0000000100000000) 2179 // 2180 // 0x00000034: DW_TAG_subprogram 2181 // DW_AT_name ("stripped2") 2182 // DW_AT_low_pc (0x0000000000003000) 2183 // DW_AT_high_pc (0x0000000000003000) 2184 // 2185 // 0x00000041: DW_TAG_subprogram 2186 // DW_AT_name ("stripped3") 2187 // DW_AT_low_pc (0x0000000000004000) 2188 // DW_AT_high_pc (0x0000000000003fff) 2189 // 2190 // 0x0000004e: NULL 2191 2192 StringRef yamldata = R"( 2193 debug_str: 2194 - '' 2195 - '/tmp/main.c' 2196 - main 2197 - stripped1 2198 - stripped2 2199 - stripped3 2200 debug_abbrev: 2201 - Table: 2202 - Code: 0x00000001 2203 Tag: DW_TAG_compile_unit 2204 Children: DW_CHILDREN_yes 2205 Attributes: 2206 - Attribute: DW_AT_name 2207 Form: DW_FORM_strp 2208 - Attribute: DW_AT_low_pc 2209 Form: DW_FORM_addr 2210 - Attribute: DW_AT_high_pc 2211 Form: DW_FORM_data4 2212 - Attribute: DW_AT_language 2213 Form: DW_FORM_data2 2214 - Code: 0x00000002 2215 Tag: DW_TAG_subprogram 2216 Children: DW_CHILDREN_no 2217 Attributes: 2218 - Attribute: DW_AT_name 2219 Form: DW_FORM_strp 2220 - Attribute: DW_AT_low_pc 2221 Form: DW_FORM_addr 2222 - Attribute: DW_AT_high_pc 2223 Form: DW_FORM_data4 2224 - Code: 0x00000003 2225 Tag: DW_TAG_subprogram 2226 Children: DW_CHILDREN_no 2227 Attributes: 2228 - Attribute: DW_AT_name 2229 Form: DW_FORM_strp 2230 - Attribute: DW_AT_low_pc 2231 Form: DW_FORM_addr 2232 - Attribute: DW_AT_high_pc 2233 Form: DW_FORM_addr 2234 debug_info: 2235 - Version: 4 2236 AddrSize: 4 2237 Entries: 2238 - AbbrCode: 0x00000001 2239 Values: 2240 - Value: 0x0000000000000001 2241 - Value: 0x0000000000001000 2242 - Value: 0x0000000000001000 2243 - Value: 0x0000000000000004 2244 - AbbrCode: 0x00000002 2245 Values: 2246 - Value: 0x000000000000000D 2247 - Value: 0x0000000000001000 2248 - Value: 0x0000000000001000 2249 - AbbrCode: 0x00000002 2250 Values: 2251 - Value: 0x0000000000000012 2252 - Value: 0x00000000FFFFFFFF 2253 - Value: 0x0000000000000001 2254 - AbbrCode: 0x00000003 2255 Values: 2256 - Value: 0x000000000000001C 2257 - Value: 0x0000000000003000 2258 - Value: 0x0000000000003000 2259 - AbbrCode: 0x00000003 2260 Values: 2261 - Value: 0x0000000000000026 2262 - Value: 0x0000000000004000 2263 - Value: 0x0000000000003FFF 2264 - AbbrCode: 0x00000000 2265 )"; 2266 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 2267 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 2268 std::unique_ptr<DWARFContext> DwarfContext = 2269 DWARFContext::create(*ErrOrSections, 4); 2270 ASSERT_TRUE(DwarfContext.get() != nullptr); 2271 auto &OS = llvm::nulls(); 2272 OutputAggregator OSAgg(&OS); 2273 GsymCreator GC; 2274 DwarfTransformer DT(*DwarfContext, GC); 2275 const uint32_t ThreadCount = 1; 2276 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 2277 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 2278 SmallString<512> Str; 2279 raw_svector_ostream OutStrm(Str); 2280 const auto ByteOrder = llvm::endianness::native; 2281 FileWriter FW(OutStrm, ByteOrder); 2282 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 2283 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 2284 ASSERT_THAT_EXPECTED(GR, Succeeded()); 2285 2286 // Test that the only function that made it was the "main" function. 2287 EXPECT_EQ(GR->getNumAddresses(), 1u); 2288 auto ExpFI = GR->getFunctionInfo(0x1000); 2289 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 2290 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000)); 2291 StringRef MethodName = GR->getString(ExpFI->Name); 2292 EXPECT_EQ(MethodName, "main"); 2293 } 2294 2295 TEST(GSYMTest, TestDWARFDeadStripAddr8) { 2296 // Check that various techniques that compilers use for dead code stripping 2297 // work for 4 byte addresses. Make sure we keep the good functions and 2298 // strip any functions whose name starts with "stripped". 2299 // 2300 // 1 - Compilers might set the low PC to -1 (UINT64_MAX) for compile unit 2301 // with 8 byte addresses ("stripped1") 2302 // 2 - Set the low and high PC to the same value ("stripped2") 2303 // 3 - Have the high PC lower than the low PC ("stripped3") 2304 // 2305 // 0x0000000b: DW_TAG_compile_unit 2306 // DW_AT_name ("/tmp/main.c") 2307 // DW_AT_low_pc (0x0000000000001000) 2308 // DW_AT_high_pc (0x0000000000002000) 2309 // DW_AT_language (DW_LANG_C_plus_plus) 2310 // 2311 // 0x0000001e: DW_TAG_subprogram 2312 // DW_AT_name ("main") 2313 // DW_AT_low_pc (0x0000000000001000) 2314 // DW_AT_high_pc (0x0000000000002000) 2315 // 2316 // 0x0000002f: DW_TAG_subprogram 2317 // DW_AT_name ("stripped1") 2318 // DW_AT_low_pc (0xffffffffffffffff) 2319 // DW_AT_high_pc (0x0000000000000000) 2320 // 2321 // 0x00000040: DW_TAG_subprogram 2322 // DW_AT_name ("stripped2") 2323 // DW_AT_low_pc (0x0000000000003000) 2324 // DW_AT_high_pc (0x0000000000003000) 2325 // 2326 // 0x00000055: DW_TAG_subprogram 2327 // DW_AT_name ("stripped3") 2328 // DW_AT_low_pc (0x0000000000004000) 2329 // DW_AT_high_pc (0x0000000000003fff) 2330 // 2331 // 0x0000006a: NULL 2332 2333 StringRef yamldata = R"( 2334 debug_str: 2335 - '' 2336 - '/tmp/main.c' 2337 - main 2338 - stripped1 2339 - stripped2 2340 - stripped3 2341 debug_abbrev: 2342 - Table: 2343 - Code: 0x00000001 2344 Tag: DW_TAG_compile_unit 2345 Children: DW_CHILDREN_yes 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 - Attribute: DW_AT_language 2354 Form: DW_FORM_data2 2355 - Code: 0x00000002 2356 Tag: DW_TAG_subprogram 2357 Children: DW_CHILDREN_no 2358 Attributes: 2359 - Attribute: DW_AT_name 2360 Form: DW_FORM_strp 2361 - Attribute: DW_AT_low_pc 2362 Form: DW_FORM_addr 2363 - Attribute: DW_AT_high_pc 2364 Form: DW_FORM_data4 2365 - Code: 0x00000003 2366 Tag: DW_TAG_subprogram 2367 Children: DW_CHILDREN_no 2368 Attributes: 2369 - Attribute: DW_AT_name 2370 Form: DW_FORM_strp 2371 - Attribute: DW_AT_low_pc 2372 Form: DW_FORM_addr 2373 - Attribute: DW_AT_high_pc 2374 Form: DW_FORM_addr 2375 debug_info: 2376 - Version: 4 2377 AddrSize: 8 2378 Entries: 2379 - AbbrCode: 0x00000001 2380 Values: 2381 - Value: 0x0000000000000001 2382 - Value: 0x0000000000001000 2383 - Value: 0x0000000000001000 2384 - Value: 0x0000000000000004 2385 - AbbrCode: 0x00000002 2386 Values: 2387 - Value: 0x000000000000000D 2388 - Value: 0x0000000000001000 2389 - Value: 0x0000000000001000 2390 - AbbrCode: 0x00000002 2391 Values: 2392 - Value: 0x0000000000000012 2393 - Value: 0xFFFFFFFFFFFFFFFF 2394 - Value: 0x0000000000000001 2395 - AbbrCode: 0x00000003 2396 Values: 2397 - Value: 0x000000000000001C 2398 - Value: 0x0000000000003000 2399 - Value: 0x0000000000003000 2400 - AbbrCode: 0x00000003 2401 Values: 2402 - Value: 0x0000000000000026 2403 - Value: 0x0000000000004000 2404 - Value: 0x0000000000003FFF 2405 - AbbrCode: 0x00000000 2406 )"; 2407 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 2408 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 2409 std::unique_ptr<DWARFContext> DwarfContext = 2410 DWARFContext::create(*ErrOrSections, 8); 2411 ASSERT_TRUE(DwarfContext.get() != nullptr); 2412 auto &OS = llvm::nulls(); 2413 OutputAggregator OSAgg(&OS); 2414 GsymCreator GC; 2415 DwarfTransformer DT(*DwarfContext, GC); 2416 const uint32_t ThreadCount = 1; 2417 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 2418 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 2419 SmallString<512> Str; 2420 raw_svector_ostream OutStrm(Str); 2421 const auto ByteOrder = llvm::endianness::native; 2422 FileWriter FW(OutStrm, ByteOrder); 2423 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 2424 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 2425 ASSERT_THAT_EXPECTED(GR, Succeeded()); 2426 2427 // Test that the only function that made it was the "main" function. 2428 EXPECT_EQ(GR->getNumAddresses(), 1u); 2429 auto ExpFI = GR->getFunctionInfo(0x1000); 2430 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 2431 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000)); 2432 StringRef MethodName = GR->getString(ExpFI->Name); 2433 EXPECT_EQ(MethodName, "main"); 2434 } 2435 2436 TEST(GSYMTest, TestGsymCreatorMultipleSymbolsWithNoSize) { 2437 // Multiple symbols at the same address with zero size were being emitted 2438 // instead of being combined into a single entry. This function tests to make 2439 // sure we only get one symbol. 2440 uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; 2441 GsymCreator GC; 2442 GC.setUUID(UUID); 2443 constexpr uint64_t BaseAddr = 0x1000; 2444 constexpr uint8_t AddrOffSize = 1; 2445 const uint32_t Func1Name = GC.insertString("foo"); 2446 const uint32_t Func2Name = GC.insertString("bar"); 2447 GC.addFunctionInfo(FunctionInfo(BaseAddr, 0, Func1Name)); 2448 GC.addFunctionInfo(FunctionInfo(BaseAddr, 0, Func2Name)); 2449 OutputAggregator Null(nullptr); 2450 Error Err = GC.finalize(Null); 2451 ASSERT_FALSE(Err); 2452 TestEncodeDecode(GC, llvm::endianness::little, GSYM_VERSION, AddrOffSize, 2453 BaseAddr, 2454 1, // NumAddresses 2455 ArrayRef<uint8_t>(UUID)); 2456 TestEncodeDecode(GC, llvm::endianness::big, GSYM_VERSION, AddrOffSize, 2457 BaseAddr, 2458 1, // NumAddresses 2459 ArrayRef<uint8_t>(UUID)); 2460 } 2461 2462 // Helper function to quickly create a FunctionInfo in a GsymCreator for testing. 2463 static void AddFunctionInfo(GsymCreator &GC, const char *FuncName, 2464 uint64_t FuncAddr, const char *SourcePath, 2465 const char *HeaderPath) { 2466 FunctionInfo FI(FuncAddr, 0x30, GC.insertString(FuncName)); 2467 FI.OptLineTable = LineTable(); 2468 const uint32_t SourceFileIdx = GC.insertFile(SourcePath); 2469 const uint32_t HeaderFileIdx = GC.insertFile(HeaderPath); 2470 FI.OptLineTable->push(LineEntry(FuncAddr+0x00, SourceFileIdx, 5)); 2471 FI.OptLineTable->push(LineEntry(FuncAddr+0x10, HeaderFileIdx, 10)); 2472 FI.OptLineTable->push(LineEntry(FuncAddr+0x12, HeaderFileIdx, 20)); 2473 FI.OptLineTable->push(LineEntry(FuncAddr+0x14, HeaderFileIdx, 11)); 2474 FI.OptLineTable->push(LineEntry(FuncAddr+0x16, HeaderFileIdx, 30)); 2475 FI.OptLineTable->push(LineEntry(FuncAddr+0x18, HeaderFileIdx, 12)); 2476 FI.OptLineTable->push(LineEntry(FuncAddr+0x20, SourceFileIdx, 8)); 2477 FI.Inline = InlineInfo(); 2478 2479 std::string InlineName1(FuncName); InlineName1.append("1"); 2480 std::string InlineName2(FuncName); InlineName2.append("2"); 2481 std::string InlineName3(FuncName); InlineName3.append("3"); 2482 2483 FI.Inline->Name = GC.insertString(InlineName1); 2484 FI.Inline->CallFile = SourceFileIdx; 2485 FI.Inline->CallLine = 6; 2486 FI.Inline->Ranges.insert(AddressRange(FuncAddr + 0x10, FuncAddr + 0x20)); 2487 InlineInfo Inline2; 2488 Inline2.Name = GC.insertString(InlineName2); 2489 Inline2.CallFile = HeaderFileIdx; 2490 Inline2.CallLine = 33; 2491 Inline2.Ranges.insert(AddressRange(FuncAddr + 0x12, FuncAddr + 0x14)); 2492 FI.Inline->Children.emplace_back(Inline2); 2493 InlineInfo Inline3; 2494 Inline3.Name = GC.insertString(InlineName3); 2495 Inline3.CallFile = HeaderFileIdx; 2496 Inline3.CallLine = 35; 2497 Inline3.Ranges.insert(AddressRange(FuncAddr + 0x16, FuncAddr + 0x18)); 2498 FI.Inline->Children.emplace_back(Inline3); 2499 GC.addFunctionInfo(std::move(FI)); 2500 } 2501 2502 // Finalize a GsymCreator, encode it and decode it and return the error or 2503 // GsymReader that was successfully decoded. 2504 static Expected<GsymReader> FinalizeEncodeAndDecode(GsymCreator &GC) { 2505 OutputAggregator Null(nullptr); 2506 Error FinalizeErr = GC.finalize(Null); 2507 if (FinalizeErr) 2508 return std::move(FinalizeErr); 2509 SmallString<1024> Str; 2510 raw_svector_ostream OutStrm(Str); 2511 const auto ByteOrder = llvm::endianness::native; 2512 FileWriter FW(OutStrm, ByteOrder); 2513 llvm::Error Err = GC.encode(FW); 2514 if (Err) 2515 return std::move(Err); 2516 return GsymReader::copyBuffer(OutStrm.str()); 2517 } 2518 2519 TEST(GSYMTest, TestGsymSegmenting) { 2520 // Test creating a GSYM file with function infos and segment the information. 2521 // We verify segmenting is working by creating a full GSYM and also by 2522 // encoding multiple segments, then we verify that we get the same information 2523 // when doing lookups on the full GSYM that was decoded from encoding the 2524 // entire GSYM and also by decoding information from the segments themselves. 2525 GsymCreator GC; 2526 GC.setBaseAddress(0); 2527 AddFunctionInfo(GC, "main", 0x1000, "/tmp/main.c", "/tmp/main.h"); 2528 AddFunctionInfo(GC, "foo", 0x2000, "/tmp/foo.c", "/tmp/foo.h"); 2529 AddFunctionInfo(GC, "bar", 0x3000, "/tmp/bar.c", "/tmp/bar.h"); 2530 AddFunctionInfo(GC, "baz", 0x4000, "/tmp/baz.c", "/tmp/baz.h"); 2531 Expected<GsymReader> GR = FinalizeEncodeAndDecode(GC); 2532 ASSERT_THAT_EXPECTED(GR, Succeeded()); 2533 //GR->dump(outs()); 2534 2535 // Create segmented GSYM files where each file contains 1 function. We will 2536 // then test doing lookups on the "GR", or the full GSYM file and then test 2537 // doing lookups on the GsymReader objects for each segment to ensure we get 2538 // the exact same information. So after all of the code below we will have 2539 // GsymReader objects that each contain one function. We name the creators 2540 // and readers to match the one and only address they contain. 2541 // GC1000 and GR1000 are for [0x1000-0x1030) 2542 // GC2000 and GR2000 are for [0x2000-0x2030) 2543 // GC3000 and GR3000 are for [0x3000-0x3030) 2544 // GC4000 and GR4000 are for [0x4000-0x4030) 2545 2546 // Create the segments and verify that FuncIdx, an in/out parameter, gets 2547 // updated as expected. 2548 size_t FuncIdx = 0; 2549 // Make sure we get an error if the segment size is too small to encode a 2550 // single function info. 2551 llvm::Expected<std::unique_ptr<GsymCreator>> GCError = 2552 GC.createSegment(57, FuncIdx); 2553 ASSERT_FALSE((bool)GCError); 2554 checkError("a segment size of 57 is to small to fit any function infos, " 2555 "specify a larger value", GCError.takeError()); 2556 // Make sure that the function index didn't get incremented when we didn't 2557 // encode any values into the segmented GsymCreator. 2558 ASSERT_EQ(FuncIdx, (size_t)0); 2559 2560 llvm::Expected<std::unique_ptr<GsymCreator>> GC1000 = 2561 GC.createSegment(128, FuncIdx); 2562 ASSERT_THAT_EXPECTED(GC1000, Succeeded()); 2563 ASSERT_EQ(FuncIdx, (size_t)1); 2564 llvm::Expected<std::unique_ptr<GsymCreator>> GC2000 = 2565 GC.createSegment(128, FuncIdx); 2566 ASSERT_THAT_EXPECTED(GC2000, Succeeded()); 2567 ASSERT_EQ(FuncIdx, (size_t)2); 2568 llvm::Expected<std::unique_ptr<GsymCreator>> GC3000 = 2569 GC.createSegment(128, FuncIdx); 2570 ASSERT_THAT_EXPECTED(GC3000, Succeeded()); 2571 ASSERT_EQ(FuncIdx, (size_t)3); 2572 llvm::Expected<std::unique_ptr<GsymCreator>> GC4000 = 2573 GC.createSegment(128, FuncIdx); 2574 ASSERT_THAT_EXPECTED(GC4000, Succeeded()); 2575 ASSERT_EQ(FuncIdx, (size_t)4); 2576 // When there are no function infos left to encode we expect to get no error 2577 // and get a NULL GsymCreator in the return value from createSegment. 2578 llvm::Expected<std::unique_ptr<GsymCreator>> GCNull = 2579 GC.createSegment(128, FuncIdx); 2580 ASSERT_THAT_EXPECTED(GCNull, Succeeded()); 2581 ASSERT_TRUE(GC1000.get() != nullptr); 2582 ASSERT_TRUE(GC2000.get() != nullptr); 2583 ASSERT_TRUE(GC3000.get() != nullptr); 2584 ASSERT_TRUE(GC4000.get() != nullptr); 2585 ASSERT_TRUE(GCNull.get() == nullptr); 2586 // Encode and decode the GsymReader for each segment and verify they succeed. 2587 Expected<GsymReader> GR1000 = FinalizeEncodeAndDecode(*GC1000.get()); 2588 ASSERT_THAT_EXPECTED(GR1000, Succeeded()); 2589 Expected<GsymReader> GR2000 = FinalizeEncodeAndDecode(*GC2000.get()); 2590 ASSERT_THAT_EXPECTED(GR2000, Succeeded()); 2591 Expected<GsymReader> GR3000 = FinalizeEncodeAndDecode(*GC3000.get()); 2592 ASSERT_THAT_EXPECTED(GR3000, Succeeded()); 2593 Expected<GsymReader> GR4000 = FinalizeEncodeAndDecode(*GC4000.get()); 2594 ASSERT_THAT_EXPECTED(GR4000, Succeeded()); 2595 2596 // Verify that all lookups match the range [0x1000-0x1030) when doing lookups 2597 // in the GsymReader that contains all functions and from the segmented 2598 // GsymReader in GR1000. 2599 for (uint64_t Addr = 0x1000; Addr < 0x1030; ++Addr) { 2600 // Lookup in the main GsymReader that contains all function infos 2601 auto MainLR = GR->lookup(Addr); 2602 ASSERT_THAT_EXPECTED(MainLR, Succeeded()); 2603 auto SegmentLR = GR1000->lookup(Addr); 2604 ASSERT_THAT_EXPECTED(SegmentLR, Succeeded()); 2605 // Make sure the lookup results match. 2606 EXPECT_EQ(MainLR.get(), SegmentLR.get()); 2607 // Make sure that the lookups on the functions that are not in the segment 2608 // fail as expected. 2609 ASSERT_THAT_EXPECTED(GR1000->lookup(0x2000), Failed()); 2610 ASSERT_THAT_EXPECTED(GR1000->lookup(0x3000), Failed()); 2611 ASSERT_THAT_EXPECTED(GR1000->lookup(0x4000), Failed()); 2612 } 2613 2614 // Verify that all lookups match the range [0x2000-0x2030) when doing lookups 2615 // in the GsymReader that contains all functions and from the segmented 2616 // GsymReader in GR2000. 2617 for (uint64_t Addr = 0x2000; Addr < 0x2030; ++Addr) { 2618 // Lookup in the main GsymReader that contains all function infos 2619 auto MainLR = GR->lookup(Addr); 2620 ASSERT_THAT_EXPECTED(MainLR, Succeeded()); 2621 auto SegmentLR = GR2000->lookup(Addr); 2622 ASSERT_THAT_EXPECTED(SegmentLR, Succeeded()); 2623 // Make sure the lookup results match. 2624 EXPECT_EQ(MainLR.get(), SegmentLR.get()); 2625 // Make sure that the lookups on the functions that are not in the segment 2626 // fail as expected. 2627 ASSERT_THAT_EXPECTED(GR2000->lookup(0x1000), Failed()); 2628 ASSERT_THAT_EXPECTED(GR2000->lookup(0x3000), Failed()); 2629 ASSERT_THAT_EXPECTED(GR2000->lookup(0x4000), Failed()); 2630 2631 } 2632 2633 // Verify that all lookups match the range [0x3000-0x3030) when doing lookups 2634 // in the GsymReader that contains all functions and from the segmented 2635 // GsymReader in GR3000. 2636 for (uint64_t Addr = 0x3000; Addr < 0x3030; ++Addr) { 2637 // Lookup in the main GsymReader that contains all function infos 2638 auto MainLR = GR->lookup(Addr); 2639 ASSERT_THAT_EXPECTED(MainLR, Succeeded()); 2640 auto SegmentLR = GR3000->lookup(Addr); 2641 ASSERT_THAT_EXPECTED(SegmentLR, Succeeded()); 2642 // Make sure the lookup results match. 2643 EXPECT_EQ(MainLR.get(), SegmentLR.get()); 2644 // Make sure that the lookups on the functions that are not in the segment 2645 // fail as expected. 2646 ASSERT_THAT_EXPECTED(GR3000->lookup(0x1000), Failed()); 2647 ASSERT_THAT_EXPECTED(GR3000->lookup(0x2000), Failed()); 2648 ASSERT_THAT_EXPECTED(GR3000->lookup(0x4000), Failed()); 2649 } 2650 2651 // Verify that all lookups match the range [0x4000-0x4030) when doing lookups 2652 // in the GsymReader that contains all functions and from the segmented 2653 // GsymReader in GR4000. 2654 for (uint64_t Addr = 0x4000; Addr < 0x4030; ++Addr) { 2655 // Lookup in the main GsymReader that contains all function infos 2656 auto MainLR = GR->lookup(Addr); 2657 ASSERT_THAT_EXPECTED(MainLR, Succeeded()); 2658 // Lookup in the GsymReader for that contains 0x4000 2659 auto SegmentLR = GR4000->lookup(Addr); 2660 ASSERT_THAT_EXPECTED(SegmentLR, Succeeded()); 2661 // Make sure the lookup results match. 2662 EXPECT_EQ(MainLR.get(), SegmentLR.get()); 2663 // Make sure that the lookups on the functions that are not in the segment 2664 // fail as expected. 2665 ASSERT_THAT_EXPECTED(GR4000->lookup(0x1000), Failed()); 2666 ASSERT_THAT_EXPECTED(GR4000->lookup(0x2000), Failed()); 2667 ASSERT_THAT_EXPECTED(GR4000->lookup(0x3000), Failed()); 2668 } 2669 } 2670 2671 TEST(GSYMTest, TestGsymSegmentingNoBase) { 2672 // Test creating a GSYM file with function infos and segment the information. 2673 // We verify segmenting is working by creating a full GSYM and also by 2674 // encoding multiple segments, then we verify that we get the same information 2675 // when doing lookups on the full GSYM that was decoded from encoding the 2676 // entire GSYM and also by decoding information from the segments themselves. 2677 GsymCreator GC; 2678 AddFunctionInfo(GC, "main", 0x1000, "/tmp/main.c", "/tmp/main.h"); 2679 AddFunctionInfo(GC, "foo", 0x2000, "/tmp/foo.c", "/tmp/foo.h"); 2680 AddFunctionInfo(GC, "bar", 0x3000, "/tmp/bar.c", "/tmp/bar.h"); 2681 AddFunctionInfo(GC, "baz", 0x4000, "/tmp/baz.c", "/tmp/baz.h"); 2682 Expected<GsymReader> GR = FinalizeEncodeAndDecode(GC); 2683 ASSERT_THAT_EXPECTED(GR, Succeeded()); 2684 //GR->dump(outs()); 2685 2686 // Create segmented GSYM files where each file contains 1 function. We will 2687 // then test doing lookups on the "GR", or the full GSYM file and then test 2688 // doing lookups on the GsymReader objects for each segment to ensure we get 2689 // the exact same information. So after all of the code below we will have 2690 // GsymReader objects that each contain one function. We name the creators 2691 // and readers to match the one and only address they contain. 2692 // GC1000 and GR1000 are for [0x1000-0x1030) 2693 // GC2000 and GR2000 are for [0x2000-0x2030) 2694 // GC3000 and GR3000 are for [0x3000-0x3030) 2695 // GC4000 and GR4000 are for [0x4000-0x4030) 2696 2697 // Create the segments and verify that FuncIdx, an in/out parameter, gets 2698 // updated as expected. 2699 size_t FuncIdx = 0; 2700 // Make sure we get an error if the segment size is too small to encode a 2701 // single function info. 2702 llvm::Expected<std::unique_ptr<GsymCreator>> GCError = 2703 GC.createSegment(57, FuncIdx); 2704 ASSERT_FALSE((bool)GCError); 2705 checkError("a segment size of 57 is to small to fit any function infos, " 2706 "specify a larger value", GCError.takeError()); 2707 // Make sure that the function index didn't get incremented when we didn't 2708 // encode any values into the segmented GsymCreator. 2709 ASSERT_EQ(FuncIdx, (size_t)0); 2710 2711 llvm::Expected<std::unique_ptr<GsymCreator>> GC1000 = 2712 GC.createSegment(128, FuncIdx); 2713 ASSERT_THAT_EXPECTED(GC1000, Succeeded()); 2714 ASSERT_EQ(FuncIdx, (size_t)1); 2715 llvm::Expected<std::unique_ptr<GsymCreator>> GC2000 = 2716 GC.createSegment(128, FuncIdx); 2717 ASSERT_THAT_EXPECTED(GC2000, Succeeded()); 2718 ASSERT_EQ(FuncIdx, (size_t)2); 2719 llvm::Expected<std::unique_ptr<GsymCreator>> GC3000 = 2720 GC.createSegment(128, FuncIdx); 2721 ASSERT_THAT_EXPECTED(GC3000, Succeeded()); 2722 ASSERT_EQ(FuncIdx, (size_t)3); 2723 llvm::Expected<std::unique_ptr<GsymCreator>> GC4000 = 2724 GC.createSegment(128, FuncIdx); 2725 ASSERT_THAT_EXPECTED(GC4000, Succeeded()); 2726 ASSERT_EQ(FuncIdx, (size_t)4); 2727 // When there are no function infos left to encode we expect to get no error 2728 // and get a NULL GsymCreator in the return value from createSegment. 2729 llvm::Expected<std::unique_ptr<GsymCreator>> GCNull = 2730 GC.createSegment(128, FuncIdx); 2731 ASSERT_THAT_EXPECTED(GCNull, Succeeded()); 2732 ASSERT_TRUE(GC1000.get() != nullptr); 2733 ASSERT_TRUE(GC2000.get() != nullptr); 2734 ASSERT_TRUE(GC3000.get() != nullptr); 2735 ASSERT_TRUE(GC4000.get() != nullptr); 2736 ASSERT_TRUE(GCNull.get() == nullptr); 2737 // Encode and decode the GsymReader for each segment and verify they succeed. 2738 Expected<GsymReader> GR1000 = FinalizeEncodeAndDecode(*GC1000.get()); 2739 ASSERT_THAT_EXPECTED(GR1000, Succeeded()); 2740 Expected<GsymReader> GR2000 = FinalizeEncodeAndDecode(*GC2000.get()); 2741 ASSERT_THAT_EXPECTED(GR2000, Succeeded()); 2742 Expected<GsymReader> GR3000 = FinalizeEncodeAndDecode(*GC3000.get()); 2743 ASSERT_THAT_EXPECTED(GR3000, Succeeded()); 2744 Expected<GsymReader> GR4000 = FinalizeEncodeAndDecode(*GC4000.get()); 2745 ASSERT_THAT_EXPECTED(GR4000, Succeeded()); 2746 2747 // Verify that all lookups match the range [0x1000-0x1030) when doing lookups 2748 // in the GsymReader that contains all functions and from the segmented 2749 // GsymReader in GR1000. 2750 for (uint64_t Addr = 0x1000; Addr < 0x1030; ++Addr) { 2751 // Lookup in the main GsymReader that contains all function infos 2752 auto MainLR = GR->lookup(Addr); 2753 ASSERT_THAT_EXPECTED(MainLR, Succeeded()); 2754 auto SegmentLR = GR1000->lookup(Addr); 2755 ASSERT_THAT_EXPECTED(SegmentLR, Succeeded()); 2756 // Make sure the lookup results match. 2757 EXPECT_EQ(MainLR.get(), SegmentLR.get()); 2758 // Make sure that the lookups on the functions that are not in the segment 2759 // fail as expected. 2760 ASSERT_THAT_EXPECTED(GR1000->lookup(0x2000), Failed()); 2761 ASSERT_THAT_EXPECTED(GR1000->lookup(0x3000), Failed()); 2762 ASSERT_THAT_EXPECTED(GR1000->lookup(0x4000), Failed()); 2763 } 2764 2765 // Verify that all lookups match the range [0x2000-0x2030) when doing lookups 2766 // in the GsymReader that contains all functions and from the segmented 2767 // GsymReader in GR2000. 2768 for (uint64_t Addr = 0x2000; Addr < 0x2030; ++Addr) { 2769 // Lookup in the main GsymReader that contains all function infos 2770 auto MainLR = GR->lookup(Addr); 2771 ASSERT_THAT_EXPECTED(MainLR, Succeeded()); 2772 auto SegmentLR = GR2000->lookup(Addr); 2773 ASSERT_THAT_EXPECTED(SegmentLR, Succeeded()); 2774 // Make sure the lookup results match. 2775 EXPECT_EQ(MainLR.get(), SegmentLR.get()); 2776 // Make sure that the lookups on the functions that are not in the segment 2777 // fail as expected. 2778 ASSERT_THAT_EXPECTED(GR2000->lookup(0x1000), Failed()); 2779 ASSERT_THAT_EXPECTED(GR2000->lookup(0x3000), Failed()); 2780 ASSERT_THAT_EXPECTED(GR2000->lookup(0x4000), Failed()); 2781 2782 } 2783 2784 // Verify that all lookups match the range [0x3000-0x3030) when doing lookups 2785 // in the GsymReader that contains all functions and from the segmented 2786 // GsymReader in GR3000. 2787 for (uint64_t Addr = 0x3000; Addr < 0x3030; ++Addr) { 2788 // Lookup in the main GsymReader that contains all function infos 2789 auto MainLR = GR->lookup(Addr); 2790 ASSERT_THAT_EXPECTED(MainLR, Succeeded()); 2791 auto SegmentLR = GR3000->lookup(Addr); 2792 ASSERT_THAT_EXPECTED(SegmentLR, Succeeded()); 2793 // Make sure the lookup results match. 2794 EXPECT_EQ(MainLR.get(), SegmentLR.get()); 2795 // Make sure that the lookups on the functions that are not in the segment 2796 // fail as expected. 2797 ASSERT_THAT_EXPECTED(GR3000->lookup(0x1000), Failed()); 2798 ASSERT_THAT_EXPECTED(GR3000->lookup(0x2000), Failed()); 2799 ASSERT_THAT_EXPECTED(GR3000->lookup(0x4000), Failed()); 2800 } 2801 2802 // Verify that all lookups match the range [0x4000-0x4030) when doing lookups 2803 // in the GsymReader that contains all functions and from the segmented 2804 // GsymReader in GR4000. 2805 for (uint64_t Addr = 0x4000; Addr < 0x4030; ++Addr) { 2806 // Lookup in the main GsymReader that contains all function infos 2807 auto MainLR = GR->lookup(Addr); 2808 ASSERT_THAT_EXPECTED(MainLR, Succeeded()); 2809 // Lookup in the GsymReader for that contains 0x4000 2810 auto SegmentLR = GR4000->lookup(Addr); 2811 ASSERT_THAT_EXPECTED(SegmentLR, Succeeded()); 2812 // Make sure the lookup results match. 2813 EXPECT_EQ(MainLR.get(), SegmentLR.get()); 2814 // Make sure that the lookups on the functions that are not in the segment 2815 // fail as expected. 2816 ASSERT_THAT_EXPECTED(GR4000->lookup(0x1000), Failed()); 2817 ASSERT_THAT_EXPECTED(GR4000->lookup(0x2000), Failed()); 2818 ASSERT_THAT_EXPECTED(GR4000->lookup(0x3000), Failed()); 2819 } 2820 } 2821 2822 2823 TEST(GSYMTest, TestDWARFInlineRangeScopes) { 2824 // Test cases where inlined functions address ranges are not contained in the 2825 // parent ranges and that we can successfully remove them and emit error 2826 // messages. The DWARF for this looks like the dump below. The inlined 2827 // functions named "invalid1" and "invalid2" are expected to be removed and 2828 // an appropriate error message will be emitted. 2829 // 2830 // 0x0000000b: DW_TAG_compile_unit 2831 // DW_AT_name ("/tmp/main.cpp") 2832 // DW_AT_language (DW_LANG_C) 2833 // DW_AT_stmt_list (0x00000000) 2834 // 2835 // 0x00000015: DW_TAG_subprogram 2836 // DW_AT_name ("foo") 2837 // DW_AT_low_pc (0x0000000000001000) 2838 // DW_AT_high_pc (0x0000000000002000) 2839 // 2840 // 0x0000002a: DW_TAG_inlined_subroutine 2841 // DW_AT_name ("invalid1") 2842 // DW_AT_low_pc (0x0000000000000fff) 2843 // DW_AT_high_pc (0x0000000000001001) 2844 // DW_AT_call_file ("/tmp/main.cpp") 2845 // DW_AT_call_line (10) 2846 // 2847 // 0x00000041: DW_TAG_inlined_subroutine 2848 // DW_AT_name ("valid1") 2849 // DW_AT_low_pc (0x0000000000001010) 2850 // DW_AT_high_pc (0x0000000000001100) 2851 // DW_AT_call_file ("/tmp/main.cpp") 2852 // DW_AT_call_line (11) 2853 // 2854 // 0x00000058: DW_TAG_inlined_subroutine 2855 // DW_AT_name ("invalid2") 2856 // DW_AT_low_pc (0x0000000000001000) 2857 // DW_AT_high_pc (0x0000000000001100) 2858 // DW_AT_call_file ("/tmp/main.cpp") 2859 // DW_AT_call_line (12) 2860 // 2861 // 0x0000006f: DW_TAG_inlined_subroutine 2862 // DW_AT_name ("valid2") 2863 // DW_AT_low_pc (0x0000000000001020) 2864 // DW_AT_high_pc (0x0000000000001030) 2865 // DW_AT_call_file ("/tmp/main.cpp") 2866 // DW_AT_call_line (13) 2867 // 2868 // 0x00000086: NULL 2869 // 2870 // 0x00000087: NULL 2871 // 2872 // 0x00000088: NULL 2873 2874 StringRef yamldata = R"( 2875 debug_str: 2876 - '' 2877 - '/tmp/main.cpp' 2878 - foo 2879 - invalid1 2880 - valid1 2881 - invalid2 2882 - valid2 2883 debug_abbrev: 2884 - ID: 0 2885 Table: 2886 - Code: 0x1 2887 Tag: DW_TAG_compile_unit 2888 Children: DW_CHILDREN_yes 2889 Attributes: 2890 - Attribute: DW_AT_name 2891 Form: DW_FORM_strp 2892 - Attribute: DW_AT_language 2893 Form: DW_FORM_udata 2894 - Attribute: DW_AT_stmt_list 2895 Form: DW_FORM_sec_offset 2896 - Code: 0x2 2897 Tag: DW_TAG_subprogram 2898 Children: DW_CHILDREN_yes 2899 Attributes: 2900 - Attribute: DW_AT_name 2901 Form: DW_FORM_strp 2902 - Attribute: DW_AT_low_pc 2903 Form: DW_FORM_addr 2904 - Attribute: DW_AT_high_pc 2905 Form: DW_FORM_addr 2906 - Code: 0x3 2907 Tag: DW_TAG_inlined_subroutine 2908 Children: DW_CHILDREN_no 2909 Attributes: 2910 - Attribute: DW_AT_name 2911 Form: DW_FORM_strp 2912 - Attribute: DW_AT_low_pc 2913 Form: DW_FORM_addr 2914 - Attribute: DW_AT_high_pc 2915 Form: DW_FORM_addr 2916 - Attribute: DW_AT_call_file 2917 Form: DW_FORM_data1 2918 - Attribute: DW_AT_call_line 2919 Form: DW_FORM_data1 2920 - Code: 0x4 2921 Tag: DW_TAG_inlined_subroutine 2922 Children: DW_CHILDREN_yes 2923 Attributes: 2924 - Attribute: DW_AT_name 2925 Form: DW_FORM_strp 2926 - Attribute: DW_AT_low_pc 2927 Form: DW_FORM_addr 2928 - Attribute: DW_AT_high_pc 2929 Form: DW_FORM_addr 2930 - Attribute: DW_AT_call_file 2931 Form: DW_FORM_data1 2932 - Attribute: DW_AT_call_line 2933 Form: DW_FORM_data1 2934 debug_info: 2935 - Length: 0x85 2936 Version: 4 2937 AbbrevTableID: 0 2938 AbbrOffset: 0x0 2939 AddrSize: 8 2940 Entries: 2941 - AbbrCode: 0x1 2942 Values: 2943 - Value: 0x1 2944 - Value: 0x2 2945 - Value: 0x0 2946 - AbbrCode: 0x2 2947 Values: 2948 - Value: 0xF 2949 - Value: 0x1000 2950 - Value: 0x2000 2951 - AbbrCode: 0x3 2952 Values: 2953 - Value: 0x13 2954 - Value: 0xFFF 2955 - Value: 0x1001 2956 - Value: 0x1 2957 - Value: 0xA 2958 - AbbrCode: 0x4 2959 Values: 2960 - Value: 0x1C 2961 - Value: 0x1010 2962 - Value: 0x1100 2963 - Value: 0x1 2964 - Value: 0xB 2965 - AbbrCode: 0x3 2966 Values: 2967 - Value: 0x23 2968 - Value: 0x1000 2969 - Value: 0x1100 2970 - Value: 0x1 2971 - Value: 0xC 2972 - AbbrCode: 0x3 2973 Values: 2974 - Value: 0x2C 2975 - Value: 0x1020 2976 - Value: 0x1030 2977 - Value: 0x1 2978 - Value: 0xD 2979 - AbbrCode: 0x0 2980 - AbbrCode: 0x0 2981 - AbbrCode: 0x0 2982 debug_line: 2983 - Length: 84 2984 Version: 2 2985 PrologueLength: 36 2986 MinInstLength: 1 2987 DefaultIsStmt: 1 2988 LineBase: 251 2989 LineRange: 14 2990 OpcodeBase: 13 2991 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 2992 IncludeDirs: 2993 - '/tmp' 2994 Files: 2995 - Name: main.cpp 2996 DirIdx: 1 2997 ModTime: 0 2998 Length: 0 2999 Opcodes: 3000 - Opcode: DW_LNS_extended_op 3001 ExtLen: 9 3002 SubOpcode: DW_LNE_set_address 3003 Data: 4096 3004 - Opcode: DW_LNS_advance_line 3005 SData: 9 3006 Data: 0 3007 - Opcode: DW_LNS_copy 3008 Data: 0 3009 - Opcode: DW_LNS_advance_pc 3010 Data: 16 3011 - Opcode: DW_LNS_advance_line 3012 SData: 1 3013 Data: 0 3014 - Opcode: DW_LNS_copy 3015 Data: 0 3016 - Opcode: DW_LNS_advance_pc 3017 Data: 16 3018 - Opcode: DW_LNS_advance_line 3019 SData: 1 3020 Data: 0 3021 - Opcode: DW_LNS_copy 3022 Data: 0 3023 - Opcode: DW_LNS_advance_pc 3024 Data: 16 3025 - Opcode: DW_LNS_advance_line 3026 SData: 1 3027 Data: 0 3028 - Opcode: DW_LNS_copy 3029 Data: 0 3030 - Opcode: DW_LNS_advance_pc 3031 Data: 4048 3032 - Opcode: DW_LNS_advance_line 3033 SData: 1 3034 Data: 0 3035 - Opcode: DW_LNS_copy 3036 Data: 0 3037 - Opcode: DW_LNS_advance_pc 3038 Data: 16 3039 - Opcode: DW_LNS_advance_line 3040 SData: -1 3041 Data: 0 3042 - Opcode: DW_LNS_extended_op 3043 ExtLen: 1 3044 SubOpcode: DW_LNE_end_sequence 3045 Data: 0 3046 )"; 3047 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 3048 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 3049 std::unique_ptr<DWARFContext> DwarfContext = 3050 DWARFContext::create(*ErrOrSections, 8); 3051 ASSERT_TRUE(DwarfContext.get() != nullptr); 3052 std::string errors; 3053 raw_string_ostream OS(errors); 3054 OutputAggregator OSAgg(&OS); 3055 GsymCreator GC; 3056 DwarfTransformer DT(*DwarfContext, GC); 3057 const uint32_t ThreadCount = 1; 3058 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 3059 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 3060 SmallString<512> Str; 3061 raw_svector_ostream OutStrm(Str); 3062 const auto ByteOrder = llvm::endianness::native; 3063 FileWriter FW(OutStrm, ByteOrder); 3064 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 3065 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 3066 ASSERT_THAT_EXPECTED(GR, Succeeded()); 3067 // There should only be one function in our GSYM. 3068 EXPECT_EQ(GR->getNumAddresses(), 1u); 3069 auto ExpFI = GR->getFunctionInfo(0x1000); 3070 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 3071 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x2000)); 3072 EXPECT_TRUE(ExpFI->OptLineTable.has_value()); 3073 EXPECT_TRUE(ExpFI->Inline.has_value()); 3074 StringRef FuncName = GR->getString(ExpFI->Name); 3075 EXPECT_EQ(FuncName, "foo"); 3076 std::vector<std::string> ExpectedLogErrors = { 3077 "error: inlined function DIE at 0x0000002a has a range [0x0000000000000fff " 3078 "- 0x0000000000001001) that isn't contained in any parent address ranges, " 3079 "this inline range will be removed.", 3080 "error: inlined function DIE at 0x00000058 has a range [0x0000000000001000 " 3081 "- 0x0000000000001100) that isn't contained in any parent address ranges, " 3082 "this inline range will be removed." 3083 }; 3084 // Make sure all expected errors are in the error stream for the two invalid 3085 // inlined functions that we removed due to invalid range scoping. 3086 for (const auto &Error: ExpectedLogErrors) { 3087 EXPECT_TRUE(OS.str().find(Error) != std::string::npos); 3088 } 3089 // The top level inline info is for the function "foo" itself. Verify that 3090 // we have only 1 inline function inside of this, even though the DWARF 3091 // contains two. One of the inline functions in "foo" is invalid, so we must 3092 // only end up with 1. 3093 StringRef InlineFuncName = GR->getString(ExpFI->Inline->Name); 3094 EXPECT_EQ(InlineFuncName, "foo"); 3095 EXPECT_EQ(ExpFI->Inline->CallFile, 0u); 3096 EXPECT_EQ(ExpFI->Inline->CallLine, 0u); 3097 EXPECT_EQ(ExpFI->Inline->Children.size(), 1u); 3098 3099 3100 // The first inline function "valid1" contains two inline functions in the 3101 // DWARF, but one has an address range which isn't contained in any ranges 3102 // from "foo", so only 1 inline function be parsed. 3103 InlineInfo &Inline1 = ExpFI->Inline->Children[0]; 3104 StringRef Inline1Name = GR->getString(Inline1.Name); 3105 EXPECT_EQ(Inline1Name, "valid1"); 3106 EXPECT_EQ(Inline1.CallFile, 1u); 3107 EXPECT_EQ(Inline1.CallLine, 11u); 3108 EXPECT_EQ(Inline1.Children.size(), 1u); 3109 3110 3111 // The second inline function "valid2" contains two inline functions in the 3112 // DWARF, but one has an address range which isn't contained in any ranges 3113 // from "valid1", so only 1 inline function be parsed. 3114 InlineInfo &Inline2 = Inline1.Children[0]; 3115 StringRef Inline2Name = GR->getString(Inline2.Name); 3116 EXPECT_EQ(Inline2Name, "valid2"); 3117 EXPECT_EQ(Inline2.CallFile, 1u); 3118 EXPECT_EQ(Inline2.CallLine, 13u); 3119 EXPECT_EQ(Inline2.Children.size(), 0u); 3120 } 3121 3122 TEST(GSYMTest, TestDWARFEmptyInline) { 3123 // Test cases where we have inline function information in the DWARF that 3124 // results in us trying to parse the inline info, but since the inline 3125 // info ends up not adding any valid inline functions due to ranges 3126 // not being correct, we end up not encoding any inline information. This 3127 // tests that if we end up creating an empty inline info struct, we end up 3128 // not encoding it into the GSYM file. 3129 // 3130 // 0x0000000b: DW_TAG_compile_unit 3131 // DW_AT_name ("/tmp/main.cpp") 3132 // DW_AT_language (DW_LANG_C) 3133 // DW_AT_stmt_list (0x00000000) 3134 // 3135 // 0x00000015: DW_TAG_subprogram 3136 // DW_AT_name ("foo") 3137 // DW_AT_low_pc (0x0000000000001000) 3138 // DW_AT_high_pc (0x0000000000001050) 3139 // 3140 // 0x0000002a: DW_TAG_inlined_subroutine 3141 // DW_AT_name ("inlineWithInvalidRange") 3142 // DW_AT_low_pc (0x0000000000001100) 3143 // DW_AT_high_pc (0x0000000000001200) 3144 // DW_AT_call_file ("/tmp/main.cpp") 3145 // DW_AT_call_line (11) 3146 // 3147 // 0x00000047: NULL 3148 // 3149 // 0x00000048: NULL 3150 3151 StringRef yamldata = R"( 3152 debug_str: 3153 - '' 3154 - '/tmp/main.cpp' 3155 - foo 3156 - inlineWithInvalidRange 3157 debug_abbrev: 3158 - ID: 0 3159 Table: 3160 - Code: 0x1 3161 Tag: DW_TAG_compile_unit 3162 Children: DW_CHILDREN_yes 3163 Attributes: 3164 - Attribute: DW_AT_name 3165 Form: DW_FORM_strp 3166 - Attribute: DW_AT_language 3167 Form: DW_FORM_udata 3168 - Attribute: DW_AT_stmt_list 3169 Form: DW_FORM_sec_offset 3170 - Code: 0x2 3171 Tag: DW_TAG_subprogram 3172 Children: DW_CHILDREN_yes 3173 Attributes: 3174 - Attribute: DW_AT_name 3175 Form: DW_FORM_strp 3176 - Attribute: DW_AT_low_pc 3177 Form: DW_FORM_addr 3178 - Attribute: DW_AT_high_pc 3179 Form: DW_FORM_addr 3180 - Code: 0x3 3181 Tag: DW_TAG_inlined_subroutine 3182 Children: DW_CHILDREN_no 3183 Attributes: 3184 - Attribute: DW_AT_name 3185 Form: DW_FORM_strp 3186 - Attribute: DW_AT_low_pc 3187 Form: DW_FORM_addr 3188 - Attribute: DW_AT_high_pc 3189 Form: DW_FORM_addr 3190 - Attribute: DW_AT_call_file 3191 Form: DW_FORM_data4 3192 - Attribute: DW_AT_call_line 3193 Form: DW_FORM_data4 3194 debug_info: 3195 - Length: 0x45 3196 Version: 4 3197 AbbrevTableID: 0 3198 AbbrOffset: 0x0 3199 AddrSize: 8 3200 Entries: 3201 - AbbrCode: 0x1 3202 Values: 3203 - Value: 0x1 3204 - Value: 0x2 3205 - Value: 0x0 3206 - AbbrCode: 0x2 3207 Values: 3208 - Value: 0xF 3209 - Value: 0x1000 3210 - Value: 0x1050 3211 - AbbrCode: 0x3 3212 Values: 3213 - Value: 0x13 3214 - Value: 0x1100 3215 - Value: 0x1200 3216 - Value: 0x1 3217 - Value: 0xB 3218 - AbbrCode: 0x0 3219 - AbbrCode: 0x0 3220 debug_line: 3221 - Length: 76 3222 Version: 2 3223 PrologueLength: 36 3224 MinInstLength: 1 3225 DefaultIsStmt: 1 3226 LineBase: 251 3227 LineRange: 14 3228 OpcodeBase: 13 3229 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 3230 IncludeDirs: 3231 - '/tmp' 3232 Files: 3233 - Name: main.cpp 3234 DirIdx: 1 3235 ModTime: 0 3236 Length: 0 3237 Opcodes: 3238 - Opcode: DW_LNS_extended_op 3239 ExtLen: 9 3240 SubOpcode: DW_LNE_set_address 3241 Data: 4096 3242 - Opcode: DW_LNS_advance_line 3243 SData: 9 3244 Data: 0 3245 - Opcode: DW_LNS_copy 3246 Data: 0 3247 - Opcode: DW_LNS_advance_pc 3248 Data: 16 3249 - Opcode: DW_LNS_advance_line 3250 SData: 1 3251 Data: 0 3252 - Opcode: DW_LNS_copy 3253 Data: 0 3254 - Opcode: DW_LNS_advance_pc 3255 Data: 16 3256 - Opcode: DW_LNS_advance_line 3257 SData: 1 3258 Data: 0 3259 - Opcode: DW_LNS_copy 3260 Data: 0 3261 - Opcode: DW_LNS_advance_pc 3262 Data: 16 3263 - Opcode: DW_LNS_advance_line 3264 SData: 1 3265 Data: 0 3266 - Opcode: DW_LNS_copy 3267 Data: 0 3268 - Opcode: DW_LNS_advance_pc 3269 Data: 32 3270 - Opcode: DW_LNS_extended_op 3271 ExtLen: 1 3272 SubOpcode: DW_LNE_end_sequence 3273 Data: 0 3274 )"; 3275 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 3276 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 3277 std::unique_ptr<DWARFContext> DwarfContext = 3278 DWARFContext::create(*ErrOrSections, 8); 3279 ASSERT_TRUE(DwarfContext.get() != nullptr); 3280 std::string errors; 3281 raw_string_ostream OS(errors); 3282 OutputAggregator OSAgg(&OS); 3283 GsymCreator GC; 3284 DwarfTransformer DT(*DwarfContext, GC); 3285 const uint32_t ThreadCount = 1; 3286 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 3287 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 3288 SmallString<512> Str; 3289 raw_svector_ostream OutStrm(Str); 3290 const auto ByteOrder = llvm::endianness::native; 3291 FileWriter FW(OutStrm, ByteOrder); 3292 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 3293 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 3294 ASSERT_THAT_EXPECTED(GR, Succeeded()); 3295 // There should only be one function in our GSYM. 3296 EXPECT_EQ(GR->getNumAddresses(), 1u); 3297 auto ExpFI = GR->getFunctionInfo(0x1000); 3298 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 3299 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x1050)); 3300 EXPECT_TRUE(ExpFI->OptLineTable.has_value()); 3301 EXPECT_FALSE(ExpFI->Inline.has_value()); 3302 StringRef FuncName = GR->getString(ExpFI->Name); 3303 EXPECT_EQ(FuncName, "foo"); 3304 std::vector<std::string> ExpectedLogErrors = { 3305 "error: inlined function DIE at 0x0000002a has a range [0x0000000000001100" 3306 " - 0x0000000000001200) that isn't contained in any parent address ranges," 3307 " this inline range will be removed.", 3308 "warning: DIE contains inline function information that has no valid " 3309 "ranges, removing inline information:", 3310 }; 3311 // Make sure all expected errors are in the error stream for the two invalid 3312 // inlined functions that we removed due to invalid range scoping. 3313 for (const auto &Error: ExpectedLogErrors) { 3314 EXPECT_TRUE(OS.str().find(Error) != std::string::npos); 3315 } 3316 } 3317 3318 TEST(GSYMTest, TestFinalizeForLineTables) { 3319 // This example has two compile units: 3320 // - one contains a function "foo" with line table entries and "bar" without 3321 // - one contains a function "bar" with line table entries and "foo" without 3322 // This test ensures that no matter what order information gets processed, 3323 // we want to make sure that we prioritize the entries with the most debug 3324 // info. 3325 // 3326 // The DWARF is the same for the functions, but the first compile unit has 3327 // lines entries for "foo" and the second one doesn't. And the first compile 3328 // unit has no line entries for "bar", but the second one does. We expect the 3329 // resulting gsym file to have a "foo" and "bar" that both have line entries. 3330 // 3331 // 0x0000000b: DW_TAG_compile_unit 3332 // DW_AT_name ("/tmp/main.cpp") 3333 // DW_AT_language (DW_LANG_C) 3334 // DW_AT_stmt_list (0x00000000) 3335 // 3336 // 0x00000015: DW_TAG_subprogram 3337 // DW_AT_name ("foo") 3338 // DW_AT_low_pc (0x0000000000001000) 3339 // DW_AT_high_pc (0x0000000000001050) 3340 // 3341 // 0x0000002a: DW_TAG_subprogram 3342 // DW_AT_name ("bar") 3343 // DW_AT_low_pc (0x0000000000002000) 3344 // DW_AT_high_pc (0x0000000000002050) 3345 // 3346 // 0x0000003f: NULL 3347 // 0x00000040: Compile Unit: length = 0x0000003c, format = DWARF32, version = 0x0004, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x00000080) 3348 // 3349 // 0x0000004b: DW_TAG_compile_unit 3350 // DW_AT_name ("/tmp/main.cpp") 3351 // DW_AT_language (DW_LANG_C) 3352 // DW_AT_stmt_list (0x00000043) 3353 // 3354 // 0x00000055: DW_TAG_subprogram 3355 // DW_AT_name ("foo") 3356 // DW_AT_low_pc (0x0000000000001000) 3357 // DW_AT_high_pc (0x0000000000001050) 3358 // 3359 // 0x0000006a: DW_TAG_subprogram 3360 // DW_AT_name ("bar") 3361 // DW_AT_low_pc (0x0000000000002000) 3362 // DW_AT_high_pc (0x0000000000002050) 3363 // 3364 // 0x0000007f: NULL 3365 3366 StringRef yamldata = R"( 3367 debug_str: 3368 - '' 3369 - '/tmp/main.cpp' 3370 - foo 3371 - bar 3372 debug_abbrev: 3373 - ID: 0 3374 Table: 3375 - Code: 0x1 3376 Tag: DW_TAG_compile_unit 3377 Children: DW_CHILDREN_yes 3378 Attributes: 3379 - Attribute: DW_AT_name 3380 Form: DW_FORM_strp 3381 - Attribute: DW_AT_language 3382 Form: DW_FORM_udata 3383 - Attribute: DW_AT_stmt_list 3384 Form: DW_FORM_sec_offset 3385 - Code: 0x2 3386 Tag: DW_TAG_subprogram 3387 Children: DW_CHILDREN_no 3388 Attributes: 3389 - Attribute: DW_AT_name 3390 Form: DW_FORM_strp 3391 - Attribute: DW_AT_low_pc 3392 Form: DW_FORM_addr 3393 - Attribute: DW_AT_high_pc 3394 Form: DW_FORM_addr 3395 debug_info: 3396 - Length: 0x3C 3397 Version: 4 3398 AbbrevTableID: 0 3399 AbbrOffset: 0x0 3400 AddrSize: 8 3401 Entries: 3402 - AbbrCode: 0x1 3403 Values: 3404 - Value: 0x1 3405 - Value: 0x2 3406 - Value: 0x0 3407 - AbbrCode: 0x2 3408 Values: 3409 - Value: 0xF 3410 - Value: 0x1000 3411 - Value: 0x1050 3412 - AbbrCode: 0x2 3413 Values: 3414 - Value: 0x13 3415 - Value: 0x2000 3416 - Value: 0x2050 3417 - AbbrCode: 0x0 3418 - Length: 0x3C 3419 Version: 4 3420 AbbrevTableID: 0 3421 AbbrOffset: 0x0 3422 AddrSize: 8 3423 Entries: 3424 - AbbrCode: 0x1 3425 Values: 3426 - Value: 0x1 3427 - Value: 0x2 3428 - Value: 0x43 3429 - AbbrCode: 0x2 3430 Values: 3431 - Value: 0xF 3432 - Value: 0x1000 3433 - Value: 0x1050 3434 - AbbrCode: 0x2 3435 Values: 3436 - Value: 0x13 3437 - Value: 0x2000 3438 - Value: 0x2050 3439 - AbbrCode: 0x0 3440 debug_line: 3441 - Length: 63 3442 Version: 2 3443 PrologueLength: 36 3444 MinInstLength: 1 3445 DefaultIsStmt: 1 3446 LineBase: 251 3447 LineRange: 14 3448 OpcodeBase: 13 3449 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 3450 IncludeDirs: 3451 - '/tmp' 3452 Files: 3453 - Name: main.cpp 3454 DirIdx: 1 3455 ModTime: 0 3456 Length: 0 3457 Opcodes: 3458 - Opcode: DW_LNS_extended_op 3459 ExtLen: 9 3460 SubOpcode: DW_LNE_set_address 3461 Data: 4096 3462 - Opcode: DW_LNS_advance_line 3463 SData: 9 3464 Data: 0 3465 - Opcode: DW_LNS_copy 3466 Data: 0 3467 - Opcode: DW_LNS_advance_pc 3468 Data: 80 3469 - Opcode: DW_LNS_advance_line 3470 SData: 1 3471 Data: 0 3472 - Opcode: DW_LNS_extended_op 3473 ExtLen: 1 3474 SubOpcode: DW_LNE_end_sequence 3475 Data: 0 3476 - Length: 63 3477 Version: 2 3478 PrologueLength: 36 3479 MinInstLength: 1 3480 DefaultIsStmt: 1 3481 LineBase: 251 3482 LineRange: 14 3483 OpcodeBase: 13 3484 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 3485 IncludeDirs: 3486 - '/tmp' 3487 Files: 3488 - Name: main.cpp 3489 DirIdx: 1 3490 ModTime: 0 3491 Length: 0 3492 Opcodes: 3493 - Opcode: DW_LNS_extended_op 3494 ExtLen: 9 3495 SubOpcode: DW_LNE_set_address 3496 Data: 8192 3497 - Opcode: DW_LNS_advance_line 3498 SData: 19 3499 Data: 0 3500 - Opcode: DW_LNS_copy 3501 Data: 0 3502 - Opcode: DW_LNS_advance_pc 3503 Data: 80 3504 - Opcode: DW_LNS_advance_line 3505 SData: 1 3506 Data: 0 3507 - Opcode: DW_LNS_extended_op 3508 ExtLen: 1 3509 SubOpcode: DW_LNE_end_sequence 3510 Data: 0 3511 )"; 3512 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 3513 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 3514 std::unique_ptr<DWARFContext> DwarfContext = 3515 DWARFContext::create(*ErrOrSections, 8); 3516 ASSERT_TRUE(DwarfContext.get() != nullptr); 3517 std::string errors; 3518 raw_string_ostream OS(errors); 3519 OutputAggregator OSAgg(&OS); 3520 GsymCreator GC; 3521 DwarfTransformer DT(*DwarfContext, GC); 3522 const uint32_t ThreadCount = 1; 3523 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 3524 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 3525 SmallString<512> Str; 3526 raw_svector_ostream OutStrm(Str); 3527 const auto ByteOrder = llvm::endianness::native; 3528 FileWriter FW(OutStrm, ByteOrder); 3529 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 3530 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 3531 ASSERT_THAT_EXPECTED(GR, Succeeded()); 3532 // There should only be two functions in our GSYM. 3533 EXPECT_EQ(GR->getNumAddresses(), 2u); 3534 // Verify "foo" is present and has a line table 3535 auto ExpFI = GR->getFunctionInfo(0x1000); 3536 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 3537 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x1050)); 3538 EXPECT_TRUE(ExpFI->OptLineTable.has_value()); 3539 EXPECT_FALSE(ExpFI->Inline.has_value()); 3540 StringRef FuncName = GR->getString(ExpFI->Name); 3541 EXPECT_EQ(FuncName, "foo"); 3542 3543 // Verify "foo" is present and has a line table 3544 auto ExpFI2 = GR->getFunctionInfo(0x2000); 3545 ASSERT_THAT_EXPECTED(ExpFI2, Succeeded()); 3546 ASSERT_EQ(ExpFI2->Range, AddressRange(0x2000, 0x2050)); 3547 EXPECT_TRUE(ExpFI2->OptLineTable.has_value()); 3548 EXPECT_FALSE(ExpFI2->Inline.has_value()); 3549 StringRef FuncName2 = GR->getString(ExpFI2->Name); 3550 EXPECT_EQ(FuncName2, "bar"); 3551 } 3552 3553 3554 TEST(GSYMTest, TestRangeWarnings) { 3555 // This example has a single compile unit that has a DW_TAG_subprogram that 3556 // has two discontiguous ranges. We will create two FunctionInfo objects for 3557 // each range in the function that only contains info for each range. We also 3558 // want to verify that we only emit errors and warnings for ranges that 3559 // aren't contained in any parent address ranges if this is true. Prior to 3560 // this fix we would create two FunctionInfo objects and as each one was 3561 // being created we would end up warning about all of the ranges that weren't 3562 // in the current FunctionInfo's range even though the DWARF was well formed. 3563 // Now we don't incorrectly emit errors when there are none. 3564 // 3565 // 0x0000000b: DW_TAG_compile_unit 3566 // DW_AT_name ("/tmp/main.cpp") 3567 // DW_AT_language (DW_LANG_C) 3568 // DW_AT_stmt_list (0x00000000) 3569 // 3570 // 0x00000015: DW_TAG_subprogram 3571 // DW_AT_name ("foo") 3572 // DW_AT_ranges (0x00000000 3573 // [0x0000000000001000, 0x0000000000001050) 3574 // [0x0000000000002000, 0x0000000000002050)) 3575 // 3576 // 0x0000001e: DW_TAG_inlined_subroutine 3577 // DW_AT_name ("inline1") 3578 // DW_AT_ranges (0x00000030 3579 // [0x0000000000001010, 0x0000000000001040) 3580 // [0x0000000000002010, 0x0000000000002040)) 3581 // DW_AT_call_file ("/tmp/main.cpp") 3582 // DW_AT_call_line (11) 3583 // 3584 // 0x0000002f: DW_TAG_inlined_subroutine 3585 // DW_AT_name ("inline2") 3586 // DW_AT_ranges (0x00000060 3587 // [0x0000000000001015, 0x0000000000001020) 3588 // [0x0000000000002015, 0x0000000000002020)) 3589 // DW_AT_call_file ("/tmp/inline.h") 3590 // DW_AT_call_line (21) 3591 // 3592 // 0x00000040: NULL 3593 // 3594 // 0x00000041: NULL 3595 // 3596 // 0x00000042: NULL 3597 3598 StringRef yamldata = R"( 3599 debug_str: 3600 - '' 3601 - '/tmp/main.cpp' 3602 - foo 3603 - inline1 3604 - inline2 3605 debug_abbrev: 3606 - ID: 0 3607 Table: 3608 - Code: 0x1 3609 Tag: DW_TAG_compile_unit 3610 Children: DW_CHILDREN_yes 3611 Attributes: 3612 - Attribute: DW_AT_name 3613 Form: DW_FORM_strp 3614 - Attribute: DW_AT_language 3615 Form: DW_FORM_udata 3616 - Attribute: DW_AT_stmt_list 3617 Form: DW_FORM_sec_offset 3618 - Code: 0x2 3619 Tag: DW_TAG_subprogram 3620 Children: DW_CHILDREN_yes 3621 Attributes: 3622 - Attribute: DW_AT_name 3623 Form: DW_FORM_strp 3624 - Attribute: DW_AT_ranges 3625 Form: DW_FORM_sec_offset 3626 - Code: 0x3 3627 Tag: DW_TAG_inlined_subroutine 3628 Children: DW_CHILDREN_yes 3629 Attributes: 3630 - Attribute: DW_AT_name 3631 Form: DW_FORM_strp 3632 - Attribute: DW_AT_ranges 3633 Form: DW_FORM_sec_offset 3634 - Attribute: DW_AT_call_file 3635 Form: DW_FORM_data4 3636 - Attribute: DW_AT_call_line 3637 Form: DW_FORM_data4 3638 - Code: 0x4 3639 Tag: DW_TAG_inlined_subroutine 3640 Children: DW_CHILDREN_no 3641 Attributes: 3642 - Attribute: DW_AT_name 3643 Form: DW_FORM_strp 3644 - Attribute: DW_AT_ranges 3645 Form: DW_FORM_sec_offset 3646 - Attribute: DW_AT_call_file 3647 Form: DW_FORM_data4 3648 - Attribute: DW_AT_call_line 3649 Form: DW_FORM_data4 3650 debug_ranges: 3651 - Offset: 0x0 3652 AddrSize: 0x8 3653 Entries: 3654 - LowOffset: 0x1000 3655 HighOffset: 0x1050 3656 - LowOffset: 0x2000 3657 HighOffset: 0x2050 3658 - Offset: 0x30 3659 AddrSize: 0x8 3660 Entries: 3661 - LowOffset: 0x1010 3662 HighOffset: 0x1040 3663 - LowOffset: 0x2010 3664 HighOffset: 0x2040 3665 - Offset: 0x60 3666 AddrSize: 0x8 3667 Entries: 3668 - LowOffset: 0x1015 3669 HighOffset: 0x1020 3670 - LowOffset: 0x2015 3671 HighOffset: 0x2020 3672 debug_info: 3673 - Length: 0x3F 3674 Version: 4 3675 AbbrevTableID: 0 3676 AbbrOffset: 0x0 3677 AddrSize: 8 3678 Entries: 3679 - AbbrCode: 0x1 3680 Values: 3681 - Value: 0x1 3682 - Value: 0x2 3683 - Value: 0x0 3684 - AbbrCode: 0x2 3685 Values: 3686 - Value: 0xF 3687 - Value: 0x0 3688 - AbbrCode: 0x3 3689 Values: 3690 - Value: 0x13 3691 - Value: 0x30 3692 - Value: 0x1 3693 - Value: 0xB 3694 - AbbrCode: 0x4 3695 Values: 3696 - Value: 0x1B 3697 - Value: 0x60 3698 - Value: 0x2 3699 - Value: 0x15 3700 - AbbrCode: 0x0 3701 - AbbrCode: 0x0 3702 - AbbrCode: 0x0 3703 debug_line: 3704 - Length: 120 3705 Version: 2 3706 PrologueLength: 48 3707 MinInstLength: 1 3708 DefaultIsStmt: 1 3709 LineBase: 251 3710 LineRange: 14 3711 OpcodeBase: 13 3712 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 3713 IncludeDirs: 3714 - '/tmp' 3715 Files: 3716 - Name: main.cpp 3717 DirIdx: 1 3718 ModTime: 0 3719 Length: 0 3720 - Name: inline.h 3721 DirIdx: 1 3722 ModTime: 0 3723 Length: 0 3724 Opcodes: 3725 - Opcode: DW_LNS_extended_op 3726 ExtLen: 9 3727 SubOpcode: DW_LNE_set_address 3728 Data: 4096 3729 - Opcode: DW_LNS_advance_line 3730 SData: 9 3731 Data: 0 3732 - Opcode: DW_LNS_copy 3733 Data: 0 3734 - Opcode: DW_LNS_advance_pc 3735 Data: 16 3736 - Opcode: DW_LNS_set_file 3737 Data: 2 3738 - Opcode: DW_LNS_advance_line 3739 SData: 10 3740 Data: 0 3741 - Opcode: DW_LNS_copy 3742 Data: 0 3743 - Opcode: DW_LNS_advance_pc 3744 Data: 16 3745 - Opcode: DW_LNS_advance_line 3746 SData: 1 3747 Data: 0 3748 - Opcode: DW_LNS_copy 3749 Data: 0 3750 - Opcode: DW_LNS_advance_pc 3751 Data: 48 3752 - Opcode: DW_LNS_set_file 3753 Data: 1 3754 - Opcode: DW_LNS_advance_line 3755 SData: -10 3756 Data: 0 3757 - Opcode: DW_LNS_extended_op 3758 ExtLen: 1 3759 SubOpcode: DW_LNE_end_sequence 3760 Data: 0 3761 - Opcode: DW_LNS_extended_op 3762 ExtLen: 9 3763 SubOpcode: DW_LNE_set_address 3764 Data: 8192 3765 - Opcode: DW_LNS_advance_line 3766 SData: 19 3767 Data: 0 3768 - Opcode: DW_LNS_copy 3769 Data: 0 3770 - Opcode: DW_LNS_advance_pc 3771 Data: 16 3772 - Opcode: DW_LNS_set_file 3773 Data: 2 3774 - Opcode: DW_LNS_copy 3775 Data: 0 3776 - Opcode: DW_LNS_advance_pc 3777 Data: 16 3778 - Opcode: DW_LNS_advance_line 3779 SData: 1 3780 Data: 0 3781 - Opcode: DW_LNS_copy 3782 Data: 0 3783 - Opcode: DW_LNS_advance_pc 3784 Data: 48 3785 - Opcode: DW_LNS_set_file 3786 Data: 1 3787 - Opcode: DW_LNS_extended_op 3788 ExtLen: 1 3789 SubOpcode: DW_LNE_end_sequence 3790 Data: 0 3791 )"; 3792 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 3793 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 3794 std::unique_ptr<DWARFContext> DwarfContext = 3795 DWARFContext::create(*ErrOrSections, 8); 3796 ASSERT_TRUE(DwarfContext.get() != nullptr); 3797 std::string errors; 3798 raw_string_ostream OS(errors); 3799 OutputAggregator OSAgg(&OS); 3800 GsymCreator GC; 3801 DwarfTransformer DT(*DwarfContext, GC); 3802 const uint32_t ThreadCount = 1; 3803 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 3804 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 3805 SmallString<512> Str; 3806 raw_svector_ostream OutStrm(Str); 3807 const auto ByteOrder = llvm::endianness::native; 3808 FileWriter FW(OutStrm, ByteOrder); 3809 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 3810 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 3811 ASSERT_THAT_EXPECTED(GR, Succeeded()); 3812 // There should be two functions in our GSYM. 3813 EXPECT_EQ(GR->getNumAddresses(), 2u); 3814 // Verify "foo" is present and has a line table 3815 auto ExpFI = GR->getFunctionInfo(0x1000); 3816 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 3817 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x1050)); 3818 EXPECT_TRUE(ExpFI->OptLineTable.has_value()); 3819 EXPECT_TRUE(ExpFI->Inline.has_value()); 3820 StringRef FuncName = GR->getString(ExpFI->Name); 3821 EXPECT_EQ(FuncName, "foo"); 3822 3823 // Verify "foo" is present and has a line table 3824 auto ExpFI2 = GR->getFunctionInfo(0x2000); 3825 ASSERT_THAT_EXPECTED(ExpFI2, Succeeded()); 3826 ASSERT_EQ(ExpFI2->Range, AddressRange(0x2000, 0x2050)); 3827 EXPECT_TRUE(ExpFI2->OptLineTable.has_value()); 3828 EXPECT_TRUE(ExpFI2->Inline.has_value()); 3829 StringRef FuncName2 = GR->getString(ExpFI2->Name); 3830 EXPECT_EQ(FuncName2, "foo"); 3831 3832 // Make sure we don't see spurious errors in the output: 3833 EXPECT_TRUE(errors.find("error:") == std::string::npos); 3834 } 3835 3836 TEST(GSYMTest, TestEmptyRangeWarnings) { 3837 // This example has a single compile unit that has a DW_TAG_subprogram that 3838 // has a function that contains an inlined function that has an empty range. 3839 // We want to make sure that if we run into only empty inline functions 3840 // inside of a real function, that we don't end up with inline information 3841 // in the GSYM and we don't warn about the inline function's range not being 3842 // contined in the parent ranges since it is ok for inline functions to be 3843 // elided. 3844 // 3845 // 0x0000000b: DW_TAG_compile_unit 3846 // DW_AT_name ("/tmp/main.cpp") 3847 // DW_AT_language (DW_LANG_C) 3848 // DW_AT_stmt_list (0x00000000) 3849 // 3850 // 0x00000015: DW_TAG_subprogram 3851 // DW_AT_name ("foo") 3852 // DW_AT_low_pc (0x0000000000001000) 3853 // DW_AT_high_pc (0x0000000000001050) 3854 // 3855 // 0x0000002a: DW_TAG_inlined_subroutine 3856 // DW_AT_name ("inline1") 3857 // DW_AT_low_pc (0x0000000000001010) 3858 // DW_AT_high_pc (0x0000000000001010) 3859 // DW_AT_call_file ("/tmp/main.cpp") 3860 // DW_AT_call_line (11) 3861 // 3862 // 0x00000047: NULL 3863 // 3864 // 0x00000048: NULL 3865 3866 StringRef yamldata = R"( 3867 debug_str: 3868 - '' 3869 - '/tmp/main.cpp' 3870 - foo 3871 - inline1 3872 debug_abbrev: 3873 - ID: 0 3874 Table: 3875 - Code: 0x1 3876 Tag: DW_TAG_compile_unit 3877 Children: DW_CHILDREN_yes 3878 Attributes: 3879 - Attribute: DW_AT_name 3880 Form: DW_FORM_strp 3881 - Attribute: DW_AT_language 3882 Form: DW_FORM_udata 3883 - Attribute: DW_AT_stmt_list 3884 Form: DW_FORM_sec_offset 3885 - Code: 0x2 3886 Tag: DW_TAG_subprogram 3887 Children: DW_CHILDREN_yes 3888 Attributes: 3889 - Attribute: DW_AT_name 3890 Form: DW_FORM_strp 3891 - Attribute: DW_AT_low_pc 3892 Form: DW_FORM_addr 3893 - Attribute: DW_AT_high_pc 3894 Form: DW_FORM_addr 3895 - Code: 0x3 3896 Tag: DW_TAG_inlined_subroutine 3897 Children: DW_CHILDREN_no 3898 Attributes: 3899 - Attribute: DW_AT_name 3900 Form: DW_FORM_strp 3901 - Attribute: DW_AT_low_pc 3902 Form: DW_FORM_addr 3903 - Attribute: DW_AT_high_pc 3904 Form: DW_FORM_addr 3905 - Attribute: DW_AT_call_file 3906 Form: DW_FORM_data4 3907 - Attribute: DW_AT_call_line 3908 Form: DW_FORM_data4 3909 debug_info: 3910 - Length: 0x45 3911 Version: 4 3912 AbbrevTableID: 0 3913 AbbrOffset: 0x0 3914 AddrSize: 8 3915 Entries: 3916 - AbbrCode: 0x1 3917 Values: 3918 - Value: 0x1 3919 - Value: 0x2 3920 - Value: 0x0 3921 - AbbrCode: 0x2 3922 Values: 3923 - Value: 0xF 3924 - Value: 0x1000 3925 - Value: 0x1050 3926 - AbbrCode: 0x3 3927 Values: 3928 - Value: 0x13 3929 - Value: 0x1010 3930 - Value: 0x1010 3931 - Value: 0x1 3932 - Value: 0xB 3933 - AbbrCode: 0x0 3934 - AbbrCode: 0x0 3935 debug_line: 3936 - Length: 89 3937 Version: 2 3938 PrologueLength: 48 3939 MinInstLength: 1 3940 DefaultIsStmt: 1 3941 LineBase: 251 3942 LineRange: 14 3943 OpcodeBase: 13 3944 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 3945 IncludeDirs: 3946 - '/tmp' 3947 Files: 3948 - Name: main.cpp 3949 DirIdx: 1 3950 ModTime: 0 3951 Length: 0 3952 - Name: inline.h 3953 DirIdx: 1 3954 ModTime: 0 3955 Length: 0 3956 Opcodes: 3957 - Opcode: DW_LNS_extended_op 3958 ExtLen: 9 3959 SubOpcode: DW_LNE_set_address 3960 Data: 4096 3961 - Opcode: DW_LNS_advance_line 3962 SData: 9 3963 Data: 0 3964 - Opcode: DW_LNS_copy 3965 Data: 0 3966 - Opcode: DW_LNS_advance_pc 3967 Data: 16 3968 - Opcode: DW_LNS_set_file 3969 Data: 2 3970 - Opcode: DW_LNS_advance_line 3971 SData: 10 3972 Data: 0 3973 - Opcode: DW_LNS_copy 3974 Data: 0 3975 - Opcode: DW_LNS_advance_pc 3976 Data: 16 3977 - Opcode: DW_LNS_advance_line 3978 SData: 1 3979 Data: 0 3980 - Opcode: DW_LNS_copy 3981 Data: 0 3982 - Opcode: DW_LNS_advance_pc 3983 Data: 48 3984 - Opcode: DW_LNS_set_file 3985 Data: 1 3986 - Opcode: DW_LNS_advance_line 3987 SData: -10 3988 Data: 0 3989 - Opcode: DW_LNS_extended_op 3990 ExtLen: 1 3991 SubOpcode: DW_LNE_end_sequence 3992 Data: 0 3993 )"; 3994 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 3995 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 3996 std::unique_ptr<DWARFContext> DwarfContext = 3997 DWARFContext::create(*ErrOrSections, 8); 3998 ASSERT_TRUE(DwarfContext.get() != nullptr); 3999 std::string errors; 4000 raw_string_ostream OS(errors); 4001 OutputAggregator OSAgg(&OS); 4002 GsymCreator GC; 4003 DwarfTransformer DT(*DwarfContext, GC); 4004 const uint32_t ThreadCount = 1; 4005 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 4006 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 4007 SmallString<512> Str; 4008 raw_svector_ostream OutStrm(Str); 4009 const auto ByteOrder = llvm::endianness::native; 4010 FileWriter FW(OutStrm, ByteOrder); 4011 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 4012 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 4013 ASSERT_THAT_EXPECTED(GR, Succeeded()); 4014 // There should be one function in our GSYM. 4015 EXPECT_EQ(GR->getNumAddresses(), 1u); 4016 // Verify "foo" is present and has a line table and no inline info. 4017 auto ExpFI = GR->getFunctionInfo(0x1000); 4018 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 4019 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x1050)); 4020 EXPECT_TRUE(ExpFI->OptLineTable.has_value()); 4021 EXPECT_FALSE(ExpFI->Inline.has_value()); 4022 StringRef FuncName = GR->getString(ExpFI->Name); 4023 EXPECT_EQ(FuncName, "foo"); 4024 4025 // Make sure we don't see spurious errors in the output: 4026 EXPECT_TRUE(errors.find("error:") == std::string::npos); 4027 } 4028 4029 4030 TEST(GSYMTest, TestEmptyLinkageName) { 4031 // This example has a single compile unit that has a DW_TAG_subprogram that 4032 // has a function that has an empty linkage name and a valid normal name. 4033 // Previously this would cause an encoding error: 4034 // 4035 // DWARF conversion failed: attempted to encode invalid FunctionInfo object 4036 // 4037 // This was because we would get a valid but empty linkage name and we would 4038 // try to use this in the GSYM FunctionInfo and that would cause the error 4039 // as the name was empty. 4040 // 4041 // 0x0000000b: DW_TAG_compile_unit 4042 // DW_AT_name ("/tmp/main.cpp") 4043 // DW_AT_language (DW_LANG_C) 4044 // DW_AT_stmt_list (0x00000000) 4045 // 4046 // 0x00000015: DW_TAG_subprogram 4047 // DW_AT_name ("foo") 4048 // DW_AT_linkage_name ("") 4049 // DW_AT_low_pc (0x0000000000001000) 4050 // DW_AT_high_pc (0x0000000000001050) 4051 // 4052 // 0x0000002e: NULL 4053 4054 4055 StringRef yamldata = R"( 4056 debug_str: 4057 - '' 4058 - '/tmp/main.cpp' 4059 - foo 4060 - '' 4061 debug_abbrev: 4062 - ID: 0 4063 Table: 4064 - Code: 0x1 4065 Tag: DW_TAG_compile_unit 4066 Children: DW_CHILDREN_yes 4067 Attributes: 4068 - Attribute: DW_AT_name 4069 Form: DW_FORM_strp 4070 - Attribute: DW_AT_language 4071 Form: DW_FORM_udata 4072 - Attribute: DW_AT_stmt_list 4073 Form: DW_FORM_sec_offset 4074 - Code: 0x2 4075 Tag: DW_TAG_subprogram 4076 Children: DW_CHILDREN_no 4077 Attributes: 4078 - Attribute: DW_AT_name 4079 Form: DW_FORM_strp 4080 - Attribute: DW_AT_linkage_name 4081 Form: DW_FORM_strp 4082 - Attribute: DW_AT_low_pc 4083 Form: DW_FORM_addr 4084 - Attribute: DW_AT_high_pc 4085 Form: DW_FORM_addr 4086 debug_info: 4087 - Length: 0x2B 4088 Version: 4 4089 AbbrevTableID: 0 4090 AbbrOffset: 0x0 4091 AddrSize: 8 4092 Entries: 4093 - AbbrCode: 0x1 4094 Values: 4095 - Value: 0x1 4096 - Value: 0x2 4097 - Value: 0x0 4098 - AbbrCode: 0x2 4099 Values: 4100 - Value: 0xF 4101 - Value: 0x13 4102 - Value: 0x1000 4103 - Value: 0x1050 4104 - AbbrCode: 0x0 4105 debug_line: 4106 - Length: 68 4107 Version: 2 4108 PrologueLength: 36 4109 MinInstLength: 1 4110 DefaultIsStmt: 1 4111 LineBase: 251 4112 LineRange: 14 4113 OpcodeBase: 13 4114 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 4115 IncludeDirs: 4116 - '/tmp' 4117 Files: 4118 - Name: main.cpp 4119 DirIdx: 1 4120 ModTime: 0 4121 Length: 0 4122 Opcodes: 4123 - Opcode: DW_LNS_extended_op 4124 ExtLen: 9 4125 SubOpcode: DW_LNE_set_address 4126 Data: 4096 4127 - Opcode: DW_LNS_advance_line 4128 SData: 9 4129 Data: 0 4130 - Opcode: DW_LNS_copy 4131 Data: 0 4132 - Opcode: DW_LNS_advance_pc 4133 Data: 256 4134 - Opcode: DW_LNS_advance_line 4135 SData: 1 4136 Data: 0 4137 - Opcode: DW_LNS_copy 4138 Data: 0 4139 - Opcode: DW_LNS_advance_pc 4140 Data: 256 4141 - Opcode: DW_LNS_extended_op 4142 ExtLen: 1 4143 SubOpcode: DW_LNE_end_sequence 4144 Data: 0 4145 )"; 4146 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 4147 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 4148 std::unique_ptr<DWARFContext> DwarfContext = 4149 DWARFContext::create(*ErrOrSections, 8); 4150 ASSERT_TRUE(DwarfContext.get() != nullptr); 4151 std::string errors; 4152 raw_string_ostream OS(errors); 4153 OutputAggregator OSAgg(&OS); 4154 GsymCreator GC; 4155 DwarfTransformer DT(*DwarfContext, GC); 4156 const uint32_t ThreadCount = 1; 4157 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 4158 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 4159 SmallString<512> Str; 4160 raw_svector_ostream OutStrm(Str); 4161 const auto ByteOrder = llvm::endianness::native; 4162 FileWriter FW(OutStrm, ByteOrder); 4163 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 4164 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 4165 ASSERT_THAT_EXPECTED(GR, Succeeded()); 4166 // There should be one function in our GSYM. 4167 EXPECT_EQ(GR->getNumAddresses(), 1u); 4168 // Verify "foo" is present and has a line table and no inline info. 4169 auto ExpFI = GR->getFunctionInfo(0x1000); 4170 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 4171 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x1050)); 4172 EXPECT_TRUE(ExpFI->OptLineTable.has_value()); 4173 EXPECT_FALSE(ExpFI->Inline.has_value()); 4174 StringRef FuncName = GR->getString(ExpFI->Name); 4175 EXPECT_EQ(FuncName, "foo"); 4176 4177 // Make sure we don't see spurious errors in the output: 4178 EXPECT_TRUE(errors.find("error:") == std::string::npos); 4179 } 4180 4181 TEST(GSYMTest, TestLineTablesWithEmptyRanges) { 4182 // Test that lookups find the right line table entry when there are multiple 4183 // line entries with the same address. When we have multiple line table 4184 // entries with the same address, we need to pick the last one in the line 4185 // table. We do this because a line entry's start address in the defined by 4186 // the line table entry's address and the size is determined by the 4187 // subtracting the next line table's address. If the current line table 4188 // entry's address is the same as the next one, then there is no code 4189 // assiciated with the current line table entry and it should be ignored. 4190 // 4191 // 0x0000000b: DW_TAG_compile_unit 4192 // DW_AT_name ("/tmp/main.cpp") 4193 // DW_AT_language (DW_LANG_C) 4194 // DW_AT_stmt_list (0x00000000) 4195 // 4196 // 0x00000015: DW_TAG_subprogram 4197 // DW_AT_name ("foo") 4198 // DW_AT_low_pc (0x0000000000001000) 4199 // DW_AT_high_pc (0x0000000000001050) 4200 // 4201 // 0x0000002a: NULL 4202 // 4203 // The line table has a duplicate entry at 0x1010: 4204 // 4205 // Address Line Column File ISA Discriminator Flags 4206 // ---------- ------ ------ ------ --- ------------- ------------- 4207 // 0x00001000 10 0 1 0 0 is_stmt 4208 // 0x00001010 11 0 1 0 0 is_stmt 4209 // 0x00001010 12 0 1 0 0 is_stmt 4210 // 0x00001050 13 0 1 0 0 is_stmt end_sequence 4211 4212 StringRef yamldata = R"( 4213 debug_str: 4214 - '' 4215 - '/tmp/main.cpp' 4216 - foo 4217 debug_abbrev: 4218 - ID: 0 4219 Table: 4220 - Code: 0x1 4221 Tag: DW_TAG_compile_unit 4222 Children: DW_CHILDREN_yes 4223 Attributes: 4224 - Attribute: DW_AT_name 4225 Form: DW_FORM_strp 4226 - Attribute: DW_AT_language 4227 Form: DW_FORM_udata 4228 - Attribute: DW_AT_stmt_list 4229 Form: DW_FORM_sec_offset 4230 - Code: 0x2 4231 Tag: DW_TAG_subprogram 4232 Children: DW_CHILDREN_no 4233 Attributes: 4234 - Attribute: DW_AT_name 4235 Form: DW_FORM_strp 4236 - Attribute: DW_AT_low_pc 4237 Form: DW_FORM_addr 4238 - Attribute: DW_AT_high_pc 4239 Form: DW_FORM_addr 4240 debug_info: 4241 - Length: 0x27 4242 Version: 4 4243 AbbrevTableID: 0 4244 AbbrOffset: 0x0 4245 AddrSize: 8 4246 Entries: 4247 - AbbrCode: 0x1 4248 Values: 4249 - Value: 0x1 4250 - Value: 0x2 4251 - Value: 0x0 4252 - AbbrCode: 0x2 4253 Values: 4254 - Value: 0xF 4255 - Value: 0x1000 4256 - Value: 0x1050 4257 - AbbrCode: 0x0 4258 debug_line: 4259 - Length: 71 4260 Version: 2 4261 PrologueLength: 36 4262 MinInstLength: 1 4263 DefaultIsStmt: 1 4264 LineBase: 251 4265 LineRange: 14 4266 OpcodeBase: 13 4267 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 4268 IncludeDirs: 4269 - '/tmp' 4270 Files: 4271 - Name: main.cpp 4272 DirIdx: 1 4273 ModTime: 0 4274 Length: 0 4275 Opcodes: 4276 - Opcode: DW_LNS_extended_op 4277 ExtLen: 9 4278 SubOpcode: DW_LNE_set_address 4279 Data: 4096 4280 - Opcode: DW_LNS_advance_line 4281 SData: 9 4282 Data: 0 4283 - Opcode: DW_LNS_copy 4284 Data: 0 4285 - Opcode: DW_LNS_advance_pc 4286 Data: 16 4287 - Opcode: DW_LNS_advance_line 4288 SData: 1 4289 Data: 0 4290 - Opcode: DW_LNS_copy 4291 Data: 0 4292 - Opcode: DW_LNS_advance_line 4293 SData: 1 4294 Data: 0 4295 - Opcode: DW_LNS_copy 4296 Data: 0 4297 - Opcode: DW_LNS_advance_pc 4298 Data: 64 4299 - Opcode: DW_LNS_advance_line 4300 SData: 1 4301 Data: 0 4302 - Opcode: DW_LNS_extended_op 4303 ExtLen: 1 4304 SubOpcode: DW_LNE_end_sequence 4305 Data: 0 4306 )"; 4307 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 4308 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 4309 std::unique_ptr<DWARFContext> DwarfContext = 4310 DWARFContext::create(*ErrOrSections, 8); 4311 ASSERT_TRUE(DwarfContext.get() != nullptr); 4312 std::string errors; 4313 raw_string_ostream OS(errors); 4314 OutputAggregator OSAgg(&OS); 4315 GsymCreator GC; 4316 DwarfTransformer DT(*DwarfContext, GC); 4317 const uint32_t ThreadCount = 1; 4318 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 4319 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 4320 SmallString<512> Str; 4321 raw_svector_ostream OutStrm(Str); 4322 const auto ByteOrder = llvm::endianness::native; 4323 FileWriter FW(OutStrm, ByteOrder); 4324 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 4325 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 4326 ASSERT_THAT_EXPECTED(GR, Succeeded()); 4327 // There should be one function in our GSYM. 4328 EXPECT_EQ(GR->getNumAddresses(), 1u); 4329 // Verify "foo" is present and has a line table and no inline info. 4330 auto ExpFI = GR->getFunctionInfo(0x1000); 4331 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 4332 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x1050)); 4333 EXPECT_TRUE(ExpFI->OptLineTable.has_value()); 4334 EXPECT_FALSE(ExpFI->Inline.has_value()); 4335 StringRef FuncName = GR->getString(ExpFI->Name); 4336 EXPECT_EQ(FuncName, "foo"); 4337 4338 // Make sure we don't see spurious errors in the output: 4339 EXPECT_TRUE(errors.find("error:") == std::string::npos); 4340 4341 // Make sure that when we lookup address 0x1010, that we get the entry that 4342 // matches line 12, the second line entry that also has the address of 4343 // 0x1010. 4344 auto LR = GR->lookup(0x1010); 4345 ASSERT_THAT_EXPECTED(LR, Succeeded()); 4346 SourceLocation src_loc = {"foo", "/tmp", "main.cpp", 12, 16}; 4347 EXPECT_THAT(LR->Locations, testing::ElementsAre(src_loc)); 4348 } 4349 4350 TEST(GSYMTest, TestHandlingOfInvalidFileIndexes) { 4351 // Test that llvm-gsymutil can handle invalid file indexes in the following 4352 // cases: 4353 // - In line entries in the line table 4354 // - When parsing inline entries that have a DW_AT_call_file 4355 // - When parsing function dies with no line table entries and it tries to 4356 // use the DW_AT_decl_file 4357 // 4358 // 4359 // 0x0000000b: DW_TAG_compile_unit 4360 // DW_AT_name ("/tmp/main.cpp") 4361 // DW_AT_language (DW_LANG_C) 4362 // DW_AT_stmt_list (0x00000000) 4363 // 4364 // 0x00000015: DW_TAG_subprogram 4365 // DW_AT_name ("foo") 4366 // DW_AT_low_pc (0x0000000000001000) 4367 // DW_AT_high_pc (0x0000000000001050) 4368 // 4369 // 0x0000002a: DW_TAG_inlined_subroutine 4370 // DW_AT_name ("inline_with_invalid_call_file") 4371 // DW_AT_low_pc (0x0000000000001010) 4372 // DW_AT_high_pc (0x0000000000001020) 4373 // DW_AT_call_file (0x0000000a) 4374 // DW_AT_call_line (11) 4375 // 4376 // 0x00000047: DW_TAG_inlined_subroutine 4377 // DW_AT_name 4378 // ("inline_inside_parent_with_invalid_call_file") 4379 // DW_AT_low_pc (0x0000000000001010) 4380 // DW_AT_high_pc (0x0000000000001015) 4381 // DW_AT_call_file ("/tmp/main.cpp") 4382 // DW_AT_call_line (12) 4383 // 4384 // 0x00000064: NULL 4385 // 4386 // 0x00000065: DW_TAG_inlined_subroutine 4387 // DW_AT_name ("inline_with_valid_call_file") 4388 // DW_AT_low_pc (0x0000000000001020) 4389 // DW_AT_high_pc (0x0000000000001030) 4390 // DW_AT_call_file ("/tmp/main.cpp") 4391 // DW_AT_call_line (13) 4392 // 4393 // 0x00000082: DW_TAG_inlined_subroutine 4394 // DW_AT_name 4395 // ("inline_inside_parent_with_valid_call_file") 4396 // DW_AT_low_pc (0x0000000000001020) 4397 // DW_AT_high_pc (0x0000000000001025) 4398 // DW_AT_call_file ("/tmp/main.cpp") 4399 // DW_AT_call_line (14) 4400 // 4401 // 0x0000009f: NULL 4402 // 4403 // 0x000000a0: NULL 4404 // 4405 // 0x000000a1: DW_TAG_subprogram 4406 // DW_AT_name ("func_with_valid_decl_file") 4407 // DW_AT_decl_file ("/tmp/main.cpp") 4408 // DW_AT_decl_line (20) 4409 // DW_AT_low_pc (0x0000000000002000) 4410 // DW_AT_high_pc (0x0000000000002050) 4411 // 4412 // 0x000000b8: DW_TAG_subprogram 4413 // DW_AT_name ("func_with_invalid_decl_file") 4414 // DW_AT_decl_file (0x0a) 4415 // DW_AT_decl_line (20) 4416 // DW_AT_low_pc (0x0000000000003000) 4417 // DW_AT_high_pc (0x0000000000003050) 4418 // 4419 // 0x000000cf: NULL 4420 // 4421 // The table looks has an entry at address 0x0000000000001010 that has an 4422 // invalid file index that needs to be removed. 4423 // 4424 // Address Line Column File ISA Discriminator Flags 4425 // ---------- ------ ------ ------ --- ------------- ------------- 4426 // 0x00001000 10 0 1 0 0 is_stmt 4427 // 0x00001010 11 0 10 0 0 is_stmt 4428 // 0x00001020 11 0 1 0 0 is_stmt 4429 // 0x00001030 12 0 1 0 0 is_stmt 4430 // 0x00001050 12 0 1 0 0 is_stmt end_sequence 4431 4432 StringRef yamldata = R"( 4433 debug_str: 4434 - '' 4435 - '/tmp/main.cpp' 4436 - foo 4437 - inline_with_invalid_call_file 4438 - inline_inside_parent_with_invalid_call_file 4439 - inline_with_valid_call_file 4440 - inline_inside_parent_with_valid_call_file 4441 - func_with_valid_decl_file 4442 - func_with_invalid_decl_file 4443 debug_abbrev: 4444 - ID: 0 4445 Table: 4446 - Code: 0x1 4447 Tag: DW_TAG_compile_unit 4448 Children: DW_CHILDREN_yes 4449 Attributes: 4450 - Attribute: DW_AT_name 4451 Form: DW_FORM_strp 4452 - Attribute: DW_AT_language 4453 Form: DW_FORM_udata 4454 - Attribute: DW_AT_stmt_list 4455 Form: DW_FORM_sec_offset 4456 - Code: 0x2 4457 Tag: DW_TAG_subprogram 4458 Children: DW_CHILDREN_yes 4459 Attributes: 4460 - Attribute: DW_AT_name 4461 Form: DW_FORM_strp 4462 - Attribute: DW_AT_low_pc 4463 Form: DW_FORM_addr 4464 - Attribute: DW_AT_high_pc 4465 Form: DW_FORM_addr 4466 - Code: 0x3 4467 Tag: DW_TAG_inlined_subroutine 4468 Children: DW_CHILDREN_yes 4469 Attributes: 4470 - Attribute: DW_AT_name 4471 Form: DW_FORM_strp 4472 - Attribute: DW_AT_low_pc 4473 Form: DW_FORM_addr 4474 - Attribute: DW_AT_high_pc 4475 Form: DW_FORM_addr 4476 - Attribute: DW_AT_call_file 4477 Form: DW_FORM_data4 4478 - Attribute: DW_AT_call_line 4479 Form: DW_FORM_data4 4480 - Code: 0x4 4481 Tag: DW_TAG_inlined_subroutine 4482 Children: DW_CHILDREN_no 4483 Attributes: 4484 - Attribute: DW_AT_name 4485 Form: DW_FORM_strp 4486 - Attribute: DW_AT_low_pc 4487 Form: DW_FORM_addr 4488 - Attribute: DW_AT_high_pc 4489 Form: DW_FORM_addr 4490 - Attribute: DW_AT_call_file 4491 Form: DW_FORM_data4 4492 - Attribute: DW_AT_call_line 4493 Form: DW_FORM_data4 4494 - Code: 0x5 4495 Tag: DW_TAG_subprogram 4496 Children: DW_CHILDREN_no 4497 Attributes: 4498 - Attribute: DW_AT_name 4499 Form: DW_FORM_strp 4500 - Attribute: DW_AT_decl_file 4501 Form: DW_FORM_data1 4502 - Attribute: DW_AT_decl_line 4503 Form: DW_FORM_data1 4504 - Attribute: DW_AT_low_pc 4505 Form: DW_FORM_addr 4506 - Attribute: DW_AT_high_pc 4507 Form: DW_FORM_addr 4508 debug_info: 4509 - Length: 0xCC 4510 Version: 4 4511 AbbrevTableID: 0 4512 AbbrOffset: 0x0 4513 AddrSize: 8 4514 Entries: 4515 - AbbrCode: 0x1 4516 Values: 4517 - Value: 0x1 4518 - Value: 0x2 4519 - Value: 0x0 4520 - AbbrCode: 0x2 4521 Values: 4522 - Value: 0xF 4523 - Value: 0x1000 4524 - Value: 0x1050 4525 - AbbrCode: 0x3 4526 Values: 4527 - Value: 0x13 4528 - Value: 0x1010 4529 - Value: 0x1020 4530 - Value: 0xA 4531 - Value: 0xB 4532 - AbbrCode: 0x4 4533 Values: 4534 - Value: 0x31 4535 - Value: 0x1010 4536 - Value: 0x1015 4537 - Value: 0x1 4538 - Value: 0xC 4539 - AbbrCode: 0x0 4540 - AbbrCode: 0x3 4541 Values: 4542 - Value: 0x5D 4543 - Value: 0x1020 4544 - Value: 0x1030 4545 - Value: 0x1 4546 - Value: 0xD 4547 - AbbrCode: 0x4 4548 Values: 4549 - Value: 0x79 4550 - Value: 0x1020 4551 - Value: 0x1025 4552 - Value: 0x1 4553 - Value: 0xE 4554 - AbbrCode: 0x0 4555 - AbbrCode: 0x0 4556 - AbbrCode: 0x5 4557 Values: 4558 - Value: 0xA3 4559 - Value: 0x1 4560 - Value: 0x14 4561 - Value: 0x2000 4562 - Value: 0x2050 4563 - AbbrCode: 0x5 4564 Values: 4565 - Value: 0xBD 4566 - Value: 0xA 4567 - Value: 0x14 4568 - Value: 0x3000 4569 - Value: 0x3050 4570 - AbbrCode: 0x0 4571 debug_line: 4572 - Length: 78 4573 Version: 2 4574 PrologueLength: 36 4575 MinInstLength: 1 4576 DefaultIsStmt: 1 4577 LineBase: 251 4578 LineRange: 14 4579 OpcodeBase: 13 4580 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 4581 IncludeDirs: 4582 - '/tmp' 4583 Files: 4584 - Name: main.cpp 4585 DirIdx: 1 4586 ModTime: 0 4587 Length: 0 4588 Opcodes: 4589 - Opcode: DW_LNS_extended_op 4590 ExtLen: 9 4591 SubOpcode: DW_LNE_set_address 4592 Data: 4096 4593 - Opcode: DW_LNS_advance_line 4594 SData: 9 4595 Data: 0 4596 - Opcode: DW_LNS_copy 4597 Data: 0 4598 - Opcode: DW_LNS_advance_pc 4599 Data: 16 4600 - Opcode: DW_LNS_set_file 4601 Data: 10 4602 - Opcode: DW_LNS_advance_line 4603 SData: 1 4604 Data: 0 4605 - Opcode: DW_LNS_copy 4606 Data: 0 4607 - Opcode: DW_LNS_advance_pc 4608 Data: 16 4609 - Opcode: DW_LNS_set_file 4610 Data: 1 4611 - Opcode: DW_LNS_copy 4612 Data: 0 4613 - Opcode: DW_LNS_advance_pc 4614 Data: 16 4615 - Opcode: DW_LNS_advance_line 4616 SData: 1 4617 Data: 0 4618 - Opcode: DW_LNS_copy 4619 Data: 0 4620 - Opcode: DW_LNS_advance_pc 4621 Data: 32 4622 - Opcode: DW_LNS_extended_op 4623 ExtLen: 1 4624 SubOpcode: DW_LNE_end_sequence 4625 Data: 0 4626 )"; 4627 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 4628 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 4629 std::unique_ptr<DWARFContext> DwarfContext = 4630 DWARFContext::create(*ErrOrSections, 8); 4631 ASSERT_TRUE(DwarfContext.get() != nullptr); 4632 std::string errors; 4633 raw_string_ostream OS(errors); 4634 OutputAggregator OSAgg(&OS); 4635 GsymCreator GC; 4636 DwarfTransformer DT(*DwarfContext, GC); 4637 const uint32_t ThreadCount = 1; 4638 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 4639 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 4640 SmallString<512> Str; 4641 raw_svector_ostream OutStrm(Str); 4642 const auto ByteOrder = llvm::endianness::native; 4643 FileWriter FW(OutStrm, ByteOrder); 4644 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 4645 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 4646 ASSERT_THAT_EXPECTED(GR, Succeeded()); 4647 // There should be one function in our GSYM. 4648 EXPECT_EQ(GR->getNumAddresses(), 3u); 4649 // Verify "foo" is present and has a line table and no inline info. 4650 auto ExpFI = GR->getFunctionInfo(0x1000); 4651 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 4652 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x1050)); 4653 StringRef FuncName = GR->getString(ExpFI->Name); 4654 EXPECT_EQ(FuncName, "foo"); 4655 4656 EXPECT_TRUE(ExpFI->OptLineTable.has_value()); 4657 // Make sure we only have 3 entries to show we removed the line entry with 4658 // the invalid file index whose address is 0x0000000000001010. 4659 ASSERT_EQ(ExpFI->OptLineTable->size(), 3u); 4660 EXPECT_TRUE(ExpFI->Inline.has_value()); 4661 4662 // Make sure that we only have one inline function, not two. We remove one of 4663 // the inline functions because it has an invalid DW_AT_call_file attribute. 4664 ASSERT_EQ(ExpFI->Inline->Children.size(), 1u); 4665 StringRef InlineName = GR->getString(ExpFI->Inline->Children[0].Name); 4666 EXPECT_EQ(InlineName, "inline_with_valid_call_file"); 4667 4668 ExpFI = GR->getFunctionInfo(0x0000000000002000); 4669 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 4670 ASSERT_EQ(ExpFI->Range, AddressRange(0x2000, 0x2050)); 4671 FuncName = GR->getString(ExpFI->Name); 4672 EXPECT_EQ(FuncName, "func_with_valid_decl_file"); 4673 EXPECT_FALSE(ExpFI->Inline.has_value()); 4674 // Make sure we only have 1 entry in the line table which indicates we were 4675 // able to parse the DW_AT_decl_file/DW_AT_decl_line correctly. 4676 EXPECT_TRUE(ExpFI->OptLineTable.has_value()); 4677 ASSERT_EQ(ExpFI->OptLineTable->size(), 1u); 4678 4679 ExpFI = GR->getFunctionInfo(0x0000000000003000); 4680 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 4681 ASSERT_EQ(ExpFI->Range, AddressRange(0x3000, 0x3050)); 4682 FuncName = GR->getString(ExpFI->Name); 4683 EXPECT_EQ(FuncName, "func_with_invalid_decl_file"); 4684 EXPECT_FALSE(ExpFI->Inline.has_value()); 4685 // Make sure we only no line table because there are no line entries in the 4686 // line table and the DW_AT_decl_file attribute was invalid so we were not 4687 // able to parse the DW_AT_decl_file/DW_AT_decl_line correctly. 4688 EXPECT_FALSE(ExpFI->OptLineTable.has_value()); 4689 4690 // Make sure we don't see spurious errors in the output: 4691 std::vector<std::string> ExpectedLogErrors = { 4692 "error: function DIE at 0x00000015 has a line entry with invalid DWARF " 4693 "file index, this entry will be removed:", 4694 "error: inlined function DIE at 0x0000002a has an invalid file index 10 " 4695 "in its DW_AT_call_file attribute, this inline entry and all children " 4696 "will be removed.", 4697 "error: function DIE at 0x000000b8 has an invalid file index 10 in its " 4698 "DW_AT_decl_file attribute, unable to create a single line entry from " 4699 "the DW_AT_decl_file/DW_AT_decl_line attributes."}; 4700 // Make sure all expected errors are in the error stream for the two invalid 4701 // inlined functions that we removed due to invalid range scoping. 4702 for (const auto &Error : ExpectedLogErrors) 4703 EXPECT_TRUE(errors.find(Error) != std::string::npos); 4704 } 4705 4706 TEST(GSYMTest, TestLookupsOfOverlappingAndUnequalRanges) { 4707 // Test that llvm-gsymutil lookup the correct funtion info when address 4708 // ranges overlap. When functions overlap we always want to pick the first 4709 // function info when symbolicating if there are multiple entries with the 4710 // same address. Previous to this fix we would just binary search the address 4711 // table and pick the first function info that matched the address. After 4712 // this fix we now always select the first matching entry whose address range 4713 // contains the lookup address to ensure we have the most debug info. We have 4714 // seen case where the debug info would contain a small range and a symbol 4715 // would have the same start address but the range was larger and sometimes, 4716 // depending on how the binary search of the address table happened, we would 4717 // pick these latter entries. We want the first entries because they always 4718 // have the most debug info. 4719 // 4720 // To repro this case, we just make some simple DWARF that has two 4721 // overlapping ranges and ensure that any lookups between 0x1000 and 0x104f 4722 // match "foo", and any ranges between 0x1050 and 0x1fff match "bar". 4723 // 4724 // 0x0000000b: DW_TAG_compile_unit 4725 // DW_AT_name ("/tmp/main.cpp") 4726 // DW_AT_language (DW_LANG_C) 4727 // DW_AT_stmt_list (0x00000000) 4728 // 4729 // 0x00000015: DW_TAG_subprogram 4730 // DW_AT_name ("foo") 4731 // DW_AT_low_pc (0x0000000000001000) 4732 // DW_AT_high_pc (0x0000000000001050) 4733 // 4734 // 0x0000002a: DW_TAG_subprogram 4735 // DW_AT_name ("bar") 4736 // DW_AT_low_pc (0x0000000000001000) 4737 // DW_AT_high_pc (0x0000000000001100) 4738 // 4739 // 0x0000003f: NULL 4740 4741 StringRef yamldata = R"( 4742 debug_str: 4743 - '' 4744 - '/tmp/main.cpp' 4745 - foo 4746 - bar 4747 debug_abbrev: 4748 - ID: 0 4749 Table: 4750 - Code: 0x1 4751 Tag: DW_TAG_compile_unit 4752 Children: DW_CHILDREN_yes 4753 Attributes: 4754 - Attribute: DW_AT_name 4755 Form: DW_FORM_strp 4756 - Attribute: DW_AT_language 4757 Form: DW_FORM_udata 4758 - Attribute: DW_AT_stmt_list 4759 Form: DW_FORM_sec_offset 4760 - Code: 0x2 4761 Tag: DW_TAG_subprogram 4762 Children: DW_CHILDREN_no 4763 Attributes: 4764 - Attribute: DW_AT_name 4765 Form: DW_FORM_strp 4766 - Attribute: DW_AT_low_pc 4767 Form: DW_FORM_addr 4768 - Attribute: DW_AT_high_pc 4769 Form: DW_FORM_addr 4770 debug_info: 4771 - Length: 0x3C 4772 Version: 4 4773 AbbrevTableID: 0 4774 AbbrOffset: 0x0 4775 AddrSize: 8 4776 Entries: 4777 - AbbrCode: 0x1 4778 Values: 4779 - Value: 0x1 4780 - Value: 0x2 4781 - Value: 0x0 4782 - AbbrCode: 0x2 4783 Values: 4784 - Value: 0xF 4785 - Value: 0x1000 4786 - Value: 0x1050 4787 - AbbrCode: 0x2 4788 Values: 4789 - Value: 0x13 4790 - Value: 0x1000 4791 - Value: 0x1100 4792 - AbbrCode: 0x0 4793 debug_line: 4794 - Length: 71 4795 Version: 2 4796 PrologueLength: 36 4797 MinInstLength: 1 4798 DefaultIsStmt: 1 4799 LineBase: 251 4800 LineRange: 14 4801 OpcodeBase: 13 4802 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] 4803 IncludeDirs: 4804 - '/tmp' 4805 Files: 4806 - Name: main.cpp 4807 DirIdx: 1 4808 ModTime: 0 4809 Length: 0 4810 Opcodes: 4811 - Opcode: DW_LNS_extended_op 4812 ExtLen: 9 4813 SubOpcode: DW_LNE_set_address 4814 Data: 4096 4815 - Opcode: DW_LNS_advance_line 4816 SData: 9 4817 Data: 0 4818 - Opcode: DW_LNS_copy 4819 Data: 0 4820 - Opcode: DW_LNS_advance_pc 4821 Data: 16 4822 - Opcode: DW_LNS_advance_line 4823 SData: 1 4824 Data: 0 4825 - Opcode: DW_LNS_copy 4826 Data: 0 4827 - Opcode: DW_LNS_advance_line 4828 SData: 1 4829 Data: 0 4830 - Opcode: DW_LNS_copy 4831 Data: 0 4832 - Opcode: DW_LNS_advance_pc 4833 Data: 64 4834 - Opcode: DW_LNS_advance_line 4835 SData: 1 4836 Data: 0 4837 - Opcode: DW_LNS_extended_op 4838 ExtLen: 1 4839 SubOpcode: DW_LNE_end_sequence 4840 Data: 0 4841 )"; 4842 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); 4843 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); 4844 std::unique_ptr<DWARFContext> DwarfContext = 4845 DWARFContext::create(*ErrOrSections, 8); 4846 ASSERT_TRUE(DwarfContext.get() != nullptr); 4847 std::string errors; 4848 raw_string_ostream OS(errors); 4849 OutputAggregator OSAgg(&OS); 4850 GsymCreator GC; 4851 DwarfTransformer DT(*DwarfContext, GC); 4852 const uint32_t ThreadCount = 1; 4853 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); 4854 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); 4855 SmallString<512> Str; 4856 raw_svector_ostream OutStrm(Str); 4857 const auto ByteOrder = llvm::endianness::native; 4858 FileWriter FW(OutStrm, ByteOrder); 4859 ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); 4860 Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str()); 4861 ASSERT_THAT_EXPECTED(GR, Succeeded()); 4862 // There should be two functions in our GSYM. 4863 EXPECT_EQ(GR->getNumAddresses(), 2u); 4864 // Verify "foo" is correctly looked up for each of its addresses. 4865 for (uint64_t Addr = 0x1000; Addr < 0x1050; ++Addr) { 4866 auto ExpFI = GR->getFunctionInfo(Addr); 4867 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 4868 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x1050)); 4869 StringRef FuncName = GR->getString(ExpFI->Name); 4870 EXPECT_EQ(FuncName, "foo"); 4871 } 4872 4873 // Verify "bar" is correctly looked up for each of its addresses. 4874 for (uint64_t Addr = 0x1050; Addr < 0x1100; ++Addr) { 4875 auto ExpFI = GR->getFunctionInfo(Addr); 4876 ASSERT_THAT_EXPECTED(ExpFI, Succeeded()); 4877 ASSERT_EQ(ExpFI->Range, AddressRange(0x1000, 0x1100)); 4878 StringRef FuncName = GR->getString(ExpFI->Name); 4879 EXPECT_EQ(FuncName, "bar"); 4880 } 4881 4882 // Prior to the fix for this issue when we dumped an entire GSYM file, we 4883 // were using a function that would extract a FunctionInfo object for a 4884 // given address which caused us to always dump the first FunctionInfo 4885 // entry for a given address. We now dump it correctly using an address 4886 // index. Below we verify that we dump the right FunctionInfo gets dumped. 4887 4888 SmallString<512> DumpStr; 4889 raw_svector_ostream DumpStrm(DumpStr); 4890 GR->dump(DumpStrm); 4891 4892 // Make sure we see both "foo" and "bar" in the output of an entire GSYM 4893 // dump. Prior to this fix we would two "foo" entries. 4894 std::vector<std::string> ExpectedDumpLines = { 4895 "@ 0x00000068: [0x0000000000001000 - 0x0000000000001050) \"foo\"", 4896 "@ 0x00000088: [0x0000000000001000 - 0x0000000000001100) \"bar\""}; 4897 // Make sure all expected errors are in the error stream for the two invalid 4898 // inlined functions that we removed due to invalid range scoping. 4899 for (const auto &Line : ExpectedDumpLines) 4900 EXPECT_TRUE(DumpStr.find(Line) != std::string::npos); 4901 } 4902