5088 lines · cpp
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-exception6//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 31using namespace llvm;32using namespace gsym;33 34void 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 StringRef41 // properly.42 EXPECT_EQ(Actual.message(), ExpectedMsgs[WhichMsg++]);43 });44 EXPECT_EQ(WhichMsg, ExpectedMsgs.size());45 EXPECT_FALSE(Remaining);46}47 48void checkError(std::string ExpectedMsg, Error Err) {49 checkError(ArrayRef<std::string>{ExpectedMsg}, std::move(Err));50}51TEST(GSYMTest, TestFileEntry) {52 // Make sure default constructed GSYM FileEntry has zeroes in the53 // 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 works59 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 84TEST(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 == operator112 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 FunctionInfo132 // structs from a variety of sources: symtab, debug info, runtime info133 // and we sort them and want the sorting to allow us to quickly get the134 // 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 one140 // that has name, size and any number of line table entries141 EXPECT_LT(FISymtab, FIWithLines);142 143 // Test that if we have a function info without inline info and one with144 // 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 more152 // inline entries that the one with fewer inline functins is less than the153 // 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 than163 // the same one with valid inline info164 EXPECT_LT(FIWithLines, FIWithLinesAndInline);165 166 // Test if we have an entry with lines and one with more lines for the same167 // 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 entries173 // in the FunctionInfo.OptLineTable.Lines vector.174 FunctionInfo FIWithLinesWithHigherAddress = FIWithLines;175 FIWithLinesWithHigherAddress.OptLineTable->get(0).Addr += 0x10;176 EXPECT_LT(FIWithLines, FIWithLinesWithHigherAddress);177}178 179static 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 192TEST(GSYMTest, TestFunctionInfoDecodeErrors) {193 // Test decoding FunctionInfo objects that ensure we report an appropriate194 // 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 value218 FW.writeU32(0); // LineTableInfo InfoType data length.219 TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,220 "0x00000008: unsupported InfoType 7");221}222 223static 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 234TEST(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 anything246 // 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 anything253 // 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 259static 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 280static 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 291static 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 302TEST(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 table308 // 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 table314 // 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 table321 // 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 table328 // 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 336static void TestInlineInfoEncodeDecode(llvm::endianness ByteOrder,337 const InlineInfo &Inline) {338 // Test encoding and decoding InlineInfo objects339 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 355static 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 367static 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 379TEST(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 since385 // top level InlineInfo objects have ranges with no name, call file386 // or call line387 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. The393 // indentation of the address range indicates the parent child394 // relationships of the InlineInfo objects:395 //396 // Variable Range and values397 // =========== ====================================================398 // Root [0x100-0x200) (no name, file, or line)399 // Inline1 [0x150-0x160) Name = 1, File = 1, Line = 11400 // Inline1Sub1 [0x152-0x155) Name = 2, File = 2, Line = 22401 // Inline1Sub2 [0x157-0x158) Name = 3, File = 3, Line = 33402 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 match424 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 in431 // [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 in436 // [[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 in447 // [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 in460 // [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 objects473 TestInlineInfoEncodeDecode(llvm::endianness::little, Root);474 TestInlineInfoEncodeDecode(llvm::endianness::big, Root);475}476 477TEST(GSYMTest, TestInlineInfoEncodeErrors) {478 // Test InlineInfo encoding errors.479 480 // Test that we get an error when trying to encode an InlineInfo object481 // 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 has488 // 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 has496 // 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 509TEST(GSYMTest, TestInlineInfoDecodeErrors) {510 // Test decoding InlineInfo objects that ensure we report an appropriate511 // 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 535TEST(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 operators548 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 561TEST(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 574static 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 619TEST(GSYMTest, TestFileWriter) {620 TestFileWriterHelper(llvm::endianness::little);621 TestFileWriterHelper(llvm::endianness::big);622}623 624TEST(GSYMTest, TestAddressRangeEncodeDecode) {625 // Test encoding and decoding AddressRange objects. AddressRange objects626 // are always stored as offsets from the a base address. The base address627 // is the FunctionInfo's base address for function level ranges, and is628 // 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 650static 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 668TEST(GSYMTest, TestAddressRangesEncodeDecode) {669 // Test encoding and decoding AddressRanges. AddressRanges objects contain670 // ranges that are stored as offsets from the a base address. The base address671 // is the FunctionInfo's base address for function level ranges, and is the672 // 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 689static 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 707TEST(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 than745 // 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 a753 // 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 765static 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 777TEST(GSYMTest, TestLineTableDecodeErrors) {778 // Test decoding InlineInfo objects that ensure we report an appropriate779 // 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 stream797 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 stream802 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 stream807 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 813TEST(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 less825 // 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 less835 // 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 843static 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 853static 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.866static 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 else879 H.UUID[i] = 0;880 }881}882 883TEST(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 899TEST(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 921static 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}936TEST(GSYMTest, TestHeaderEncodeDecode) {937 Header H;938 InitHeader(H);939 TestHeaderEncodeDecode(H, llvm::endianness::little);940 TestHeaderEncodeDecode(H, llvm::endianness::big);941}942 943static 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 954TEST(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 no960 // function infos. We shouldn't be saving a GSYM file in this case since961 // 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't969 // 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 is982 // 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 line988 // table.989 GC.forEachFunctionInfo([](FunctionInfo &FI) -> bool {990 FI.OptLineTable = LineTable(); // Invalid line table.991 return false; // Stop iterating992 });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 inline996 // info.997 GC.forEachFunctionInfo([](FunctionInfo &FI) -> bool {998 FI.OptLineTable = std::nullopt;999 FI.Inline = InlineInfo(); // Invalid InlineInfo.1000 return false; // Stop iterating1001 });1002 TestGsymCreatorEncodeError(llvm::endianness::little, GC,1003 "attempted to encode invalid InlineInfo object");1004}1005 1006static void Compare(const GsymCreator &GC, const GsymReader &GR) {1007 // Verify that all of the data in a GsymCreator is correctly decoded from1008 // a GsymReader. To do this, we iterator over1009 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 1017static 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 1038TEST(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, // NumAddresses1054 ArrayRef<uint8_t>(UUID));1055 TestEncodeDecode(GC, llvm::endianness::big, GSYM_VERSION, AddrOffSize,1056 BaseAddr,1057 2, // NumAddresses1058 ArrayRef<uint8_t>(UUID));1059}1060 1061TEST(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, // NumAddresses1077 ArrayRef<uint8_t>(UUID));1078 TestEncodeDecode(GC, llvm::endianness::big, GSYM_VERSION, AddrOffSize,1079 BaseAddr,1080 2, // NumAddresses1081 ArrayRef<uint8_t>(UUID));1082}1083 1084TEST(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, // NumAddresses1100 ArrayRef<uint8_t>(UUID));1101 TestEncodeDecode(GC, llvm::endianness::big, GSYM_VERSION, AddrOffSize,1102 BaseAddr,1103 2, // NumAddresses1104 ArrayRef<uint8_t>(UUID));1105}1106 1107TEST(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, // NumAddresses1123 ArrayRef<uint8_t>(UUID));1124 TestEncodeDecode(GC, llvm::endianness::big, GSYM_VERSION, AddrOffSize,1125 BaseAddr,1126 2, // NumAddresses1127 ArrayRef<uint8_t>(UUID));1128}1129 1130static 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 1137static 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 1144TEST(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 1185TEST(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 entire1188 // FunctionInfo or InlineInfo, they only extract information needed for the1189 // lookup to happen which avoids allocations which can slow down1190 // 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 1284TEST(GSYMTest, TestDWARFFunctionWithAddresses) {1285 // Create a single compile unit with a single function and make sure it gets1286 // converted to DWARF correctly. The function's address range is in where1287 // DW_AT_low_pc and DW_AT_high_pc are both addresses.1288 StringRef yamldata = R"(1289 debug_str:1290 - ''1291 - /tmp/main.c1292 - main1293 debug_abbrev:1294 - Table:1295 - Code: 0x000000011296 Tag: DW_TAG_compile_unit1297 Children: DW_CHILDREN_yes1298 Attributes:1299 - Attribute: DW_AT_name1300 Form: DW_FORM_strp1301 - Attribute: DW_AT_low_pc1302 Form: DW_FORM_addr1303 - Attribute: DW_AT_high_pc1304 Form: DW_FORM_addr1305 - Attribute: DW_AT_language1306 Form: DW_FORM_data21307 - Code: 0x000000021308 Tag: DW_TAG_subprogram1309 Children: DW_CHILDREN_no1310 Attributes:1311 - Attribute: DW_AT_name1312 Form: DW_FORM_strp1313 - Attribute: DW_AT_low_pc1314 Form: DW_FORM_addr1315 - Attribute: DW_AT_high_pc1316 Form: DW_FORM_addr1317 debug_info:1318 - Version: 41319 AddrSize: 81320 Entries:1321 - AbbrCode: 0x000000011322 Values:1323 - Value: 0x00000000000000011324 - Value: 0x00000000000010001325 - Value: 0x00000000000020001326 - Value: 0x00000000000000041327 - AbbrCode: 0x000000021328 Values:1329 - Value: 0x000000000000000D1330 - Value: 0x00000000000010001331 - Value: 0x00000000000020001332 - AbbrCode: 0x000000001333 )";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 1362TEST(GSYMTest, TestDWARFFunctionWithAddressAndOffset) {1363 // Create a single compile unit with a single function and make sure it gets1364 // converted to DWARF correctly. The function's address range is in where1365 // 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.c1370 - main1371 debug_abbrev:1372 - Table:1373 - Code: 0x000000011374 Tag: DW_TAG_compile_unit1375 Children: DW_CHILDREN_yes1376 Attributes:1377 - Attribute: DW_AT_name1378 Form: DW_FORM_strp1379 - Attribute: DW_AT_low_pc1380 Form: DW_FORM_addr1381 - Attribute: DW_AT_high_pc1382 Form: DW_FORM_data41383 - Attribute: DW_AT_language1384 Form: DW_FORM_data21385 - Code: 0x000000021386 Tag: DW_TAG_subprogram1387 Children: DW_CHILDREN_no1388 Attributes:1389 - Attribute: DW_AT_name1390 Form: DW_FORM_strp1391 - Attribute: DW_AT_low_pc1392 Form: DW_FORM_addr1393 - Attribute: DW_AT_high_pc1394 Form: DW_FORM_data41395 debug_info:1396 - Version: 41397 AddrSize: 81398 Entries:1399 - AbbrCode: 0x000000011400 Values:1401 - Value: 0x00000000000000011402 - Value: 0x00000000000010001403 - Value: 0x00000000000010001404 - Value: 0x00000000000000041405 - AbbrCode: 0x000000021406 Values:1407 - Value: 0x000000000000000D1408 - Value: 0x00000000000010001409 - Value: 0x00000000000010001410 - AbbrCode: 0x000000001411 )";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 1440TEST(GSYMTest, TestDWARFStructMethodNoMangled) {1441 // Sometimes the compiler will omit the mangled name in the DWARF for static1442 // and member functions of classes and structs. This test verifies that the1443 // fully qualified name of the method is computed and used as the string for1444 // the function in the GSYM in these cases. Otherwise we might just get a1445 // function name like "erase" instead of "std::vector<int>::erase".1446 StringRef yamldata = R"(1447 debug_str:1448 - ''1449 - /tmp/main.c1450 - Foo1451 - dump1452 - this1453 debug_abbrev:1454 - Table:1455 - Code: 0x000000011456 Tag: DW_TAG_compile_unit1457 Children: DW_CHILDREN_yes1458 Attributes:1459 - Attribute: DW_AT_name1460 Form: DW_FORM_strp1461 - Attribute: DW_AT_low_pc1462 Form: DW_FORM_addr1463 - Attribute: DW_AT_high_pc1464 Form: DW_FORM_addr1465 - Attribute: DW_AT_language1466 Form: DW_FORM_data21467 - Code: 0x000000021468 Tag: DW_TAG_structure_type1469 Children: DW_CHILDREN_yes1470 Attributes:1471 - Attribute: DW_AT_name1472 Form: DW_FORM_strp1473 - Code: 0x000000031474 Tag: DW_TAG_subprogram1475 Children: DW_CHILDREN_yes1476 Attributes:1477 - Attribute: DW_AT_name1478 Form: DW_FORM_strp1479 - Attribute: DW_AT_low_pc1480 Form: DW_FORM_addr1481 - Attribute: DW_AT_high_pc1482 Form: DW_FORM_addr1483 - Code: 0x000000041484 Tag: DW_TAG_formal_parameter1485 Children: DW_CHILDREN_no1486 Attributes:1487 - Attribute: DW_AT_name1488 Form: DW_FORM_strp1489 - Attribute: DW_AT_type1490 Form: DW_FORM_ref41491 - Attribute: DW_AT_artificial1492 Form: DW_FORM_flag_present1493 debug_info:1494 - Version: 41495 AddrSize: 81496 Entries:1497 - AbbrCode: 0x000000011498 Values:1499 - Value: 0x00000000000000011500 - Value: 0x00000000000010001501 - Value: 0x00000000000020001502 - Value: 0x00000000000000041503 - AbbrCode: 0x000000021504 Values:1505 - Value: 0x000000000000000D1506 - AbbrCode: 0x000000031507 Values:1508 - Value: 0x00000000000000111509 - Value: 0x00000000000010001510 - Value: 0x00000000000020001511 - AbbrCode: 0x000000041512 Values:1513 - Value: 0x00000000000000161514 - Value: 0x00000000000000221515 - Value: 0x00000000000000011516 - AbbrCode: 0x000000001517 - AbbrCode: 0x000000001518 - AbbrCode: 0x000000001519 )";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 1550TEST(GSYMTest, TestDWARFTextRanges) {1551 // Linkers don't understand DWARF, they just like to concatenate and1552 // relocate data within the DWARF sections. This means that if a function1553 // gets dead stripped, and if those functions use an offset as the1554 // DW_AT_high_pc, we can end up with many functions at address zero. The1555 // DwarfTransformer allows clients to specify valid .text address ranges1556 // and any addresses of any functions must fall within those ranges if any1557 // have been specified. This means that an object file can calcuate the1558 // address ranges within the binary where code lives and set these ranges1559 // as constraints in the DwarfTransformer. ObjectFile instances can1560 // add a address ranges of sections that have executable permissions. This1561 // keeps bad information from being added to a GSYM file and causing issues1562 // when symbolicating.1563 StringRef yamldata = R"(1564 debug_str:1565 - ''1566 - /tmp/main.c1567 - main1568 - dead_stripped1569 - dead_stripped21570 debug_abbrev:1571 - Table:1572 - Code: 0x000000011573 Tag: DW_TAG_compile_unit1574 Children: DW_CHILDREN_yes1575 Attributes:1576 - Attribute: DW_AT_name1577 Form: DW_FORM_strp1578 - Attribute: DW_AT_low_pc1579 Form: DW_FORM_addr1580 - Attribute: DW_AT_high_pc1581 Form: DW_FORM_data41582 - Attribute: DW_AT_language1583 Form: DW_FORM_data21584 - Code: 0x000000021585 Tag: DW_TAG_subprogram1586 Children: DW_CHILDREN_no1587 Attributes:1588 - Attribute: DW_AT_name1589 Form: DW_FORM_strp1590 - Attribute: DW_AT_low_pc1591 Form: DW_FORM_addr1592 - Attribute: DW_AT_high_pc1593 Form: DW_FORM_data41594 debug_info:1595 - Version: 41596 AddrSize: 81597 Entries:1598 - AbbrCode: 0x000000011599 Values:1600 - Value: 0x00000000000000011601 - Value: 0x00000000000010001602 - Value: 0x00000000000010001603 - Value: 0x00000000000000041604 - AbbrCode: 0x000000021605 Values:1606 - Value: 0x000000000000000D1607 - Value: 0x00000000000010001608 - Value: 0x00000000000010001609 - AbbrCode: 0x000000021610 Values:1611 - Value: 0x00000000000000121612 - Value: 0x00000000000000001613 - Value: 0x00000000000001001614 - AbbrCode: 0x000000021615 Values:1616 - Value: 0x00000000000000201617 - Value: 0x00000000000000001618 - Value: 0x00000000000000401619 - AbbrCode: 0x000000001620 )";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 the1631 // 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 1656TEST(GSYMTest, TestEmptySymbolEndAddressOfTextRanges) {1657 // Test that if we have valid text ranges and we have a symbol with no size1658 // as the last FunctionInfo entry that the size of the symbol gets set to the1659 // 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 1685TEST(GSYMTest, TestDWARFInlineInfo) {1686 // Make sure we parse the line table and inline information correctly from1687 // DWARF.1688 StringRef yamldata = R"(1689 debug_str:1690 - ''1691 - /tmp/main.c1692 - main1693 - inline11694 debug_abbrev:1695 - Table:1696 - Code: 0x000000011697 Tag: DW_TAG_compile_unit1698 Children: DW_CHILDREN_yes1699 Attributes:1700 - Attribute: DW_AT_name1701 Form: DW_FORM_strp1702 - Attribute: DW_AT_low_pc1703 Form: DW_FORM_addr1704 - Attribute: DW_AT_high_pc1705 Form: DW_FORM_data41706 - Attribute: DW_AT_language1707 Form: DW_FORM_data21708 - Attribute: DW_AT_stmt_list1709 Form: DW_FORM_sec_offset1710 - Code: 0x000000021711 Tag: DW_TAG_subprogram1712 Children: DW_CHILDREN_yes1713 Attributes:1714 - Attribute: DW_AT_name1715 Form: DW_FORM_strp1716 - Attribute: DW_AT_low_pc1717 Form: DW_FORM_addr1718 - Attribute: DW_AT_high_pc1719 Form: DW_FORM_data41720 - Code: 0x000000031721 Tag: DW_TAG_inlined_subroutine1722 Children: DW_CHILDREN_no1723 Attributes:1724 - Attribute: DW_AT_name1725 Form: DW_FORM_strp1726 - Attribute: DW_AT_low_pc1727 Form: DW_FORM_addr1728 - Attribute: DW_AT_high_pc1729 Form: DW_FORM_data41730 - Attribute: DW_AT_call_file1731 Form: DW_FORM_data41732 - Attribute: DW_AT_call_line1733 Form: DW_FORM_data41734 debug_info:1735 - Version: 41736 AddrSize: 81737 Entries:1738 - AbbrCode: 0x000000011739 Values:1740 - Value: 0x00000000000000011741 - Value: 0x00000000000010001742 - Value: 0x00000000000010001743 - Value: 0x00000000000000041744 - Value: 0x00000000000000001745 - AbbrCode: 0x000000021746 Values:1747 - Value: 0x000000000000000D1748 - Value: 0x00000000000010001749 - Value: 0x00000000000010001750 - AbbrCode: 0x000000031751 Values:1752 - Value: 0x00000000000000121753 - Value: 0x00000000000011001754 - Value: 0x00000000000001001755 - Value: 0x00000000000000011756 - Value: 0x000000000000000A1757 - AbbrCode: 0x000000001758 - AbbrCode: 0x000000001759 debug_line:1760 - Length: 961761 Version: 21762 PrologueLength: 461763 MinInstLength: 11764 DefaultIsStmt: 11765 LineBase: 2511766 LineRange: 141767 OpcodeBase: 131768 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]1769 IncludeDirs:1770 - /tmp1771 Files:1772 - Name: main.c1773 DirIdx: 11774 ModTime: 01775 Length: 01776 - Name: inline.h1777 DirIdx: 11778 ModTime: 01779 Length: 01780 Opcodes:1781 - Opcode: DW_LNS_extended_op1782 ExtLen: 91783 SubOpcode: DW_LNE_set_address1784 Data: 40961785 - Opcode: DW_LNS_advance_line1786 SData: 91787 Data: 40961788 - Opcode: DW_LNS_copy1789 Data: 40961790 - Opcode: DW_LNS_advance_pc1791 Data: 2561792 - Opcode: DW_LNS_set_file1793 Data: 21794 - Opcode: DW_LNS_advance_line1795 SData: 101796 Data: 21797 - Opcode: DW_LNS_copy1798 Data: 21799 - Opcode: DW_LNS_advance_pc1800 Data: 1281801 - Opcode: DW_LNS_advance_line1802 SData: 11803 Data: 1281804 - Opcode: DW_LNS_copy1805 Data: 1281806 - Opcode: DW_LNS_advance_pc1807 Data: 1281808 - Opcode: DW_LNS_set_file1809 Data: 11810 - Opcode: DW_LNS_advance_line1811 SData: -101812 Data: 11813 - Opcode: DW_LNS_copy1814 Data: 11815 - Opcode: DW_LNS_advance_pc1816 Data: 35841817 - Opcode: DW_LNS_advance_line1818 SData: 11819 Data: 35841820 - Opcode: DW_LNS_extended_op1821 ExtLen: 11822 SubOpcode: DW_LNE_end_sequence1823 Data: 35841824 )";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 1891TEST(GSYMTest, TestDWARFNoLines) {1892 // Check that if a DW_TAG_subprogram doesn't have line table entries that1893 // we fall back and use the DW_AT_decl_file and DW_AT_decl_line to at least1894 // 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 make1898 // 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, make1902 // sure we have one line table entry that starts at1903 // the function start address and the decl file and1904 // line.1905 //1906 // 0x0000000b: DW_TAG_compile_unit1907 // 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_subprogram1914 // DW_AT_name ("lines_no_decl")1915 // DW_AT_low_pc (0x0000000000001000)1916 // DW_AT_high_pc (0x0000000000002000)1917 //1918 // 0x00000033: DW_TAG_subprogram1919 // 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_subprogram1926 // DW_AT_name ("no_lines_no_decl")1927 // DW_AT_low_pc (0x0000000000003000)1928 // DW_AT_high_pc (0x0000000000004000)1929 //1930 // 0x00000057: DW_TAG_subprogram1931 // 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: NULL1938 1939 StringRef yamldata = R"(1940 debug_str:1941 - ''1942 - '/tmp/main.c'1943 - lines_no_decl1944 - lines_with_decl1945 - no_lines_no_decl1946 - no_lines_with_decl1947 debug_abbrev:1948 - Table:1949 - Code: 0x000000011950 Tag: DW_TAG_compile_unit1951 Children: DW_CHILDREN_yes1952 Attributes:1953 - Attribute: DW_AT_name1954 Form: DW_FORM_strp1955 - Attribute: DW_AT_low_pc1956 Form: DW_FORM_addr1957 - Attribute: DW_AT_high_pc1958 Form: DW_FORM_data41959 - Attribute: DW_AT_language1960 Form: DW_FORM_data21961 - Attribute: DW_AT_stmt_list1962 Form: DW_FORM_sec_offset1963 - Code: 0x000000021964 Tag: DW_TAG_subprogram1965 Children: DW_CHILDREN_no1966 Attributes:1967 - Attribute: DW_AT_name1968 Form: DW_FORM_strp1969 - Attribute: DW_AT_low_pc1970 Form: DW_FORM_addr1971 - Attribute: DW_AT_high_pc1972 Form: DW_FORM_data41973 - Code: 0x000000031974 Tag: DW_TAG_subprogram1975 Children: DW_CHILDREN_no1976 Attributes:1977 - Attribute: DW_AT_name1978 Form: DW_FORM_strp1979 - Attribute: DW_AT_low_pc1980 Form: DW_FORM_addr1981 - Attribute: DW_AT_high_pc1982 Form: DW_FORM_data41983 - Attribute: DW_AT_decl_file1984 Form: DW_FORM_data11985 - Attribute: DW_AT_decl_line1986 Form: DW_FORM_data11987 debug_info:1988 - Version: 41989 AddrSize: 81990 Entries:1991 - AbbrCode: 0x000000011992 Values:1993 - Value: 0x00000000000000011994 - Value: 0x00000000000010001995 - Value: 0x00000000000010001996 - Value: 0x00000000000000041997 - Value: 0x00000000000000001998 - AbbrCode: 0x000000021999 Values:2000 - Value: 0x000000000000000D2001 - Value: 0x00000000000010002002 - Value: 0x00000000000010002003 - AbbrCode: 0x000000032004 Values:2005 - Value: 0x000000000000001B2006 - Value: 0x00000000000020002007 - Value: 0x00000000000010002008 - Value: 0x00000000000000012009 - Value: 0x00000000000000142010 - AbbrCode: 0x000000022011 Values:2012 - Value: 0x000000000000002B2013 - Value: 0x00000000000030002014 - Value: 0x00000000000010002015 - AbbrCode: 0x000000032016 Values:2017 - Value: 0x000000000000003C2018 - Value: 0x00000000000040002019 - Value: 0x00000000000010002020 - Value: 0x00000000000000012021 - Value: 0x00000000000000282022 - AbbrCode: 0x000000002023 debug_line:2024 - Length: 922025 Version: 22026 PrologueLength: 342027 MinInstLength: 12028 DefaultIsStmt: 12029 LineBase: 2512030 LineRange: 142031 OpcodeBase: 132032 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]2033 IncludeDirs:2034 - '/tmp'2035 Files:2036 - Name: main.c2037 DirIdx: 12038 ModTime: 02039 Length: 02040 Opcodes:2041 - Opcode: DW_LNS_extended_op2042 ExtLen: 92043 SubOpcode: DW_LNE_set_address2044 Data: 40962045 - Opcode: DW_LNS_advance_line2046 SData: 102047 Data: 02048 - Opcode: DW_LNS_copy2049 Data: 02050 - Opcode: DW_LNS_advance_pc2051 Data: 5122052 - Opcode: DW_LNS_advance_line2053 SData: 12054 Data: 02055 - Opcode: DW_LNS_copy2056 Data: 02057 - Opcode: DW_LNS_advance_pc2058 Data: 35842059 - Opcode: DW_LNS_extended_op2060 ExtLen: 12061 SubOpcode: DW_LNE_end_sequence2062 Data: 02063 - Opcode: DW_LNS_extended_op2064 ExtLen: 92065 SubOpcode: DW_LNE_set_address2066 Data: 81922067 - Opcode: DW_LNS_advance_line2068 SData: 202069 Data: 02070 - Opcode: DW_LNS_copy2071 Data: 02072 - Opcode: DW_LNS_advance_pc2073 Data: 5122074 - Opcode: DW_LNS_advance_line2075 SData: 12076 Data: 02077 - Opcode: DW_LNS_copy2078 Data: 02079 - Opcode: DW_LNS_advance_pc2080 Data: 35842081 - Opcode: DW_LNS_extended_op2082 ExtLen: 12083 SubOpcode: DW_LNE_end_sequence2084 Data: 02085 )";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 entry2115 // 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 202127 // 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/line2147 // 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 2154TEST(GSYMTest, TestDWARFDeadStripAddr4) {2155 // Check that various techniques that compilers use for dead code stripping2156 // work for 4 byte addresses. Make sure we keep the good functions and2157 // strip any functions whose name starts with "stripped".2158 //2159 // 1 - Compilers might set the low PC to -1 (UINT32_MAX) for compile unit2160 // 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_unit2165 // 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_subprogram2171 // DW_AT_name ("main")2172 // DW_AT_low_pc (0x0000000000001000)2173 // DW_AT_high_pc (0x0000000000002000)2174 //2175 // 0x00000027: DW_TAG_subprogram2176 // DW_AT_name ("stripped1")2177 // DW_AT_low_pc (0x00000000ffffffff)2178 // DW_AT_high_pc (0x0000000100000000)2179 //2180 // 0x00000034: DW_TAG_subprogram2181 // DW_AT_name ("stripped2")2182 // DW_AT_low_pc (0x0000000000003000)2183 // DW_AT_high_pc (0x0000000000003000)2184 //2185 // 0x00000041: DW_TAG_subprogram2186 // DW_AT_name ("stripped3")2187 // DW_AT_low_pc (0x0000000000004000)2188 // DW_AT_high_pc (0x0000000000003fff)2189 //2190 // 0x0000004e: NULL2191 2192 StringRef yamldata = R"(2193 debug_str:2194 - ''2195 - '/tmp/main.c'2196 - main2197 - stripped12198 - stripped22199 - stripped32200 debug_abbrev:2201 - Table:2202 - Code: 0x000000012203 Tag: DW_TAG_compile_unit2204 Children: DW_CHILDREN_yes2205 Attributes:2206 - Attribute: DW_AT_name2207 Form: DW_FORM_strp2208 - Attribute: DW_AT_low_pc2209 Form: DW_FORM_addr2210 - Attribute: DW_AT_high_pc2211 Form: DW_FORM_data42212 - Attribute: DW_AT_language2213 Form: DW_FORM_data22214 - Code: 0x000000022215 Tag: DW_TAG_subprogram2216 Children: DW_CHILDREN_no2217 Attributes:2218 - Attribute: DW_AT_name2219 Form: DW_FORM_strp2220 - Attribute: DW_AT_low_pc2221 Form: DW_FORM_addr2222 - Attribute: DW_AT_high_pc2223 Form: DW_FORM_data42224 - Code: 0x000000032225 Tag: DW_TAG_subprogram2226 Children: DW_CHILDREN_no2227 Attributes:2228 - Attribute: DW_AT_name2229 Form: DW_FORM_strp2230 - Attribute: DW_AT_low_pc2231 Form: DW_FORM_addr2232 - Attribute: DW_AT_high_pc2233 Form: DW_FORM_addr2234 debug_info:2235 - Version: 42236 AddrSize: 42237 Entries:2238 - AbbrCode: 0x000000012239 Values:2240 - Value: 0x00000000000000012241 - Value: 0x00000000000010002242 - Value: 0x00000000000010002243 - Value: 0x00000000000000042244 - AbbrCode: 0x000000022245 Values:2246 - Value: 0x000000000000000D2247 - Value: 0x00000000000010002248 - Value: 0x00000000000010002249 - AbbrCode: 0x000000022250 Values:2251 - Value: 0x00000000000000122252 - Value: 0x00000000FFFFFFFF2253 - Value: 0x00000000000000012254 - AbbrCode: 0x000000032255 Values:2256 - Value: 0x000000000000001C2257 - Value: 0x00000000000030002258 - Value: 0x00000000000030002259 - AbbrCode: 0x000000032260 Values:2261 - Value: 0x00000000000000262262 - Value: 0x00000000000040002263 - Value: 0x0000000000003FFF2264 - AbbrCode: 0x000000002265 )";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 2295TEST(GSYMTest, TestDWARFDeadStripAddr8) {2296 // Check that various techniques that compilers use for dead code stripping2297 // work for 4 byte addresses. Make sure we keep the good functions and2298 // strip any functions whose name starts with "stripped".2299 //2300 // 1 - Compilers might set the low PC to -1 (UINT64_MAX) for compile unit2301 // 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_unit2306 // 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_subprogram2312 // DW_AT_name ("main")2313 // DW_AT_low_pc (0x0000000000001000)2314 // DW_AT_high_pc (0x0000000000002000)2315 //2316 // 0x0000002f: DW_TAG_subprogram2317 // DW_AT_name ("stripped1")2318 // DW_AT_low_pc (0xffffffffffffffff)2319 // DW_AT_high_pc (0x0000000000000000)2320 //2321 // 0x00000040: DW_TAG_subprogram2322 // DW_AT_name ("stripped2")2323 // DW_AT_low_pc (0x0000000000003000)2324 // DW_AT_high_pc (0x0000000000003000)2325 //2326 // 0x00000055: DW_TAG_subprogram2327 // DW_AT_name ("stripped3")2328 // DW_AT_low_pc (0x0000000000004000)2329 // DW_AT_high_pc (0x0000000000003fff)2330 //2331 // 0x0000006a: NULL2332 2333 StringRef yamldata = R"(2334 debug_str:2335 - ''2336 - '/tmp/main.c'2337 - main2338 - stripped12339 - stripped22340 - stripped32341 debug_abbrev:2342 - Table:2343 - Code: 0x000000012344 Tag: DW_TAG_compile_unit2345 Children: DW_CHILDREN_yes2346 Attributes:2347 - Attribute: DW_AT_name2348 Form: DW_FORM_strp2349 - Attribute: DW_AT_low_pc2350 Form: DW_FORM_addr2351 - Attribute: DW_AT_high_pc2352 Form: DW_FORM_data42353 - Attribute: DW_AT_language2354 Form: DW_FORM_data22355 - Code: 0x000000022356 Tag: DW_TAG_subprogram2357 Children: DW_CHILDREN_no2358 Attributes:2359 - Attribute: DW_AT_name2360 Form: DW_FORM_strp2361 - Attribute: DW_AT_low_pc2362 Form: DW_FORM_addr2363 - Attribute: DW_AT_high_pc2364 Form: DW_FORM_data42365 - Code: 0x000000032366 Tag: DW_TAG_subprogram2367 Children: DW_CHILDREN_no2368 Attributes:2369 - Attribute: DW_AT_name2370 Form: DW_FORM_strp2371 - Attribute: DW_AT_low_pc2372 Form: DW_FORM_addr2373 - Attribute: DW_AT_high_pc2374 Form: DW_FORM_addr2375 debug_info:2376 - Version: 42377 AddrSize: 82378 Entries:2379 - AbbrCode: 0x000000012380 Values:2381 - Value: 0x00000000000000012382 - Value: 0x00000000000010002383 - Value: 0x00000000000010002384 - Value: 0x00000000000000042385 - AbbrCode: 0x000000022386 Values:2387 - Value: 0x000000000000000D2388 - Value: 0x00000000000010002389 - Value: 0x00000000000010002390 - AbbrCode: 0x000000022391 Values:2392 - Value: 0x00000000000000122393 - Value: 0xFFFFFFFFFFFFFFFF2394 - Value: 0x00000000000000012395 - AbbrCode: 0x000000032396 Values:2397 - Value: 0x000000000000001C2398 - Value: 0x00000000000030002399 - Value: 0x00000000000030002400 - AbbrCode: 0x000000032401 Values:2402 - Value: 0x00000000000000262403 - Value: 0x00000000000040002404 - Value: 0x0000000000003FFF2405 - AbbrCode: 0x000000002406 )";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 2436TEST(GSYMTest, TestGsymCreatorMultipleSymbolsWithNoSize) {2437 // Multiple symbols at the same address with zero size were being emitted2438 // instead of being combined into a single entry. This function tests to make2439 // 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, // NumAddresses2455 ArrayRef<uint8_t>(UUID));2456 TestEncodeDecode(GC, llvm::endianness::big, GSYM_VERSION, AddrOffSize,2457 BaseAddr,2458 1, // NumAddresses2459 ArrayRef<uint8_t>(UUID));2460}2461 2462// Helper function to quickly create a FunctionInfo in a GsymCreator for testing.2463static 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 or2503// GsymReader that was successfully decoded.2504static 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 2519TEST(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 by2522 // encoding multiple segments, then we verify that we get the same information2523 // when doing lookups on the full GSYM that was decoded from encoding the2524 // 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 will2536 // then test doing lookups on the "GR", or the full GSYM file and then test2537 // doing lookups on the GsymReader objects for each segment to ensure we get2538 // the exact same information. So after all of the code below we will have2539 // GsymReader objects that each contain one function. We name the creators2540 // 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, gets2547 // updated as expected.2548 size_t FuncIdx = 0;2549 // Make sure we get an error if the segment size is too small to encode a2550 // 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't2557 // 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 error2577 // 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 lookups2597 // in the GsymReader that contains all functions and from the segmented2598 // GsymReader in GR1000.2599 for (uint64_t Addr = 0x1000; Addr < 0x1030; ++Addr) {2600 // Lookup in the main GsymReader that contains all function infos2601 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 segment2608 // 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 lookups2615 // in the GsymReader that contains all functions and from the segmented2616 // GsymReader in GR2000.2617 for (uint64_t Addr = 0x2000; Addr < 0x2030; ++Addr) {2618 // Lookup in the main GsymReader that contains all function infos2619 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 segment2626 // 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 lookups2634 // in the GsymReader that contains all functions and from the segmented2635 // GsymReader in GR3000.2636 for (uint64_t Addr = 0x3000; Addr < 0x3030; ++Addr) {2637 // Lookup in the main GsymReader that contains all function infos2638 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 segment2645 // 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 lookups2652 // in the GsymReader that contains all functions and from the segmented2653 // GsymReader in GR4000.2654 for (uint64_t Addr = 0x4000; Addr < 0x4030; ++Addr) {2655 // Lookup in the main GsymReader that contains all function infos2656 auto MainLR = GR->lookup(Addr);2657 ASSERT_THAT_EXPECTED(MainLR, Succeeded());2658 // Lookup in the GsymReader for that contains 0x40002659 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 segment2664 // 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 2671TEST(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 by2674 // encoding multiple segments, then we verify that we get the same information2675 // when doing lookups on the full GSYM that was decoded from encoding the2676 // 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 will2687 // then test doing lookups on the "GR", or the full GSYM file and then test2688 // doing lookups on the GsymReader objects for each segment to ensure we get2689 // the exact same information. So after all of the code below we will have2690 // GsymReader objects that each contain one function. We name the creators2691 // 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, gets2698 // updated as expected.2699 size_t FuncIdx = 0;2700 // Make sure we get an error if the segment size is too small to encode a2701 // 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't2708 // 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 error2728 // 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 lookups2748 // in the GsymReader that contains all functions and from the segmented2749 // GsymReader in GR1000.2750 for (uint64_t Addr = 0x1000; Addr < 0x1030; ++Addr) {2751 // Lookup in the main GsymReader that contains all function infos2752 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 segment2759 // 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 lookups2766 // in the GsymReader that contains all functions and from the segmented2767 // GsymReader in GR2000.2768 for (uint64_t Addr = 0x2000; Addr < 0x2030; ++Addr) {2769 // Lookup in the main GsymReader that contains all function infos2770 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 segment2777 // 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 lookups2785 // in the GsymReader that contains all functions and from the segmented2786 // GsymReader in GR3000.2787 for (uint64_t Addr = 0x3000; Addr < 0x3030; ++Addr) {2788 // Lookup in the main GsymReader that contains all function infos2789 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 segment2796 // 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 lookups2803 // in the GsymReader that contains all functions and from the segmented2804 // GsymReader in GR4000.2805 for (uint64_t Addr = 0x4000; Addr < 0x4030; ++Addr) {2806 // Lookup in the main GsymReader that contains all function infos2807 auto MainLR = GR->lookup(Addr);2808 ASSERT_THAT_EXPECTED(MainLR, Succeeded());2809 // Lookup in the GsymReader for that contains 0x40002810 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 segment2815 // 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 2823TEST(GSYMTest, TestDWARFInlineRangeScopes) {2824 // Test cases where inlined functions address ranges are not contained in the2825 // parent ranges and that we can successfully remove them and emit error2826 // messages. The DWARF for this looks like the dump below. The inlined2827 // functions named "invalid1" and "invalid2" are expected to be removed and2828 // an appropriate error message will be emitted.2829 //2830 // 0x0000000b: DW_TAG_compile_unit2831 // DW_AT_name ("/tmp/main.cpp")2832 // DW_AT_language (DW_LANG_C)2833 // DW_AT_stmt_list (0x00000000)2834 //2835 // 0x00000015: DW_TAG_subprogram2836 // DW_AT_name ("foo")2837 // DW_AT_low_pc (0x0000000000001000)2838 // DW_AT_high_pc (0x0000000000002000)2839 //2840 // 0x0000002a: DW_TAG_inlined_subroutine2841 // 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_subroutine2848 // 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_subroutine2855 // 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_subroutine2862 // 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: NULL2869 //2870 // 0x00000087: NULL2871 //2872 // 0x00000088: NULL2873 2874 StringRef yamldata = R"(2875 debug_str:2876 - ''2877 - '/tmp/main.cpp'2878 - foo2879 - invalid12880 - valid12881 - invalid22882 - valid22883 debug_abbrev:2884 - ID: 02885 Table:2886 - Code: 0x12887 Tag: DW_TAG_compile_unit2888 Children: DW_CHILDREN_yes2889 Attributes:2890 - Attribute: DW_AT_name2891 Form: DW_FORM_strp2892 - Attribute: DW_AT_language2893 Form: DW_FORM_udata2894 - Attribute: DW_AT_stmt_list2895 Form: DW_FORM_sec_offset2896 - Code: 0x22897 Tag: DW_TAG_subprogram2898 Children: DW_CHILDREN_yes2899 Attributes:2900 - Attribute: DW_AT_name2901 Form: DW_FORM_strp2902 - Attribute: DW_AT_low_pc2903 Form: DW_FORM_addr2904 - Attribute: DW_AT_high_pc2905 Form: DW_FORM_addr2906 - Code: 0x32907 Tag: DW_TAG_inlined_subroutine2908 Children: DW_CHILDREN_no2909 Attributes:2910 - Attribute: DW_AT_name2911 Form: DW_FORM_strp2912 - Attribute: DW_AT_low_pc2913 Form: DW_FORM_addr2914 - Attribute: DW_AT_high_pc2915 Form: DW_FORM_addr2916 - Attribute: DW_AT_call_file2917 Form: DW_FORM_data12918 - Attribute: DW_AT_call_line2919 Form: DW_FORM_data12920 - Code: 0x42921 Tag: DW_TAG_inlined_subroutine2922 Children: DW_CHILDREN_yes2923 Attributes:2924 - Attribute: DW_AT_name2925 Form: DW_FORM_strp2926 - Attribute: DW_AT_low_pc2927 Form: DW_FORM_addr2928 - Attribute: DW_AT_high_pc2929 Form: DW_FORM_addr2930 - Attribute: DW_AT_call_file2931 Form: DW_FORM_data12932 - Attribute: DW_AT_call_line2933 Form: DW_FORM_data12934 debug_info:2935 - Length: 0x852936 Version: 42937 AbbrevTableID: 02938 AbbrOffset: 0x02939 AddrSize: 82940 Entries:2941 - AbbrCode: 0x12942 Values:2943 - Value: 0x12944 - Value: 0x22945 - Value: 0x02946 - AbbrCode: 0x22947 Values:2948 - Value: 0xF2949 - Value: 0x10002950 - Value: 0x20002951 - AbbrCode: 0x32952 Values:2953 - Value: 0x132954 - Value: 0xFFF2955 - Value: 0x10012956 - Value: 0x12957 - Value: 0xA2958 - AbbrCode: 0x42959 Values:2960 - Value: 0x1C2961 - Value: 0x10102962 - Value: 0x11002963 - Value: 0x12964 - Value: 0xB2965 - AbbrCode: 0x32966 Values:2967 - Value: 0x232968 - Value: 0x10002969 - Value: 0x11002970 - Value: 0x12971 - Value: 0xC2972 - AbbrCode: 0x32973 Values:2974 - Value: 0x2C2975 - Value: 0x10202976 - Value: 0x10302977 - Value: 0x12978 - Value: 0xD2979 - AbbrCode: 0x02980 - AbbrCode: 0x02981 - AbbrCode: 0x02982 debug_line:2983 - Length: 842984 Version: 22985 PrologueLength: 362986 MinInstLength: 12987 DefaultIsStmt: 12988 LineBase: 2512989 LineRange: 142990 OpcodeBase: 132991 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]2992 IncludeDirs:2993 - '/tmp'2994 Files:2995 - Name: main.cpp2996 DirIdx: 12997 ModTime: 02998 Length: 02999 Opcodes:3000 - Opcode: DW_LNS_extended_op3001 ExtLen: 93002 SubOpcode: DW_LNE_set_address3003 Data: 40963004 - Opcode: DW_LNS_advance_line3005 SData: 93006 Data: 03007 - Opcode: DW_LNS_copy3008 Data: 03009 - Opcode: DW_LNS_advance_pc3010 Data: 163011 - Opcode: DW_LNS_advance_line3012 SData: 13013 Data: 03014 - Opcode: DW_LNS_copy3015 Data: 03016 - Opcode: DW_LNS_advance_pc3017 Data: 163018 - Opcode: DW_LNS_advance_line3019 SData: 13020 Data: 03021 - Opcode: DW_LNS_copy3022 Data: 03023 - Opcode: DW_LNS_advance_pc3024 Data: 163025 - Opcode: DW_LNS_advance_line3026 SData: 13027 Data: 03028 - Opcode: DW_LNS_copy3029 Data: 03030 - Opcode: DW_LNS_advance_pc3031 Data: 40483032 - Opcode: DW_LNS_advance_line3033 SData: 13034 Data: 03035 - Opcode: DW_LNS_copy3036 Data: 03037 - Opcode: DW_LNS_advance_pc3038 Data: 163039 - Opcode: DW_LNS_advance_line3040 SData: -13041 Data: 03042 - Opcode: DW_LNS_extended_op3043 ExtLen: 13044 SubOpcode: DW_LNE_end_sequence3045 Data: 03046 )";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 invalid3085 // 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 that3090 // we have only 1 inline function inside of this, even though the DWARF3091 // contains two. One of the inline functions in "foo" is invalid, so we must3092 // 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 the3101 // DWARF, but one has an address range which isn't contained in any ranges3102 // 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 the3112 // DWARF, but one has an address range which isn't contained in any ranges3113 // 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 3122TEST(GSYMTest, TestDWARFEmptyInline) {3123 // Test cases where we have inline function information in the DWARF that3124 // results in us trying to parse the inline info, but since the inline3125 // info ends up not adding any valid inline functions due to ranges3126 // not being correct, we end up not encoding any inline information. This3127 // tests that if we end up creating an empty inline info struct, we end up3128 // not encoding it into the GSYM file.3129 //3130 // 0x0000000b: DW_TAG_compile_unit3131 // DW_AT_name ("/tmp/main.cpp")3132 // DW_AT_language (DW_LANG_C)3133 // DW_AT_stmt_list (0x00000000)3134 //3135 // 0x00000015: DW_TAG_subprogram3136 // DW_AT_name ("foo")3137 // DW_AT_low_pc (0x0000000000001000)3138 // DW_AT_high_pc (0x0000000000001050)3139 //3140 // 0x0000002a: DW_TAG_inlined_subroutine3141 // 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: NULL3148 //3149 // 0x00000048: NULL3150 3151 StringRef yamldata = R"(3152 debug_str:3153 - ''3154 - '/tmp/main.cpp'3155 - foo3156 - inlineWithInvalidRange3157 debug_abbrev:3158 - ID: 03159 Table:3160 - Code: 0x13161 Tag: DW_TAG_compile_unit3162 Children: DW_CHILDREN_yes3163 Attributes:3164 - Attribute: DW_AT_name3165 Form: DW_FORM_strp3166 - Attribute: DW_AT_language3167 Form: DW_FORM_udata3168 - Attribute: DW_AT_stmt_list3169 Form: DW_FORM_sec_offset3170 - Code: 0x23171 Tag: DW_TAG_subprogram3172 Children: DW_CHILDREN_yes3173 Attributes:3174 - Attribute: DW_AT_name3175 Form: DW_FORM_strp3176 - Attribute: DW_AT_low_pc3177 Form: DW_FORM_addr3178 - Attribute: DW_AT_high_pc3179 Form: DW_FORM_addr3180 - Code: 0x33181 Tag: DW_TAG_inlined_subroutine3182 Children: DW_CHILDREN_no3183 Attributes:3184 - Attribute: DW_AT_name3185 Form: DW_FORM_strp3186 - Attribute: DW_AT_low_pc3187 Form: DW_FORM_addr3188 - Attribute: DW_AT_high_pc3189 Form: DW_FORM_addr3190 - Attribute: DW_AT_call_file3191 Form: DW_FORM_data43192 - Attribute: DW_AT_call_line3193 Form: DW_FORM_data43194 debug_info:3195 - Length: 0x453196 Version: 43197 AbbrevTableID: 03198 AbbrOffset: 0x03199 AddrSize: 83200 Entries:3201 - AbbrCode: 0x13202 Values:3203 - Value: 0x13204 - Value: 0x23205 - Value: 0x03206 - AbbrCode: 0x23207 Values:3208 - Value: 0xF3209 - Value: 0x10003210 - Value: 0x10503211 - AbbrCode: 0x33212 Values:3213 - Value: 0x133214 - Value: 0x11003215 - Value: 0x12003216 - Value: 0x13217 - Value: 0xB3218 - AbbrCode: 0x03219 - AbbrCode: 0x03220 debug_line:3221 - Length: 763222 Version: 23223 PrologueLength: 363224 MinInstLength: 13225 DefaultIsStmt: 13226 LineBase: 2513227 LineRange: 143228 OpcodeBase: 133229 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]3230 IncludeDirs:3231 - '/tmp'3232 Files:3233 - Name: main.cpp3234 DirIdx: 13235 ModTime: 03236 Length: 03237 Opcodes:3238 - Opcode: DW_LNS_extended_op3239 ExtLen: 93240 SubOpcode: DW_LNE_set_address3241 Data: 40963242 - Opcode: DW_LNS_advance_line3243 SData: 93244 Data: 03245 - Opcode: DW_LNS_copy3246 Data: 03247 - Opcode: DW_LNS_advance_pc3248 Data: 163249 - Opcode: DW_LNS_advance_line3250 SData: 13251 Data: 03252 - Opcode: DW_LNS_copy3253 Data: 03254 - Opcode: DW_LNS_advance_pc3255 Data: 163256 - Opcode: DW_LNS_advance_line3257 SData: 13258 Data: 03259 - Opcode: DW_LNS_copy3260 Data: 03261 - Opcode: DW_LNS_advance_pc3262 Data: 163263 - Opcode: DW_LNS_advance_line3264 SData: 13265 Data: 03266 - Opcode: DW_LNS_copy3267 Data: 03268 - Opcode: DW_LNS_advance_pc3269 Data: 323270 - Opcode: DW_LNS_extended_op3271 ExtLen: 13272 SubOpcode: DW_LNE_end_sequence3273 Data: 03274 )";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 invalid3312 // 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 3318TEST(GSYMTest, TestFinalizeForLineTables) {3319 // This example has two compile units:3320 // - one contains a function "foo" with line table entries and "bar" without3321 // - one contains a function "bar" with line table entries and "foo" without3322 // 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 debug3324 // info.3325 //3326 // The DWARF is the same for the functions, but the first compile unit has3327 // lines entries for "foo" and the second one doesn't. And the first compile3328 // unit has no line entries for "bar", but the second one does. We expect the3329 // resulting gsym file to have a "foo" and "bar" that both have line entries.3330 //3331 // 0x0000000b: DW_TAG_compile_unit3332 // DW_AT_name ("/tmp/main.cpp")3333 // DW_AT_language (DW_LANG_C)3334 // DW_AT_stmt_list (0x00000000)3335 //3336 // 0x00000015: DW_TAG_subprogram3337 // DW_AT_name ("foo")3338 // DW_AT_low_pc (0x0000000000001000)3339 // DW_AT_high_pc (0x0000000000001050)3340 //3341 // 0x0000002a: DW_TAG_subprogram3342 // DW_AT_name ("bar")3343 // DW_AT_low_pc (0x0000000000002000)3344 // DW_AT_high_pc (0x0000000000002050)3345 //3346 // 0x0000003f: NULL3347 // 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_unit3350 // DW_AT_name ("/tmp/main.cpp")3351 // DW_AT_language (DW_LANG_C)3352 // DW_AT_stmt_list (0x00000043)3353 //3354 // 0x00000055: DW_TAG_subprogram3355 // DW_AT_name ("foo")3356 // DW_AT_low_pc (0x0000000000001000)3357 // DW_AT_high_pc (0x0000000000001050)3358 //3359 // 0x0000006a: DW_TAG_subprogram3360 // DW_AT_name ("bar")3361 // DW_AT_low_pc (0x0000000000002000)3362 // DW_AT_high_pc (0x0000000000002050)3363 //3364 // 0x0000007f: NULL3365 3366 StringRef yamldata = R"(3367 debug_str:3368 - ''3369 - '/tmp/main.cpp'3370 - foo3371 - bar3372 debug_abbrev:3373 - ID: 03374 Table:3375 - Code: 0x13376 Tag: DW_TAG_compile_unit3377 Children: DW_CHILDREN_yes3378 Attributes:3379 - Attribute: DW_AT_name3380 Form: DW_FORM_strp3381 - Attribute: DW_AT_language3382 Form: DW_FORM_udata3383 - Attribute: DW_AT_stmt_list3384 Form: DW_FORM_sec_offset3385 - Code: 0x23386 Tag: DW_TAG_subprogram3387 Children: DW_CHILDREN_no3388 Attributes:3389 - Attribute: DW_AT_name3390 Form: DW_FORM_strp3391 - Attribute: DW_AT_low_pc3392 Form: DW_FORM_addr3393 - Attribute: DW_AT_high_pc3394 Form: DW_FORM_addr3395 debug_info:3396 - Length: 0x3C3397 Version: 43398 AbbrevTableID: 03399 AbbrOffset: 0x03400 AddrSize: 83401 Entries:3402 - AbbrCode: 0x13403 Values:3404 - Value: 0x13405 - Value: 0x23406 - Value: 0x03407 - AbbrCode: 0x23408 Values:3409 - Value: 0xF3410 - Value: 0x10003411 - Value: 0x10503412 - AbbrCode: 0x23413 Values:3414 - Value: 0x133415 - Value: 0x20003416 - Value: 0x20503417 - AbbrCode: 0x03418 - Length: 0x3C3419 Version: 43420 AbbrevTableID: 03421 AbbrOffset: 0x03422 AddrSize: 83423 Entries:3424 - AbbrCode: 0x13425 Values:3426 - Value: 0x13427 - Value: 0x23428 - Value: 0x433429 - AbbrCode: 0x23430 Values:3431 - Value: 0xF3432 - Value: 0x10003433 - Value: 0x10503434 - AbbrCode: 0x23435 Values:3436 - Value: 0x133437 - Value: 0x20003438 - Value: 0x20503439 - AbbrCode: 0x03440 debug_line:3441 - Length: 633442 Version: 23443 PrologueLength: 363444 MinInstLength: 13445 DefaultIsStmt: 13446 LineBase: 2513447 LineRange: 143448 OpcodeBase: 133449 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]3450 IncludeDirs:3451 - '/tmp'3452 Files:3453 - Name: main.cpp3454 DirIdx: 13455 ModTime: 03456 Length: 03457 Opcodes:3458 - Opcode: DW_LNS_extended_op3459 ExtLen: 93460 SubOpcode: DW_LNE_set_address3461 Data: 40963462 - Opcode: DW_LNS_advance_line3463 SData: 93464 Data: 03465 - Opcode: DW_LNS_copy3466 Data: 03467 - Opcode: DW_LNS_advance_pc3468 Data: 803469 - Opcode: DW_LNS_advance_line3470 SData: 13471 Data: 03472 - Opcode: DW_LNS_extended_op3473 ExtLen: 13474 SubOpcode: DW_LNE_end_sequence3475 Data: 03476 - Length: 633477 Version: 23478 PrologueLength: 363479 MinInstLength: 13480 DefaultIsStmt: 13481 LineBase: 2513482 LineRange: 143483 OpcodeBase: 133484 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]3485 IncludeDirs:3486 - '/tmp'3487 Files:3488 - Name: main.cpp3489 DirIdx: 13490 ModTime: 03491 Length: 03492 Opcodes:3493 - Opcode: DW_LNS_extended_op3494 ExtLen: 93495 SubOpcode: DW_LNE_set_address3496 Data: 81923497 - Opcode: DW_LNS_advance_line3498 SData: 193499 Data: 03500 - Opcode: DW_LNS_copy3501 Data: 03502 - Opcode: DW_LNS_advance_pc3503 Data: 803504 - Opcode: DW_LNS_advance_line3505 SData: 13506 Data: 03507 - Opcode: DW_LNS_extended_op3508 ExtLen: 13509 SubOpcode: DW_LNE_end_sequence3510 Data: 03511 )";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 table3535 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 table3544 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 3554TEST(GSYMTest, TestRangeWarnings) {3555 // This example has a single compile unit that has a DW_TAG_subprogram that3556 // has two discontiguous ranges. We will create two FunctionInfo objects for3557 // each range in the function that only contains info for each range. We also3558 // want to verify that we only emit errors and warnings for ranges that3559 // aren't contained in any parent address ranges if this is true. Prior to3560 // this fix we would create two FunctionInfo objects and as each one was3561 // being created we would end up warning about all of the ranges that weren't3562 // 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_unit3566 // DW_AT_name ("/tmp/main.cpp")3567 // DW_AT_language (DW_LANG_C)3568 // DW_AT_stmt_list (0x00000000)3569 //3570 // 0x00000015: DW_TAG_subprogram3571 // DW_AT_name ("foo")3572 // DW_AT_ranges (0x000000003573 // [0x0000000000001000, 0x0000000000001050)3574 // [0x0000000000002000, 0x0000000000002050))3575 //3576 // 0x0000001e: DW_TAG_inlined_subroutine3577 // DW_AT_name ("inline1")3578 // DW_AT_ranges (0x000000303579 // [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_subroutine3585 // DW_AT_name ("inline2")3586 // DW_AT_ranges (0x000000603587 // [0x0000000000001015, 0x0000000000001020)3588 // [0x0000000000002015, 0x0000000000002020))3589 // DW_AT_call_file ("/tmp/inline.h")3590 // DW_AT_call_line (21)3591 //3592 // 0x00000040: NULL3593 //3594 // 0x00000041: NULL3595 //3596 // 0x00000042: NULL3597 3598 StringRef yamldata = R"(3599 debug_str:3600 - ''3601 - '/tmp/main.cpp'3602 - foo3603 - inline13604 - inline23605 debug_abbrev:3606 - ID: 03607 Table:3608 - Code: 0x13609 Tag: DW_TAG_compile_unit3610 Children: DW_CHILDREN_yes3611 Attributes:3612 - Attribute: DW_AT_name3613 Form: DW_FORM_strp3614 - Attribute: DW_AT_language3615 Form: DW_FORM_udata3616 - Attribute: DW_AT_stmt_list3617 Form: DW_FORM_sec_offset3618 - Code: 0x23619 Tag: DW_TAG_subprogram3620 Children: DW_CHILDREN_yes3621 Attributes:3622 - Attribute: DW_AT_name3623 Form: DW_FORM_strp3624 - Attribute: DW_AT_ranges3625 Form: DW_FORM_sec_offset3626 - Code: 0x33627 Tag: DW_TAG_inlined_subroutine3628 Children: DW_CHILDREN_yes3629 Attributes:3630 - Attribute: DW_AT_name3631 Form: DW_FORM_strp3632 - Attribute: DW_AT_ranges3633 Form: DW_FORM_sec_offset3634 - Attribute: DW_AT_call_file3635 Form: DW_FORM_data43636 - Attribute: DW_AT_call_line3637 Form: DW_FORM_data43638 - Code: 0x43639 Tag: DW_TAG_inlined_subroutine3640 Children: DW_CHILDREN_no3641 Attributes:3642 - Attribute: DW_AT_name3643 Form: DW_FORM_strp3644 - Attribute: DW_AT_ranges3645 Form: DW_FORM_sec_offset3646 - Attribute: DW_AT_call_file3647 Form: DW_FORM_data43648 - Attribute: DW_AT_call_line3649 Form: DW_FORM_data43650 debug_ranges:3651 - Offset: 0x03652 AddrSize: 0x83653 Entries:3654 - LowOffset: 0x10003655 HighOffset: 0x10503656 - LowOffset: 0x20003657 HighOffset: 0x20503658 - Offset: 0x303659 AddrSize: 0x83660 Entries:3661 - LowOffset: 0x10103662 HighOffset: 0x10403663 - LowOffset: 0x20103664 HighOffset: 0x20403665 - Offset: 0x603666 AddrSize: 0x83667 Entries:3668 - LowOffset: 0x10153669 HighOffset: 0x10203670 - LowOffset: 0x20153671 HighOffset: 0x20203672 debug_info:3673 - Length: 0x3F3674 Version: 43675 AbbrevTableID: 03676 AbbrOffset: 0x03677 AddrSize: 83678 Entries:3679 - AbbrCode: 0x13680 Values:3681 - Value: 0x13682 - Value: 0x23683 - Value: 0x03684 - AbbrCode: 0x23685 Values:3686 - Value: 0xF3687 - Value: 0x03688 - AbbrCode: 0x33689 Values:3690 - Value: 0x133691 - Value: 0x303692 - Value: 0x13693 - Value: 0xB3694 - AbbrCode: 0x43695 Values:3696 - Value: 0x1B3697 - Value: 0x603698 - Value: 0x23699 - Value: 0x153700 - AbbrCode: 0x03701 - AbbrCode: 0x03702 - AbbrCode: 0x03703 debug_line:3704 - Length: 1203705 Version: 23706 PrologueLength: 483707 MinInstLength: 13708 DefaultIsStmt: 13709 LineBase: 2513710 LineRange: 143711 OpcodeBase: 133712 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]3713 IncludeDirs:3714 - '/tmp'3715 Files:3716 - Name: main.cpp3717 DirIdx: 13718 ModTime: 03719 Length: 03720 - Name: inline.h3721 DirIdx: 13722 ModTime: 03723 Length: 03724 Opcodes:3725 - Opcode: DW_LNS_extended_op3726 ExtLen: 93727 SubOpcode: DW_LNE_set_address3728 Data: 40963729 - Opcode: DW_LNS_advance_line3730 SData: 93731 Data: 03732 - Opcode: DW_LNS_copy3733 Data: 03734 - Opcode: DW_LNS_advance_pc3735 Data: 163736 - Opcode: DW_LNS_set_file3737 Data: 23738 - Opcode: DW_LNS_advance_line3739 SData: 103740 Data: 03741 - Opcode: DW_LNS_copy3742 Data: 03743 - Opcode: DW_LNS_advance_pc3744 Data: 163745 - Opcode: DW_LNS_advance_line3746 SData: 13747 Data: 03748 - Opcode: DW_LNS_copy3749 Data: 03750 - Opcode: DW_LNS_advance_pc3751 Data: 483752 - Opcode: DW_LNS_set_file3753 Data: 13754 - Opcode: DW_LNS_advance_line3755 SData: -103756 Data: 03757 - Opcode: DW_LNS_extended_op3758 ExtLen: 13759 SubOpcode: DW_LNE_end_sequence3760 Data: 03761 - Opcode: DW_LNS_extended_op3762 ExtLen: 93763 SubOpcode: DW_LNE_set_address3764 Data: 81923765 - Opcode: DW_LNS_advance_line3766 SData: 193767 Data: 03768 - Opcode: DW_LNS_copy3769 Data: 03770 - Opcode: DW_LNS_advance_pc3771 Data: 163772 - Opcode: DW_LNS_set_file3773 Data: 23774 - Opcode: DW_LNS_copy3775 Data: 03776 - Opcode: DW_LNS_advance_pc3777 Data: 163778 - Opcode: DW_LNS_advance_line3779 SData: 13780 Data: 03781 - Opcode: DW_LNS_copy3782 Data: 03783 - Opcode: DW_LNS_advance_pc3784 Data: 483785 - Opcode: DW_LNS_set_file3786 Data: 13787 - Opcode: DW_LNS_extended_op3788 ExtLen: 13789 SubOpcode: DW_LNE_end_sequence3790 Data: 03791 )";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 table3815 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 table3824 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 3836TEST(GSYMTest, TestEmptyRangeWarnings) {3837 // This example has a single compile unit that has a DW_TAG_subprogram that3838 // 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 functions3840 // inside of a real function, that we don't end up with inline information3841 // in the GSYM and we don't warn about the inline function's range not being3842 // contined in the parent ranges since it is ok for inline functions to be3843 // elided.3844 //3845 // 0x0000000b: DW_TAG_compile_unit3846 // DW_AT_name ("/tmp/main.cpp")3847 // DW_AT_language (DW_LANG_C)3848 // DW_AT_stmt_list (0x00000000)3849 //3850 // 0x00000015: DW_TAG_subprogram3851 // DW_AT_name ("foo")3852 // DW_AT_low_pc (0x0000000000001000)3853 // DW_AT_high_pc (0x0000000000001050)3854 //3855 // 0x0000002a: DW_TAG_inlined_subroutine3856 // 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: NULL3863 //3864 // 0x00000048: NULL3865 3866 StringRef yamldata = R"(3867 debug_str:3868 - ''3869 - '/tmp/main.cpp'3870 - foo3871 - inline13872 debug_abbrev:3873 - ID: 03874 Table:3875 - Code: 0x13876 Tag: DW_TAG_compile_unit3877 Children: DW_CHILDREN_yes3878 Attributes:3879 - Attribute: DW_AT_name3880 Form: DW_FORM_strp3881 - Attribute: DW_AT_language3882 Form: DW_FORM_udata3883 - Attribute: DW_AT_stmt_list3884 Form: DW_FORM_sec_offset3885 - Code: 0x23886 Tag: DW_TAG_subprogram3887 Children: DW_CHILDREN_yes3888 Attributes:3889 - Attribute: DW_AT_name3890 Form: DW_FORM_strp3891 - Attribute: DW_AT_low_pc3892 Form: DW_FORM_addr3893 - Attribute: DW_AT_high_pc3894 Form: DW_FORM_addr3895 - Code: 0x33896 Tag: DW_TAG_inlined_subroutine3897 Children: DW_CHILDREN_no3898 Attributes:3899 - Attribute: DW_AT_name3900 Form: DW_FORM_strp3901 - Attribute: DW_AT_low_pc3902 Form: DW_FORM_addr3903 - Attribute: DW_AT_high_pc3904 Form: DW_FORM_addr3905 - Attribute: DW_AT_call_file3906 Form: DW_FORM_data43907 - Attribute: DW_AT_call_line3908 Form: DW_FORM_data43909 debug_info:3910 - Length: 0x453911 Version: 43912 AbbrevTableID: 03913 AbbrOffset: 0x03914 AddrSize: 83915 Entries:3916 - AbbrCode: 0x13917 Values:3918 - Value: 0x13919 - Value: 0x23920 - Value: 0x03921 - AbbrCode: 0x23922 Values:3923 - Value: 0xF3924 - Value: 0x10003925 - Value: 0x10503926 - AbbrCode: 0x33927 Values:3928 - Value: 0x133929 - Value: 0x10103930 - Value: 0x10103931 - Value: 0x13932 - Value: 0xB3933 - AbbrCode: 0x03934 - AbbrCode: 0x03935 debug_line:3936 - Length: 893937 Version: 23938 PrologueLength: 483939 MinInstLength: 13940 DefaultIsStmt: 13941 LineBase: 2513942 LineRange: 143943 OpcodeBase: 133944 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]3945 IncludeDirs:3946 - '/tmp'3947 Files:3948 - Name: main.cpp3949 DirIdx: 13950 ModTime: 03951 Length: 03952 - Name: inline.h3953 DirIdx: 13954 ModTime: 03955 Length: 03956 Opcodes:3957 - Opcode: DW_LNS_extended_op3958 ExtLen: 93959 SubOpcode: DW_LNE_set_address3960 Data: 40963961 - Opcode: DW_LNS_advance_line3962 SData: 93963 Data: 03964 - Opcode: DW_LNS_copy3965 Data: 03966 - Opcode: DW_LNS_advance_pc3967 Data: 163968 - Opcode: DW_LNS_set_file3969 Data: 23970 - Opcode: DW_LNS_advance_line3971 SData: 103972 Data: 03973 - Opcode: DW_LNS_copy3974 Data: 03975 - Opcode: DW_LNS_advance_pc3976 Data: 163977 - Opcode: DW_LNS_advance_line3978 SData: 13979 Data: 03980 - Opcode: DW_LNS_copy3981 Data: 03982 - Opcode: DW_LNS_advance_pc3983 Data: 483984 - Opcode: DW_LNS_set_file3985 Data: 13986 - Opcode: DW_LNS_advance_line3987 SData: -103988 Data: 03989 - Opcode: DW_LNS_extended_op3990 ExtLen: 13991 SubOpcode: DW_LNE_end_sequence3992 Data: 03993 )";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 4030TEST(GSYMTest, TestEmptyLinkageName) {4031 // This example has a single compile unit that has a DW_TAG_subprogram that4032 // 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 object4036 //4037 // This was because we would get a valid but empty linkage name and we would4038 // try to use this in the GSYM FunctionInfo and that would cause the error4039 // as the name was empty.4040 //4041 // 0x0000000b: DW_TAG_compile_unit4042 // DW_AT_name ("/tmp/main.cpp")4043 // DW_AT_language (DW_LANG_C)4044 // DW_AT_stmt_list (0x00000000)4045 //4046 // 0x00000015: DW_TAG_subprogram4047 // DW_AT_name ("foo")4048 // DW_AT_linkage_name ("")4049 // DW_AT_low_pc (0x0000000000001000)4050 // DW_AT_high_pc (0x0000000000001050)4051 //4052 // 0x0000002e: NULL4053 4054 4055 StringRef yamldata = R"(4056 debug_str:4057 - ''4058 - '/tmp/main.cpp'4059 - foo4060 - ''4061 debug_abbrev:4062 - ID: 04063 Table:4064 - Code: 0x14065 Tag: DW_TAG_compile_unit4066 Children: DW_CHILDREN_yes4067 Attributes:4068 - Attribute: DW_AT_name4069 Form: DW_FORM_strp4070 - Attribute: DW_AT_language4071 Form: DW_FORM_udata4072 - Attribute: DW_AT_stmt_list4073 Form: DW_FORM_sec_offset4074 - Code: 0x24075 Tag: DW_TAG_subprogram4076 Children: DW_CHILDREN_no4077 Attributes:4078 - Attribute: DW_AT_name4079 Form: DW_FORM_strp4080 - Attribute: DW_AT_linkage_name4081 Form: DW_FORM_strp4082 - Attribute: DW_AT_low_pc4083 Form: DW_FORM_addr4084 - Attribute: DW_AT_high_pc4085 Form: DW_FORM_addr4086 debug_info:4087 - Length: 0x2B4088 Version: 44089 AbbrevTableID: 04090 AbbrOffset: 0x04091 AddrSize: 84092 Entries:4093 - AbbrCode: 0x14094 Values:4095 - Value: 0x14096 - Value: 0x24097 - Value: 0x04098 - AbbrCode: 0x24099 Values:4100 - Value: 0xF4101 - Value: 0x134102 - Value: 0x10004103 - Value: 0x10504104 - AbbrCode: 0x04105 debug_line:4106 - Length: 684107 Version: 24108 PrologueLength: 364109 MinInstLength: 14110 DefaultIsStmt: 14111 LineBase: 2514112 LineRange: 144113 OpcodeBase: 134114 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]4115 IncludeDirs:4116 - '/tmp'4117 Files:4118 - Name: main.cpp4119 DirIdx: 14120 ModTime: 04121 Length: 04122 Opcodes:4123 - Opcode: DW_LNS_extended_op4124 ExtLen: 94125 SubOpcode: DW_LNE_set_address4126 Data: 40964127 - Opcode: DW_LNS_advance_line4128 SData: 94129 Data: 04130 - Opcode: DW_LNS_copy4131 Data: 04132 - Opcode: DW_LNS_advance_pc4133 Data: 2564134 - Opcode: DW_LNS_advance_line4135 SData: 14136 Data: 04137 - Opcode: DW_LNS_copy4138 Data: 04139 - Opcode: DW_LNS_advance_pc4140 Data: 2564141 - Opcode: DW_LNS_extended_op4142 ExtLen: 14143 SubOpcode: DW_LNE_end_sequence4144 Data: 04145 )";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 4181TEST(GSYMTest, TestLineTablesWithEmptyRanges) {4182 // Test that lookups find the right line table entry when there are multiple4183 // line entries with the same address. When we have multiple line table4184 // entries with the same address, we need to pick the last one in the line4185 // table. We do this because a line entry's start address in the defined by4186 // the line table entry's address and the size is determined by the4187 // subtracting the next line table's address. If the current line table4188 // entry's address is the same as the next one, then there is no code4189 // assiciated with the current line table entry and it should be ignored.4190 //4191 // 0x0000000b: DW_TAG_compile_unit4192 // DW_AT_name ("/tmp/main.cpp")4193 // DW_AT_language (DW_LANG_C)4194 // DW_AT_stmt_list (0x00000000)4195 //4196 // 0x00000015: DW_TAG_subprogram4197 // DW_AT_name ("foo")4198 // DW_AT_low_pc (0x0000000000001000)4199 // DW_AT_high_pc (0x0000000000001050)4200 //4201 // 0x0000002a: NULL4202 //4203 // The line table has a duplicate entry at 0x1010:4204 //4205 // Address Line Column File ISA Discriminator Flags4206 // ---------- ------ ------ ------ --- ------------- -------------4207 // 0x00001000 10 0 1 0 0 is_stmt4208 // 0x00001010 11 0 1 0 0 is_stmt4209 // 0x00001010 12 0 1 0 0 is_stmt4210 // 0x00001050 13 0 1 0 0 is_stmt end_sequence4211 4212 StringRef yamldata = R"(4213 debug_str:4214 - ''4215 - '/tmp/main.cpp'4216 - foo4217 debug_abbrev:4218 - ID: 04219 Table:4220 - Code: 0x14221 Tag: DW_TAG_compile_unit4222 Children: DW_CHILDREN_yes4223 Attributes:4224 - Attribute: DW_AT_name4225 Form: DW_FORM_strp4226 - Attribute: DW_AT_language4227 Form: DW_FORM_udata4228 - Attribute: DW_AT_stmt_list4229 Form: DW_FORM_sec_offset4230 - Code: 0x24231 Tag: DW_TAG_subprogram4232 Children: DW_CHILDREN_no4233 Attributes:4234 - Attribute: DW_AT_name4235 Form: DW_FORM_strp4236 - Attribute: DW_AT_low_pc4237 Form: DW_FORM_addr4238 - Attribute: DW_AT_high_pc4239 Form: DW_FORM_addr4240 debug_info:4241 - Length: 0x274242 Version: 44243 AbbrevTableID: 04244 AbbrOffset: 0x04245 AddrSize: 84246 Entries:4247 - AbbrCode: 0x14248 Values:4249 - Value: 0x14250 - Value: 0x24251 - Value: 0x04252 - AbbrCode: 0x24253 Values:4254 - Value: 0xF4255 - Value: 0x10004256 - Value: 0x10504257 - AbbrCode: 0x04258 debug_line:4259 - Length: 714260 Version: 24261 PrologueLength: 364262 MinInstLength: 14263 DefaultIsStmt: 14264 LineBase: 2514265 LineRange: 144266 OpcodeBase: 134267 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]4268 IncludeDirs:4269 - '/tmp'4270 Files:4271 - Name: main.cpp4272 DirIdx: 14273 ModTime: 04274 Length: 04275 Opcodes:4276 - Opcode: DW_LNS_extended_op4277 ExtLen: 94278 SubOpcode: DW_LNE_set_address4279 Data: 40964280 - Opcode: DW_LNS_advance_line4281 SData: 94282 Data: 04283 - Opcode: DW_LNS_copy4284 Data: 04285 - Opcode: DW_LNS_advance_pc4286 Data: 164287 - Opcode: DW_LNS_advance_line4288 SData: 14289 Data: 04290 - Opcode: DW_LNS_copy4291 Data: 04292 - Opcode: DW_LNS_advance_line4293 SData: 14294 Data: 04295 - Opcode: DW_LNS_copy4296 Data: 04297 - Opcode: DW_LNS_advance_pc4298 Data: 644299 - Opcode: DW_LNS_advance_line4300 SData: 14301 Data: 04302 - Opcode: DW_LNS_extended_op4303 ExtLen: 14304 SubOpcode: DW_LNE_end_sequence4305 Data: 04306 )";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 that4342 // matches line 12, the second line entry that also has the address of4343 // 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 4350TEST(GSYMTest, TestHandlingOfInvalidFileIndexes) {4351 // Test that llvm-gsymutil can handle invalid file indexes in the following4352 // cases:4353 // - In line entries in the line table4354 // - When parsing inline entries that have a DW_AT_call_file4355 // - When parsing function dies with no line table entries and it tries to4356 // use the DW_AT_decl_file4357 //4358 //4359 // 0x0000000b: DW_TAG_compile_unit4360 // DW_AT_name ("/tmp/main.cpp")4361 // DW_AT_language (DW_LANG_C)4362 // DW_AT_stmt_list (0x00000000)4363 //4364 // 0x00000015: DW_TAG_subprogram4365 // DW_AT_name ("foo")4366 // DW_AT_low_pc (0x0000000000001000)4367 // DW_AT_high_pc (0x0000000000001050)4368 //4369 // 0x0000002a: DW_TAG_inlined_subroutine4370 // 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_subroutine4377 // DW_AT_name4378 // ("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: NULL4385 //4386 // 0x00000065: DW_TAG_inlined_subroutine4387 // 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_subroutine4394 // DW_AT_name4395 // ("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: NULL4402 //4403 // 0x000000a0: NULL4404 //4405 // 0x000000a1: DW_TAG_subprogram4406 // 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_subprogram4413 // 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: NULL4420 //4421 // The table looks has an entry at address 0x0000000000001010 that has an4422 // invalid file index that needs to be removed.4423 //4424 // Address Line Column File ISA Discriminator Flags4425 // ---------- ------ ------ ------ --- ------------- -------------4426 // 0x00001000 10 0 1 0 0 is_stmt4427 // 0x00001010 11 0 10 0 0 is_stmt4428 // 0x00001020 11 0 1 0 0 is_stmt4429 // 0x00001030 12 0 1 0 0 is_stmt4430 // 0x00001050 12 0 1 0 0 is_stmt end_sequence4431 4432 StringRef yamldata = R"(4433 debug_str:4434 - ''4435 - '/tmp/main.cpp'4436 - foo4437 - inline_with_invalid_call_file4438 - inline_inside_parent_with_invalid_call_file4439 - inline_with_valid_call_file4440 - inline_inside_parent_with_valid_call_file4441 - func_with_valid_decl_file4442 - func_with_invalid_decl_file4443 debug_abbrev:4444 - ID: 04445 Table:4446 - Code: 0x14447 Tag: DW_TAG_compile_unit4448 Children: DW_CHILDREN_yes4449 Attributes:4450 - Attribute: DW_AT_name4451 Form: DW_FORM_strp4452 - Attribute: DW_AT_language4453 Form: DW_FORM_udata4454 - Attribute: DW_AT_stmt_list4455 Form: DW_FORM_sec_offset4456 - Code: 0x24457 Tag: DW_TAG_subprogram4458 Children: DW_CHILDREN_yes4459 Attributes:4460 - Attribute: DW_AT_name4461 Form: DW_FORM_strp4462 - Attribute: DW_AT_low_pc4463 Form: DW_FORM_addr4464 - Attribute: DW_AT_high_pc4465 Form: DW_FORM_addr4466 - Code: 0x34467 Tag: DW_TAG_inlined_subroutine4468 Children: DW_CHILDREN_yes4469 Attributes:4470 - Attribute: DW_AT_name4471 Form: DW_FORM_strp4472 - Attribute: DW_AT_low_pc4473 Form: DW_FORM_addr4474 - Attribute: DW_AT_high_pc4475 Form: DW_FORM_addr4476 - Attribute: DW_AT_call_file4477 Form: DW_FORM_data44478 - Attribute: DW_AT_call_line4479 Form: DW_FORM_data44480 - Code: 0x44481 Tag: DW_TAG_inlined_subroutine4482 Children: DW_CHILDREN_no4483 Attributes:4484 - Attribute: DW_AT_name4485 Form: DW_FORM_strp4486 - Attribute: DW_AT_low_pc4487 Form: DW_FORM_addr4488 - Attribute: DW_AT_high_pc4489 Form: DW_FORM_addr4490 - Attribute: DW_AT_call_file4491 Form: DW_FORM_data44492 - Attribute: DW_AT_call_line4493 Form: DW_FORM_data44494 - Code: 0x54495 Tag: DW_TAG_subprogram4496 Children: DW_CHILDREN_no4497 Attributes:4498 - Attribute: DW_AT_name4499 Form: DW_FORM_strp4500 - Attribute: DW_AT_decl_file4501 Form: DW_FORM_data14502 - Attribute: DW_AT_decl_line4503 Form: DW_FORM_data14504 - Attribute: DW_AT_low_pc4505 Form: DW_FORM_addr4506 - Attribute: DW_AT_high_pc4507 Form: DW_FORM_addr4508 debug_info:4509 - Length: 0xCC4510 Version: 44511 AbbrevTableID: 04512 AbbrOffset: 0x04513 AddrSize: 84514 Entries:4515 - AbbrCode: 0x14516 Values:4517 - Value: 0x14518 - Value: 0x24519 - Value: 0x04520 - AbbrCode: 0x24521 Values:4522 - Value: 0xF4523 - Value: 0x10004524 - Value: 0x10504525 - AbbrCode: 0x34526 Values:4527 - Value: 0x134528 - Value: 0x10104529 - Value: 0x10204530 - Value: 0xA4531 - Value: 0xB4532 - AbbrCode: 0x44533 Values:4534 - Value: 0x314535 - Value: 0x10104536 - Value: 0x10154537 - Value: 0x14538 - Value: 0xC4539 - AbbrCode: 0x04540 - AbbrCode: 0x34541 Values:4542 - Value: 0x5D4543 - Value: 0x10204544 - Value: 0x10304545 - Value: 0x14546 - Value: 0xD4547 - AbbrCode: 0x44548 Values:4549 - Value: 0x794550 - Value: 0x10204551 - Value: 0x10254552 - Value: 0x14553 - Value: 0xE4554 - AbbrCode: 0x04555 - AbbrCode: 0x04556 - AbbrCode: 0x54557 Values:4558 - Value: 0xA34559 - Value: 0x14560 - Value: 0x144561 - Value: 0x20004562 - Value: 0x20504563 - AbbrCode: 0x54564 Values:4565 - Value: 0xBD4566 - Value: 0xA4567 - Value: 0x144568 - Value: 0x30004569 - Value: 0x30504570 - AbbrCode: 0x04571 debug_line:4572 - Length: 784573 Version: 24574 PrologueLength: 364575 MinInstLength: 14576 DefaultIsStmt: 14577 LineBase: 2514578 LineRange: 144579 OpcodeBase: 134580 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]4581 IncludeDirs:4582 - '/tmp'4583 Files:4584 - Name: main.cpp4585 DirIdx: 14586 ModTime: 04587 Length: 04588 Opcodes:4589 - Opcode: DW_LNS_extended_op4590 ExtLen: 94591 SubOpcode: DW_LNE_set_address4592 Data: 40964593 - Opcode: DW_LNS_advance_line4594 SData: 94595 Data: 04596 - Opcode: DW_LNS_copy4597 Data: 04598 - Opcode: DW_LNS_advance_pc4599 Data: 164600 - Opcode: DW_LNS_set_file4601 Data: 104602 - Opcode: DW_LNS_advance_line4603 SData: 14604 Data: 04605 - Opcode: DW_LNS_copy4606 Data: 04607 - Opcode: DW_LNS_advance_pc4608 Data: 164609 - Opcode: DW_LNS_set_file4610 Data: 14611 - Opcode: DW_LNS_copy4612 Data: 04613 - Opcode: DW_LNS_advance_pc4614 Data: 164615 - Opcode: DW_LNS_advance_line4616 SData: 14617 Data: 04618 - Opcode: DW_LNS_copy4619 Data: 04620 - Opcode: DW_LNS_advance_pc4621 Data: 324622 - Opcode: DW_LNS_extended_op4623 ExtLen: 14624 SubOpcode: DW_LNE_end_sequence4625 Data: 04626 )";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 with4658 // 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 of4663 // 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 were4675 // 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 the4686 // line table and the DW_AT_decl_file attribute was invalid so we were not4687 // 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 invalid4701 // 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 4706TEST(GSYMTest, TestLookupsOfOverlappingAndUnequalRanges) {4707 // Test that llvm-gsymutil lookup the correct funtion info when address4708 // ranges overlap. When functions overlap we always want to pick the first4709 // function info when symbolicating if there are multiple entries with the4710 // same address. Previous to this fix we would just binary search the address4711 // table and pick the first function info that matched the address. After4712 // this fix we now always select the first matching entry whose address range4713 // contains the lookup address to ensure we have the most debug info. We have4714 // seen case where the debug info would contain a small range and a symbol4715 // 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 would4717 // pick these latter entries. We want the first entries because they always4718 // have the most debug info.4719 //4720 // To repro this case, we just make some simple DWARF that has two4721 // overlapping ranges and ensure that any lookups between 0x1000 and 0x104f4722 // match "foo", and any ranges between 0x1050 and 0x1fff match "bar".4723 //4724 // 0x0000000b: DW_TAG_compile_unit4725 // DW_AT_name ("/tmp/main.cpp")4726 // DW_AT_language (DW_LANG_C)4727 // DW_AT_stmt_list (0x00000000)4728 //4729 // 0x00000015: DW_TAG_subprogram4730 // DW_AT_name ("foo")4731 // DW_AT_low_pc (0x0000000000001000)4732 // DW_AT_high_pc (0x0000000000001050)4733 //4734 // 0x0000002a: DW_TAG_subprogram4735 // DW_AT_name ("bar")4736 // DW_AT_low_pc (0x0000000000001000)4737 // DW_AT_high_pc (0x0000000000001100)4738 //4739 // 0x0000003f: NULL4740 4741 StringRef yamldata = R"(4742 debug_str:4743 - ''4744 - '/tmp/main.cpp'4745 - foo4746 - bar4747 debug_abbrev:4748 - ID: 04749 Table:4750 - Code: 0x14751 Tag: DW_TAG_compile_unit4752 Children: DW_CHILDREN_yes4753 Attributes:4754 - Attribute: DW_AT_name4755 Form: DW_FORM_strp4756 - Attribute: DW_AT_language4757 Form: DW_FORM_udata4758 - Attribute: DW_AT_stmt_list4759 Form: DW_FORM_sec_offset4760 - Code: 0x24761 Tag: DW_TAG_subprogram4762 Children: DW_CHILDREN_no4763 Attributes:4764 - Attribute: DW_AT_name4765 Form: DW_FORM_strp4766 - Attribute: DW_AT_low_pc4767 Form: DW_FORM_addr4768 - Attribute: DW_AT_high_pc4769 Form: DW_FORM_addr4770 debug_info:4771 - Length: 0x3C4772 Version: 44773 AbbrevTableID: 04774 AbbrOffset: 0x04775 AddrSize: 84776 Entries:4777 - AbbrCode: 0x14778 Values:4779 - Value: 0x14780 - Value: 0x24781 - Value: 0x04782 - AbbrCode: 0x24783 Values:4784 - Value: 0xF4785 - Value: 0x10004786 - Value: 0x10504787 - AbbrCode: 0x24788 Values:4789 - Value: 0x134790 - Value: 0x10004791 - Value: 0x11004792 - AbbrCode: 0x04793 debug_line:4794 - Length: 714795 Version: 24796 PrologueLength: 364797 MinInstLength: 14798 DefaultIsStmt: 14799 LineBase: 2514800 LineRange: 144801 OpcodeBase: 134802 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]4803 IncludeDirs:4804 - '/tmp'4805 Files:4806 - Name: main.cpp4807 DirIdx: 14808 ModTime: 04809 Length: 04810 Opcodes:4811 - Opcode: DW_LNS_extended_op4812 ExtLen: 94813 SubOpcode: DW_LNE_set_address4814 Data: 40964815 - Opcode: DW_LNS_advance_line4816 SData: 94817 Data: 04818 - Opcode: DW_LNS_copy4819 Data: 04820 - Opcode: DW_LNS_advance_pc4821 Data: 164822 - Opcode: DW_LNS_advance_line4823 SData: 14824 Data: 04825 - Opcode: DW_LNS_copy4826 Data: 04827 - Opcode: DW_LNS_advance_line4828 SData: 14829 Data: 04830 - Opcode: DW_LNS_copy4831 Data: 04832 - Opcode: DW_LNS_advance_pc4833 Data: 644834 - Opcode: DW_LNS_advance_line4835 SData: 14836 Data: 04837 - Opcode: DW_LNS_extended_op4838 ExtLen: 14839 SubOpcode: DW_LNE_end_sequence4840 Data: 04841 )";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, we4883 // were using a function that would extract a FunctionInfo object for a4884 // given address which caused us to always dump the first FunctionInfo4885 // entry for a given address. We now dump it correctly using an address4886 // 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 GSYM4893 // 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 invalid4898 // 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 4903TEST(GSYMTest, TestUnableToLocateDWO) {4904 // Test that llvm-gsymutil will not produce "uanble to locate DWO file" for4905 // Apple binaries. Apple uses DW_AT_GNU_dwo_id for non split DWARF purposes4906 // and this makes llvm-gsymutil create warnings and errors.4907 //4908 // 0x0000000b: DW_TAG_compile_unit4909 // DW_AT_name ("main.cpp")4910 // DW_AT_language (DW_LANG_C)4911 // DW_AT_GNU_dwo_id (0xfffffffe)4912 StringRef yamldata = R"(4913 debug_str:4914 - ''4915 - main.cpp4916 debug_abbrev:4917 - ID: 04918 Table:4919 - Code: 0x14920 Tag: DW_TAG_compile_unit4921 Children: DW_CHILDREN_no4922 Attributes:4923 - Attribute: DW_AT_name4924 Form: DW_FORM_strp4925 - Attribute: DW_AT_language4926 Form: DW_FORM_udata4927 - Attribute: DW_AT_GNU_dwo_id4928 Form: DW_FORM_data44929 debug_info:4930 - Length: 0x114931 Version: 44932 AbbrevTableID: 04933 AbbrOffset: 0x04934 AddrSize: 84935 Entries:4936 - AbbrCode: 0x14937 Values:4938 - Value: 0x14939 - Value: 0x24940 - Value: 0xFFFFFFFE4941 )";4942 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata);4943 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded());4944 std::unique_ptr<DWARFContext> DwarfContext =4945 DWARFContext::create(*ErrOrSections, 8);4946 ASSERT_TRUE(DwarfContext.get() != nullptr);4947 std::string errors;4948 raw_string_ostream OS(errors);4949 OutputAggregator OSAgg(&OS);4950 GsymCreator GC;4951 // Make a DWARF transformer that is MachO (Apple) to avoid warnings about4952 // not finding DWO files.4953 DwarfTransformer DT(*DwarfContext, GC, /*LDCS=*/false, /*MachO*/ true);4954 const uint32_t ThreadCount = 1;4955 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());4956 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());4957 4958 // Make sure this warning is not in the binary4959 std::string warn("warning: Unable to retrieve DWO .debug_info section for");4960 EXPECT_TRUE(errors.find(warn) == std::string::npos);4961}4962 4963TEST(GSYMTest, TestDWARFTransformNoErrorForMissingFileDecl) {4964 // Test that if llvm-gsymutil finds a line table for a compile unit and if4965 // there are no matching entries for a function in that compile unit, that4966 // it doesn't print out a error saying that a DIE has an invalid file index4967 // if there is no DW_AT_decl_file attribute.4968 //4969 // 0x0000000b: DW_TAG_compile_unit4970 // DW_AT_name ("main.cpp")4971 // DW_AT_language (DW_LANG_C)4972 // DW_AT_stmt_list (0x00000000)4973 //4974 // 0x00000015: DW_TAG_subprogram4975 // DW_AT_name ("foo")4976 // DW_AT_low_pc (0x0000000000001000)4977 // DW_AT_high_pc (0x0000000000001050)4978 //4979 // 0x0000002a: NULL4980 //4981 // Line table that has entries, but none that match "foo":4982 //4983 // Address Line Column File ISA Discriminator OpIndex Flags4984 // ------------------ ------ ------ ------ --- ------------- ------- -----4985 // 0x0000000000002000 10 0 1 0 0 0 is_stmt4986 // 0x0000000000002050 13 0 1 0 0 0 is_stmt4987 4988 StringRef yamldata = R"(4989 debug_str:4990 - ''4991 - main.cpp4992 debug_abbrev:4993 - ID: 04994 Table:4995 - Code: 0x14996 Tag: DW_TAG_compile_unit4997 Children: DW_CHILDREN_yes4998 Attributes:4999 - Attribute: DW_AT_name5000 Form: DW_FORM_strp5001 - Attribute: DW_AT_language5002 Form: DW_FORM_udata5003 - Attribute: DW_AT_stmt_list5004 Form: DW_FORM_sec_offset5005 - Code: 0x25006 Tag: DW_TAG_subprogram5007 Children: DW_CHILDREN_no5008 Attributes:5009 - Attribute: DW_AT_name5010 Form: DW_FORM_string5011 - Attribute: DW_AT_low_pc5012 Form: DW_FORM_addr5013 - Attribute: DW_AT_high_pc5014 Form: DW_FORM_addr5015 debug_info:5016 - Length: 0x275017 Version: 45018 AbbrevTableID: 05019 AbbrOffset: 0x05020 AddrSize: 85021 Entries:5022 - AbbrCode: 0x15023 Values:5024 - Value: 0x15025 - Value: 0x25026 - Value: 0x05027 - AbbrCode: 0x25028 Values:5029 - Value: 0xDEADBEEFDEADBEEF5030 CStr: foo5031 - Value: 0x10005032 - Value: 0x10505033 - AbbrCode: 0x05034 debug_line:5035 - Length: 585036 Version: 25037 PrologueLength: 315038 MinInstLength: 15039 DefaultIsStmt: 15040 LineBase: 2515041 LineRange: 145042 OpcodeBase: 135043 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]5044 Files:5045 - Name: main.cpp5046 DirIdx: 05047 ModTime: 05048 Length: 05049 Opcodes:5050 - Opcode: DW_LNS_extended_op5051 ExtLen: 95052 SubOpcode: DW_LNE_set_address5053 Data: 81925054 - Opcode: DW_LNS_advance_line5055 SData: 95056 Data: 05057 - Opcode: DW_LNS_copy5058 Data: 05059 - Opcode: DW_LNS_advance_pc5060 Data: 805061 - Opcode: DW_LNS_advance_line5062 SData: 35063 Data: 05064 - Opcode: DW_LNS_extended_op5065 ExtLen: 15066 SubOpcode: DW_LNE_end_sequence5067 Data: 05068 )";5069 auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata);5070 ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded());5071 std::unique_ptr<DWARFContext> DwarfContext =5072 DWARFContext::create(*ErrOrSections, 8);5073 ASSERT_TRUE(DwarfContext.get() != nullptr);5074 std::string errors;5075 raw_string_ostream OS(errors);5076 OutputAggregator OSAgg(&OS);5077 GsymCreator GC;5078 DwarfTransformer DT(*DwarfContext, GC);5079 const uint32_t ThreadCount = 1;5080 ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());5081 ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());5082 5083 // Make sure this warning is not in the binary5084 std::string error_str("error: function DIE at 0x00000015 has an invalid file "5085 "index 4294967295 in its DW_AT_decl_file attribute");5086 EXPECT_TRUE(errors.find(error_str) == std::string::npos);5087}5088