123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302 |
- //===- llvm/unittest/DebugInfo/GSYMTest.cpp -------------------------------===//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is distributed under the University of Illinois Open Source
- // License. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/SmallString.h"
- #include "llvm/DebugInfo/GSYM/Header.h"
- #include "llvm/DebugInfo/GSYM/FileEntry.h"
- #include "llvm/DebugInfo/GSYM/FileWriter.h"
- #include "llvm/DebugInfo/GSYM/FunctionInfo.h"
- #include "llvm/DebugInfo/GSYM/GsymCreator.h"
- #include "llvm/DebugInfo/GSYM/GsymReader.h"
- #include "llvm/DebugInfo/GSYM/InlineInfo.h"
- #include "llvm/DebugInfo/GSYM/Range.h"
- #include "llvm/DebugInfo/GSYM/StringTable.h"
- #include "llvm/Support/DataExtractor.h"
- #include "llvm/Support/Endian.h"
- #include "gtest/gtest.h"
- #include <string>
- using namespace llvm;
- using namespace gsym;
- void checkError(ArrayRef<std::string> ExpectedMsgs, Error Err) {
- ASSERT_TRUE(bool(Err));
- size_t WhichMsg = 0;
- Error Remaining =
- handleErrors(std::move(Err), [&](const ErrorInfoBase &Actual) {
- ASSERT_LT(WhichMsg, ExpectedMsgs.size());
- // Use .str(), because googletest doesn't visualise a StringRef
- // properly.
- EXPECT_EQ(Actual.message(), ExpectedMsgs[WhichMsg++]);
- });
- EXPECT_EQ(WhichMsg, ExpectedMsgs.size());
- EXPECT_FALSE(Remaining);
- }
- void checkError(std::string ExpectedMsg, Error Err) {
- checkError(ArrayRef<std::string>{ExpectedMsg}, std::move(Err));
- }
- TEST(GSYMTest, TestFileEntry) {
- // Make sure default constructed GSYM FileEntry has zeroes in the
- // directory and basename string table indexes.
- FileEntry empty1;
- FileEntry empty2;
- EXPECT_EQ(empty1.Dir, 0u);
- EXPECT_EQ(empty1.Base, 0u);
- // Verify equality operator works
- FileEntry a1(10, 30);
- FileEntry a2(10, 30);
- FileEntry b(10, 40);
- EXPECT_EQ(empty1, empty2);
- EXPECT_EQ(a1, a2);
- EXPECT_NE(a1, b);
- EXPECT_NE(a1, empty1);
- // Test we can use llvm::gsym::FileEntry in llvm::DenseMap.
- DenseMap<FileEntry, uint32_t> EntryToIndex;
- constexpr uint32_t Index1 = 1;
- constexpr uint32_t Index2 = 1;
- auto R = EntryToIndex.insert(std::make_pair(a1, Index1));
- EXPECT_TRUE(R.second);
- EXPECT_EQ(R.first->second, Index1);
- R = EntryToIndex.insert(std::make_pair(a1, Index1));
- EXPECT_FALSE(R.second);
- EXPECT_EQ(R.first->second, Index1);
- R = EntryToIndex.insert(std::make_pair(b, Index2));
- EXPECT_TRUE(R.second);
- EXPECT_EQ(R.first->second, Index2);
- R = EntryToIndex.insert(std::make_pair(a1, Index2));
- EXPECT_FALSE(R.second);
- EXPECT_EQ(R.first->second, Index2);
- }
- TEST(GSYMTest, TestFunctionInfo) {
- // Test GSYM FunctionInfo structs and functionality.
- FunctionInfo invalid;
- EXPECT_FALSE(invalid.isValid());
- EXPECT_FALSE(invalid.hasRichInfo());
- const uint64_t StartAddr = 0x1000;
- const uint64_t EndAddr = 0x1100;
- const uint64_t Size = EndAddr - StartAddr;
- const uint32_t NameOffset = 30;
- FunctionInfo FI(StartAddr, Size, NameOffset);
- EXPECT_TRUE(FI.isValid());
- EXPECT_FALSE(FI.hasRichInfo());
- EXPECT_EQ(FI.startAddress(), StartAddr);
- EXPECT_EQ(FI.endAddress(), EndAddr);
- EXPECT_EQ(FI.size(), Size);
- const uint32_t FileIdx = 1;
- const uint32_t Line = 12;
- FI.OptLineTable = LineTable();
- FI.OptLineTable->push(LineEntry(StartAddr,FileIdx,Line));
- EXPECT_TRUE(FI.hasRichInfo());
- FI.clear();
- EXPECT_FALSE(FI.isValid());
- EXPECT_FALSE(FI.hasRichInfo());
- FunctionInfo A1(0x1000, 0x100, NameOffset);
- FunctionInfo A2(0x1000, 0x100, NameOffset);
- FunctionInfo B;
- // Check == operator
- EXPECT_EQ(A1, A2);
- // Make sure things are not equal if they only differ by start address.
- B = A2;
- B.setStartAddress(0x2000);
- EXPECT_NE(B, A2);
- // Make sure things are not equal if they only differ by size.
- B = A2;
- B.setSize(0x101);
- EXPECT_NE(B, A2);
- // Make sure things are not equal if they only differ by name.
- B = A2;
- B.Name = 60;
- EXPECT_NE(B, A2);
- // Check < operator.
- // Check less than where address differs.
- B = A2;
- B.setStartAddress(A2.startAddress() + 0x1000);
- EXPECT_LT(A1, B);
- // We use the < operator to take a variety of different FunctionInfo
- // structs from a variety of sources: symtab, debug info, runtime info
- // and we sort them and want the sorting to allow us to quickly get the
- // best version of a function info.
- FunctionInfo FISymtab(StartAddr, Size, NameOffset);
- FunctionInfo FIWithLines(StartAddr, Size, NameOffset);
- FIWithLines.OptLineTable = LineTable();
- FIWithLines.OptLineTable->push(LineEntry(StartAddr,FileIdx,Line));
- // Test that a FunctionInfo with just a name and size is less than one
- // that has name, size and any number of line table entries
- EXPECT_LT(FISymtab, FIWithLines);
- FunctionInfo FIWithLinesAndInline = FIWithLines;
- FIWithLinesAndInline.Inline = InlineInfo();
- FIWithLinesAndInline.Inline->Ranges.insert(
- AddressRange(StartAddr, StartAddr + 0x10));
- // Test that a FunctionInfo with name, size, and line entries is less than
- // the same one with valid inline info
- EXPECT_LT(FIWithLines, FIWithLinesAndInline);
- // Test if we have an entry with lines and one with more lines for the same
- // range, the ones with more lines is greater than the one with less.
- FunctionInfo FIWithMoreLines = FIWithLines;
- FIWithMoreLines.OptLineTable->push(LineEntry(StartAddr,FileIdx,Line+5));
- EXPECT_LT(FIWithLines, FIWithMoreLines);
- // Test that if we have the same number of lines we compare the line entries
- // in the FunctionInfo.OptLineTable.Lines vector.
- FunctionInfo FIWithLinesWithHigherAddress = FIWithLines;
- FIWithLinesWithHigherAddress.OptLineTable->get(0).Addr += 0x10;
- EXPECT_LT(FIWithLines, FIWithLinesWithHigherAddress);
- }
- static void TestFunctionInfoDecodeError(llvm::support::endianness ByteOrder,
- std::string Bytes,
- const uint64_t BaseAddr,
- std::string ExpectedErrorMsg) {
- uint8_t AddressSize = 4;
- DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
- llvm::Expected<FunctionInfo> Decoded = FunctionInfo::decode(Data, BaseAddr);
- // Make sure decoding fails.
- ASSERT_FALSE((bool)Decoded);
- // Make sure decoded object is the same as the one we encoded.
- checkError(ExpectedErrorMsg, Decoded.takeError());
- }
- TEST(GSYMTest, TestFunctionInfoDecodeErrors) {
- // Test decoding FunctionInfo objects that ensure we report an appropriate
- // error message.
- const llvm::support::endianness ByteOrder = llvm::support::little;
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- const uint64_t BaseAddr = 0x100;
- TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000000: missing FunctionInfo Size");
- FW.writeU32(0x100); // Function size.
- TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000004: missing FunctionInfo Name");
- // Write out an invalid Name string table offset of zero.
- FW.writeU32(0);
- TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000004: invalid FunctionInfo Name value 0x00000000");
- // Modify the Name to be 0x00000001, which is a valid value.
- FW.fixup32(0x00000001, 4);
- TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000008: missing FunctionInfo InfoType value");
- auto FixupOffset = FW.tell();
- FW.writeU32(1); // InfoType::LineTableInfo.
- TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x0000000c: missing FunctionInfo InfoType length");
- FW.fixup32(4, FixupOffset); // Write an invalid InfoType enumeration value
- FW.writeU32(0); // LineTableInfo InfoType data length.
- TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000008: unsupported InfoType 4");
- }
- static void TestFunctionInfoEncodeError(llvm::support::endianness ByteOrder,
- const FunctionInfo &FI,
- std::string ExpectedErrorMsg) {
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- Expected<uint64_t> ExpectedOffset = FI.encode(FW);
- ASSERT_FALSE(ExpectedOffset);
- checkError(ExpectedErrorMsg, ExpectedOffset.takeError());
- }
- TEST(GSYMTest, TestFunctionInfoEncodeErrors) {
- const uint64_t FuncAddr = 0x1000;
- const uint64_t FuncSize = 0x100;
- const uint32_t InvalidName = 0;
- const uint32_t ValidName = 1;
- FunctionInfo InvalidNameFI(FuncAddr, FuncSize, InvalidName);
- TestFunctionInfoEncodeError(llvm::support::little, InvalidNameFI,
- "attempted to encode invalid FunctionInfo object");
- FunctionInfo InvalidLineTableFI(FuncAddr, FuncSize, ValidName);
- // Empty line tables are not valid. Verify if the encoding of anything
- // in our line table fails, that we see get the error propagated.
- InvalidLineTableFI.OptLineTable = LineTable();
- TestFunctionInfoEncodeError(llvm::support::little, InvalidLineTableFI,
- "attempted to encode invalid LineTable object");
- FunctionInfo InvalidInlineInfoFI(FuncAddr, FuncSize, ValidName);
- // Empty line tables are not valid. Verify if the encoding of anything
- // in our line table fails, that we see get the error propagated.
- InvalidInlineInfoFI.Inline = InlineInfo();
- TestFunctionInfoEncodeError(llvm::support::little, InvalidInlineInfoFI,
- "attempted to encode invalid InlineInfo object");
- }
- static void TestFunctionInfoEncodeDecode(llvm::support::endianness ByteOrder,
- const FunctionInfo &FI) {
- // Test encoding and decoding FunctionInfo objects.
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- llvm::Expected<uint64_t> ExpectedOffset = FI.encode(FW);
- ASSERT_TRUE(bool(ExpectedOffset));
- // Verify we got the encoded offset back from the encode function.
- ASSERT_EQ(ExpectedOffset.get(), 0ULL);
- std::string Bytes(OutStrm.str());
- uint8_t AddressSize = 4;
- DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
- llvm::Expected<FunctionInfo> Decoded = FunctionInfo::decode(Data,
- FI.Range.Start);
- // Make sure decoding succeeded.
- ASSERT_TRUE((bool)Decoded);
- // Make sure decoded object is the same as the one we encoded.
- EXPECT_EQ(FI, Decoded.get());
- }
- static void AddLines(uint64_t FuncAddr, uint32_t FileIdx, FunctionInfo &FI) {
- FI.OptLineTable = LineTable();
- LineEntry Line0(FuncAddr + 0x000, FileIdx, 10);
- LineEntry Line1(FuncAddr + 0x010, FileIdx, 11);
- LineEntry Line2(FuncAddr + 0x100, FileIdx, 1000);
- FI.OptLineTable->push(Line0);
- FI.OptLineTable->push(Line1);
- FI.OptLineTable->push(Line2);
- }
- static void AddInline(uint64_t FuncAddr, uint64_t FuncSize, FunctionInfo &FI) {
- FI.Inline = InlineInfo();
- FI.Inline->Ranges.insert(AddressRange(FuncAddr, FuncAddr + FuncSize));
- InlineInfo Inline1;
- Inline1.Ranges.insert(AddressRange(FuncAddr + 0x10, FuncAddr + 0x30));
- Inline1.Name = 1;
- Inline1.CallFile = 1;
- Inline1.CallLine = 11;
- FI.Inline->Children.push_back(Inline1);
- }
- TEST(GSYMTest, TestFunctionInfoEncoding) {
- constexpr uint64_t FuncAddr = 0x1000;
- constexpr uint64_t FuncSize = 0x100;
- constexpr uint32_t FuncName = 1;
- constexpr uint32_t FileIdx = 1;
- // Make sure that we can encode and decode a FunctionInfo with no line table
- // or inline info.
- FunctionInfo FI(FuncAddr, FuncSize, FuncName);
- TestFunctionInfoEncodeDecode(llvm::support::little, FI);
- TestFunctionInfoEncodeDecode(llvm::support::big, FI);
- // Make sure that we can encode and decode a FunctionInfo with a line table
- // and no inline info.
- FunctionInfo FILines(FuncAddr, FuncSize, FuncName);
- AddLines(FuncAddr, FileIdx, FILines);
- TestFunctionInfoEncodeDecode(llvm::support::little, FILines);
- TestFunctionInfoEncodeDecode(llvm::support::big, FILines);
- // Make sure that we can encode and decode a FunctionInfo with no line table
- // and with inline info.
- FunctionInfo FIInline(FuncAddr, FuncSize, FuncName);
- AddInline(FuncAddr, FuncSize, FIInline);
- TestFunctionInfoEncodeDecode(llvm::support::little, FIInline);
- TestFunctionInfoEncodeDecode(llvm::support::big, FIInline);
- // Make sure that we can encode and decode a FunctionInfo with no line table
- // and with inline info.
- FunctionInfo FIBoth(FuncAddr, FuncSize, FuncName);
- AddLines(FuncAddr, FileIdx, FIBoth);
- AddInline(FuncAddr, FuncSize, FIBoth);
- TestFunctionInfoEncodeDecode(llvm::support::little, FIBoth);
- TestFunctionInfoEncodeDecode(llvm::support::big, FIBoth);
- }
- static void TestInlineInfoEncodeDecode(llvm::support::endianness ByteOrder,
- const InlineInfo &Inline) {
- // Test encoding and decoding InlineInfo objects
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- const uint64_t BaseAddr = Inline.Ranges[0].Start;
- llvm::Error Err = Inline.encode(FW, BaseAddr);
- ASSERT_FALSE(Err);
- std::string Bytes(OutStrm.str());
- uint8_t AddressSize = 4;
- DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
- llvm::Expected<InlineInfo> Decoded = InlineInfo::decode(Data, BaseAddr);
- // Make sure decoding succeeded.
- ASSERT_TRUE((bool)Decoded);
- // Make sure decoded object is the same as the one we encoded.
- EXPECT_EQ(Inline, Decoded.get());
- }
- static void TestInlineInfoDecodeError(llvm::support::endianness ByteOrder,
- std::string Bytes,
- const uint64_t BaseAddr,
- std::string ExpectedErrorMsg) {
- uint8_t AddressSize = 4;
- DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
- llvm::Expected<InlineInfo> Decoded = InlineInfo::decode(Data, BaseAddr);
- // Make sure decoding fails.
- ASSERT_FALSE((bool)Decoded);
- // Make sure decoded object is the same as the one we encoded.
- checkError(ExpectedErrorMsg, Decoded.takeError());
- }
- static void TestInlineInfoEncodeError(llvm::support::endianness ByteOrder,
- const InlineInfo &Inline,
- std::string ExpectedErrorMsg) {
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- const uint64_t BaseAddr = Inline.Ranges.empty() ? 0 : Inline.Ranges[0].Start;
- llvm::Error Err = Inline.encode(FW, BaseAddr);
- checkError(ExpectedErrorMsg, std::move(Err));
- }
- TEST(GSYMTest, TestInlineInfo) {
- // Test InlineInfo structs.
- InlineInfo II;
- EXPECT_FALSE(II.isValid());
- II.Ranges.insert(AddressRange(0x1000, 0x2000));
- // Make sure InlineInfo in valid with just an address range since
- // top level InlineInfo objects have ranges with no name, call file
- // or call line
- EXPECT_TRUE(II.isValid());
- // Make sure InlineInfo isn't after being cleared.
- II.clear();
- EXPECT_FALSE(II.isValid());
- // Create an InlineInfo that contains the following data. The
- // indentation of the address range indicates the parent child
- // relationships of the InlineInfo objects:
- //
- // Variable Range and values
- // =========== ====================================================
- // Root [0x100-0x200) (no name, file, or line)
- // Inline1 [0x150-0x160) Name = 1, File = 1, Line = 11
- // Inline1Sub1 [0x152-0x155) Name = 2, File = 2, Line = 22
- // Inline1Sub2 [0x157-0x158) Name = 3, File = 3, Line = 33
- InlineInfo Root;
- Root.Ranges.insert(AddressRange(0x100, 0x200));
- InlineInfo Inline1;
- Inline1.Ranges.insert(AddressRange(0x150, 0x160));
- Inline1.Name = 1;
- Inline1.CallFile = 1;
- Inline1.CallLine = 11;
- InlineInfo Inline1Sub1;
- Inline1Sub1.Ranges.insert(AddressRange(0x152, 0x155));
- Inline1Sub1.Name = 2;
- Inline1Sub1.CallFile = 2;
- Inline1Sub1.CallLine = 22;
- InlineInfo Inline1Sub2;
- Inline1Sub2.Ranges.insert(AddressRange(0x157, 0x158));
- Inline1Sub2.Name = 3;
- Inline1Sub2.CallFile = 3;
- Inline1Sub2.CallLine = 33;
- Inline1.Children.push_back(Inline1Sub1);
- Inline1.Children.push_back(Inline1Sub2);
- Root.Children.push_back(Inline1);
- // Make sure an address that is out of range won't match
- EXPECT_FALSE(Root.getInlineStack(0x50));
- // Verify that we get no inline stacks for addresses out of [0x100-0x200)
- EXPECT_FALSE(Root.getInlineStack(Root.Ranges[0].Start - 1));
- EXPECT_FALSE(Root.getInlineStack(Root.Ranges[0].End));
- // Verify we get no inline stack entries for addresses that are in
- // [0x100-0x200) but not in [0x150-0x160)
- EXPECT_FALSE(Root.getInlineStack(Inline1.Ranges[0].Start - 1));
- EXPECT_FALSE(Root.getInlineStack(Inline1.Ranges[0].End));
- // Verify we get one inline stack entry for addresses that are in
- // [[0x150-0x160)) but not in [0x152-0x155) or [0x157-0x158)
- auto InlineInfos = Root.getInlineStack(Inline1.Ranges[0].Start);
- ASSERT_TRUE(InlineInfos);
- ASSERT_EQ(InlineInfos->size(), 1u);
- ASSERT_EQ(*InlineInfos->at(0), Inline1);
- InlineInfos = Root.getInlineStack(Inline1.Ranges[0].End - 1);
- EXPECT_TRUE(InlineInfos);
- ASSERT_EQ(InlineInfos->size(), 1u);
- ASSERT_EQ(*InlineInfos->at(0), Inline1);
- // Verify we get two inline stack entries for addresses that are in
- // [0x152-0x155)
- InlineInfos = Root.getInlineStack(Inline1Sub1.Ranges[0].Start);
- EXPECT_TRUE(InlineInfos);
- ASSERT_EQ(InlineInfos->size(), 2u);
- ASSERT_EQ(*InlineInfos->at(0), Inline1Sub1);
- ASSERT_EQ(*InlineInfos->at(1), Inline1);
- InlineInfos = Root.getInlineStack(Inline1Sub1.Ranges[0].End - 1);
- EXPECT_TRUE(InlineInfos);
- ASSERT_EQ(InlineInfos->size(), 2u);
- ASSERT_EQ(*InlineInfos->at(0), Inline1Sub1);
- ASSERT_EQ(*InlineInfos->at(1), Inline1);
- // Verify we get two inline stack entries for addresses that are in
- // [0x157-0x158)
- InlineInfos = Root.getInlineStack(Inline1Sub2.Ranges[0].Start);
- EXPECT_TRUE(InlineInfos);
- ASSERT_EQ(InlineInfos->size(), 2u);
- ASSERT_EQ(*InlineInfos->at(0), Inline1Sub2);
- ASSERT_EQ(*InlineInfos->at(1), Inline1);
- InlineInfos = Root.getInlineStack(Inline1Sub2.Ranges[0].End - 1);
- EXPECT_TRUE(InlineInfos);
- ASSERT_EQ(InlineInfos->size(), 2u);
- ASSERT_EQ(*InlineInfos->at(0), Inline1Sub2);
- ASSERT_EQ(*InlineInfos->at(1), Inline1);
- // Test encoding and decoding InlineInfo objects
- TestInlineInfoEncodeDecode(llvm::support::little, Root);
- TestInlineInfoEncodeDecode(llvm::support::big, Root);
- }
- TEST(GSYMTest, TestInlineInfoEncodeErrors) {
- // Test InlineInfo encoding errors.
- // Test that we get an error when trying to encode an InlineInfo object
- // that has no ranges.
- InlineInfo Empty;
- std::string EmptyErr("attempted to encode invalid InlineInfo object");
- TestInlineInfoEncodeError(llvm::support::little, Empty, EmptyErr);
- TestInlineInfoEncodeError(llvm::support::big, Empty, EmptyErr);
- // Verify that we get an error trying to encode an InlineInfo object that has
- // a child InlineInfo that has no ranges.
- InlineInfo ContainsEmpty;
- ContainsEmpty.Ranges.insert({0x100,200});
- ContainsEmpty.Children.push_back(Empty);
- TestInlineInfoEncodeError(llvm::support::little, ContainsEmpty, EmptyErr);
- TestInlineInfoEncodeError(llvm::support::big, ContainsEmpty, EmptyErr);
- // Verify that we get an error trying to encode an InlineInfo object that has
- // a child whose address range is not contained in the parent address range.
- InlineInfo ChildNotContained;
- std::string ChildNotContainedErr("child range not contained in parent");
- ChildNotContained.Ranges.insert({0x100,200});
- InlineInfo ChildNotContainedChild;
- ChildNotContainedChild.Ranges.insert({0x200,300});
- ChildNotContained.Children.push_back(ChildNotContainedChild);
- TestInlineInfoEncodeError(llvm::support::little, ChildNotContained,
- ChildNotContainedErr);
- TestInlineInfoEncodeError(llvm::support::big, ChildNotContained,
- ChildNotContainedErr);
- }
- TEST(GSYMTest, TestInlineInfoDecodeErrors) {
- // Test decoding InlineInfo objects that ensure we report an appropriate
- // error message.
- const llvm::support::endianness ByteOrder = llvm::support::little;
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- const uint64_t BaseAddr = 0x100;
- TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000000: missing InlineInfo address ranges data");
- AddressRanges Ranges;
- Ranges.insert({BaseAddr, BaseAddr+0x100});
- Ranges.encode(FW, BaseAddr);
- TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000004: missing InlineInfo uint8_t indicating children");
- FW.writeU8(0);
- TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000005: missing InlineInfo uint32_t for name");
- FW.writeU32(0);
- TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000009: missing ULEB128 for InlineInfo call file");
- FW.writeU8(0);
- TestInlineInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x0000000a: missing ULEB128 for InlineInfo call line");
- }
- TEST(GSYMTest, TestLineEntry) {
- // test llvm::gsym::LineEntry structs.
- const uint64_t ValidAddr = 0x1000;
- const uint64_t InvalidFileIdx = 0;
- const uint32_t ValidFileIdx = 1;
- const uint32_t ValidLine = 5;
- LineEntry Invalid;
- EXPECT_FALSE(Invalid.isValid());
- // Make sure that an entry is invalid if it has a bad file index.
- LineEntry BadFile(ValidAddr, InvalidFileIdx, ValidLine);
- EXPECT_FALSE(BadFile.isValid());
- // Test operators
- LineEntry E1(ValidAddr, ValidFileIdx, ValidLine);
- LineEntry E2(ValidAddr, ValidFileIdx, ValidLine);
- LineEntry DifferentAddr(ValidAddr + 1, ValidFileIdx, ValidLine);
- LineEntry DifferentFile(ValidAddr, ValidFileIdx + 1, ValidLine);
- LineEntry DifferentLine(ValidAddr, ValidFileIdx, ValidLine + 1);
- EXPECT_TRUE(E1.isValid());
- EXPECT_EQ(E1, E2);
- EXPECT_NE(E1, DifferentAddr);
- EXPECT_NE(E1, DifferentFile);
- EXPECT_NE(E1, DifferentLine);
- EXPECT_LT(E1, DifferentAddr);
- }
- TEST(GSYMTest, TestRanges) {
- // test llvm::gsym::AddressRange.
- const uint64_t StartAddr = 0x1000;
- const uint64_t EndAddr = 0x2000;
- // Verify constructor and API to ensure it takes start and end address.
- const AddressRange Range(StartAddr, EndAddr);
- EXPECT_EQ(Range.size(), EndAddr - StartAddr);
- // Verify llvm::gsym::AddressRange::contains().
- EXPECT_FALSE(Range.contains(0));
- EXPECT_FALSE(Range.contains(StartAddr - 1));
- EXPECT_TRUE(Range.contains(StartAddr));
- EXPECT_TRUE(Range.contains(EndAddr - 1));
- EXPECT_FALSE(Range.contains(EndAddr));
- EXPECT_FALSE(Range.contains(UINT64_MAX));
- const AddressRange RangeSame(StartAddr, EndAddr);
- const AddressRange RangeDifferentStart(StartAddr + 1, EndAddr);
- const AddressRange RangeDifferentEnd(StartAddr, EndAddr + 1);
- const AddressRange RangeDifferentStartEnd(StartAddr + 1, EndAddr + 1);
- // Test == and != with values that are the same
- EXPECT_EQ(Range, RangeSame);
- EXPECT_FALSE(Range != RangeSame);
- // Test == and != with values that are the different
- EXPECT_NE(Range, RangeDifferentStart);
- EXPECT_NE(Range, RangeDifferentEnd);
- EXPECT_NE(Range, RangeDifferentStartEnd);
- EXPECT_FALSE(Range == RangeDifferentStart);
- EXPECT_FALSE(Range == RangeDifferentEnd);
- EXPECT_FALSE(Range == RangeDifferentStartEnd);
- // Test "bool operator<(const AddressRange &, const AddressRange &)".
- EXPECT_FALSE(Range < RangeSame);
- EXPECT_FALSE(RangeSame < Range);
- EXPECT_LT(Range, RangeDifferentStart);
- EXPECT_LT(Range, RangeDifferentEnd);
- EXPECT_LT(Range, RangeDifferentStartEnd);
- // Test "bool operator<(const AddressRange &, uint64_t)"
- EXPECT_LT(Range.Start, StartAddr + 1);
- // Test "bool operator<(uint64_t, const AddressRange &)"
- EXPECT_LT(StartAddr - 1, Range.Start);
- // Verify llvm::gsym::AddressRange::isContiguousWith() and
- // llvm::gsym::AddressRange::intersects().
- const AddressRange EndsBeforeRangeStart(0, StartAddr - 1);
- const AddressRange EndsAtRangeStart(0, StartAddr);
- const AddressRange OverlapsRangeStart(StartAddr - 1, StartAddr + 1);
- const AddressRange InsideRange(StartAddr + 1, EndAddr - 1);
- const AddressRange OverlapsRangeEnd(EndAddr - 1, EndAddr + 1);
- const AddressRange StartsAtRangeEnd(EndAddr, EndAddr + 0x100);
- const AddressRange StartsAfterRangeEnd(EndAddr + 1, EndAddr + 0x100);
- EXPECT_FALSE(Range.intersects(EndsBeforeRangeStart));
- EXPECT_FALSE(Range.intersects(EndsAtRangeStart));
- EXPECT_TRUE(Range.intersects(OverlapsRangeStart));
- EXPECT_TRUE(Range.intersects(InsideRange));
- EXPECT_TRUE(Range.intersects(OverlapsRangeEnd));
- EXPECT_FALSE(Range.intersects(StartsAtRangeEnd));
- EXPECT_FALSE(Range.intersects(StartsAfterRangeEnd));
- // Test the functions that maintain GSYM address ranges:
- // "bool AddressRange::contains(uint64_t Addr) const;"
- // "void AddressRanges::insert(const AddressRange &R);"
- AddressRanges Ranges;
- Ranges.insert(AddressRange(0x1000, 0x2000));
- Ranges.insert(AddressRange(0x2000, 0x3000));
- Ranges.insert(AddressRange(0x4000, 0x5000));
- EXPECT_FALSE(Ranges.contains(0));
- EXPECT_FALSE(Ranges.contains(0x1000 - 1));
- EXPECT_TRUE(Ranges.contains(0x1000));
- EXPECT_TRUE(Ranges.contains(0x2000));
- EXPECT_TRUE(Ranges.contains(0x4000));
- EXPECT_TRUE(Ranges.contains(0x2000 - 1));
- EXPECT_TRUE(Ranges.contains(0x3000 - 1));
- EXPECT_FALSE(Ranges.contains(0x3000 + 1));
- EXPECT_TRUE(Ranges.contains(0x5000 - 1));
- EXPECT_FALSE(Ranges.contains(0x5000 + 1));
- EXPECT_FALSE(Ranges.contains(UINT64_MAX));
- EXPECT_FALSE(Ranges.contains(AddressRange()));
- EXPECT_FALSE(Ranges.contains(AddressRange(0x1000-1, 0x1000)));
- EXPECT_FALSE(Ranges.contains(AddressRange(0x1000, 0x1000)));
- EXPECT_TRUE(Ranges.contains(AddressRange(0x1000, 0x1000+1)));
- EXPECT_TRUE(Ranges.contains(AddressRange(0x1000, 0x2000)));
- EXPECT_FALSE(Ranges.contains(AddressRange(0x1000, 0x2001)));
- EXPECT_TRUE(Ranges.contains(AddressRange(0x2000, 0x3000)));
- EXPECT_FALSE(Ranges.contains(AddressRange(0x2000, 0x3001)));
- EXPECT_FALSE(Ranges.contains(AddressRange(0x3000, 0x3001)));
- EXPECT_FALSE(Ranges.contains(AddressRange(0x1500, 0x4500)));
- EXPECT_FALSE(Ranges.contains(AddressRange(0x5000, 0x5001)));
- // Verify that intersecting ranges get combined
- Ranges.clear();
- Ranges.insert(AddressRange(0x1100, 0x1F00));
- // Verify a wholy contained range that is added doesn't do anything.
- Ranges.insert(AddressRange(0x1500, 0x1F00));
- EXPECT_EQ(Ranges.size(), 1u);
- EXPECT_EQ(Ranges[0], AddressRange(0x1100, 0x1F00));
- // Verify a range that starts before and intersects gets combined.
- Ranges.insert(AddressRange(0x1000, Ranges[0].Start + 1));
- EXPECT_EQ(Ranges.size(), 1u);
- EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x1F00));
- // Verify a range that starts inside and extends ranges gets combined.
- Ranges.insert(AddressRange(Ranges[0].End - 1, 0x2000));
- EXPECT_EQ(Ranges.size(), 1u);
- EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x2000));
- // Verify that adjacent ranges don't get combined
- Ranges.insert(AddressRange(0x2000, 0x3000));
- EXPECT_EQ(Ranges.size(), 2u);
- EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x2000));
- EXPECT_EQ(Ranges[1], AddressRange(0x2000, 0x3000));
- // Verify if we add an address range that intersects two ranges
- // that they get combined
- Ranges.insert(AddressRange(Ranges[0].End - 1, Ranges[1].Start + 1));
- EXPECT_EQ(Ranges.size(), 1u);
- EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x3000));
- Ranges.insert(AddressRange(0x3000, 0x4000));
- Ranges.insert(AddressRange(0x4000, 0x5000));
- Ranges.insert(AddressRange(0x2000, 0x4500));
- EXPECT_EQ(Ranges.size(), 1u);
- EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x5000));
- }
- TEST(GSYMTest, TestStringTable) {
- StringTable StrTab(StringRef("\0Hello\0World\0", 13));
- // Test extracting strings from a string table.
- EXPECT_EQ(StrTab.getString(0), "");
- EXPECT_EQ(StrTab.getString(1), "Hello");
- EXPECT_EQ(StrTab.getString(7), "World");
- EXPECT_EQ(StrTab.getString(8), "orld");
- // Test pointing to last NULL terminator gets empty string.
- EXPECT_EQ(StrTab.getString(12), "");
- // Test pointing to past end gets empty string.
- EXPECT_EQ(StrTab.getString(13), "");
- }
- static void TestFileWriterHelper(llvm::support::endianness ByteOrder) {
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- const int64_t MinSLEB = INT64_MIN;
- const int64_t MaxSLEB = INT64_MAX;
- const uint64_t MinULEB = 0;
- const uint64_t MaxULEB = UINT64_MAX;
- const uint8_t U8 = 0x10;
- const uint16_t U16 = 0x1122;
- const uint32_t U32 = 0x12345678;
- const uint64_t U64 = 0x33445566778899aa;
- const char *Hello = "hello";
- FW.writeU8(U8);
- FW.writeU16(U16);
- FW.writeU32(U32);
- FW.writeU64(U64);
- FW.alignTo(16);
- const off_t FixupOffset = FW.tell();
- FW.writeU32(0);
- FW.writeSLEB(MinSLEB);
- FW.writeSLEB(MaxSLEB);
- FW.writeULEB(MinULEB);
- FW.writeULEB(MaxULEB);
- FW.writeNullTerminated(Hello);
- // Test Seek, Tell using Fixup32.
- FW.fixup32(U32, FixupOffset);
- std::string Bytes(OutStrm.str());
- uint8_t AddressSize = 4;
- DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
- uint64_t Offset = 0;
- EXPECT_EQ(Data.getU8(&Offset), U8);
- EXPECT_EQ(Data.getU16(&Offset), U16);
- EXPECT_EQ(Data.getU32(&Offset), U32);
- EXPECT_EQ(Data.getU64(&Offset), U64);
- Offset = alignTo(Offset, 16);
- EXPECT_EQ(Data.getU32(&Offset), U32);
- EXPECT_EQ(Data.getSLEB128(&Offset), MinSLEB);
- EXPECT_EQ(Data.getSLEB128(&Offset), MaxSLEB);
- EXPECT_EQ(Data.getULEB128(&Offset), MinULEB);
- EXPECT_EQ(Data.getULEB128(&Offset), MaxULEB);
- EXPECT_EQ(Data.getCStrRef(&Offset), StringRef(Hello));
- }
- TEST(GSYMTest, TestFileWriter) {
- TestFileWriterHelper(llvm::support::little);
- TestFileWriterHelper(llvm::support::big);
- }
- TEST(GSYMTest, TestAddressRangeEncodeDecode) {
- // Test encoding and decoding AddressRange objects. AddressRange objects
- // are always stored as offsets from the a base address. The base address
- // is the FunctionInfo's base address for function level ranges, and is
- // the base address of the parent range for subranges.
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- const auto ByteOrder = llvm::support::endian::system_endianness();
- FileWriter FW(OutStrm, ByteOrder);
- const uint64_t BaseAddr = 0x1000;
- const AddressRange Range1(0x1000, 0x1010);
- const AddressRange Range2(0x1020, 0x1030);
- Range1.encode(FW, BaseAddr);
- Range2.encode(FW, BaseAddr);
- std::string Bytes(OutStrm.str());
- uint8_t AddressSize = 4;
- DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
- AddressRange DecodedRange1, DecodedRange2;
- uint64_t Offset = 0;
- DecodedRange1.decode(Data, BaseAddr, Offset);
- DecodedRange2.decode(Data, BaseAddr, Offset);
- EXPECT_EQ(Range1, DecodedRange1);
- EXPECT_EQ(Range2, DecodedRange2);
- }
- static void TestAddressRangeEncodeDecodeHelper(const AddressRanges &Ranges,
- const uint64_t BaseAddr) {
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- const auto ByteOrder = llvm::support::endian::system_endianness();
- FileWriter FW(OutStrm, ByteOrder);
- Ranges.encode(FW, BaseAddr);
- std::string Bytes(OutStrm.str());
- uint8_t AddressSize = 4;
- DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
- AddressRanges DecodedRanges;
- uint64_t Offset = 0;
- DecodedRanges.decode(Data, BaseAddr, Offset);
- EXPECT_EQ(Ranges, DecodedRanges);
- }
- TEST(GSYMTest, TestAddressRangesEncodeDecode) {
- // Test encoding and decoding AddressRanges. AddressRanges objects contain
- // ranges that are stored as offsets from the a base address. The base address
- // is the FunctionInfo's base address for function level ranges, and is the
- // base address of the parent range for subranges.
- const uint64_t BaseAddr = 0x1000;
- // Test encoding and decoding with no ranges.
- AddressRanges Ranges;
- TestAddressRangeEncodeDecodeHelper(Ranges, BaseAddr);
- // Test encoding and decoding with 1 range.
- Ranges.insert(AddressRange(0x1000, 0x1010));
- TestAddressRangeEncodeDecodeHelper(Ranges, BaseAddr);
- // Test encoding and decoding with multiple ranges.
- Ranges.insert(AddressRange(0x1020, 0x1030));
- Ranges.insert(AddressRange(0x1050, 0x1070));
- TestAddressRangeEncodeDecodeHelper(Ranges, BaseAddr);
- }
- static void TestLineTableHelper(llvm::support::endianness ByteOrder,
- const LineTable <) {
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- const uint64_t BaseAddr = LT[0].Addr;
- llvm::Error Err = LT.encode(FW, BaseAddr);
- ASSERT_FALSE(Err);
- std::string Bytes(OutStrm.str());
- uint8_t AddressSize = 4;
- DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
- llvm::Expected<LineTable> Decoded = LineTable::decode(Data, BaseAddr);
- // Make sure decoding succeeded.
- ASSERT_TRUE((bool)Decoded);
- // Make sure decoded object is the same as the one we encoded.
- EXPECT_EQ(LT, Decoded.get());
- }
- TEST(GSYMTest, TestLineTable) {
- const uint64_t StartAddr = 0x1000;
- const uint32_t FileIdx = 1;
- LineTable LT;
- LineEntry Line0(StartAddr+0x000, FileIdx, 10);
- LineEntry Line1(StartAddr+0x010, FileIdx, 11);
- LineEntry Line2(StartAddr+0x100, FileIdx, 1000);
- ASSERT_TRUE(LT.empty());
- ASSERT_EQ(LT.size(), (size_t)0);
- LT.push(Line0);
- ASSERT_EQ(LT.size(), (size_t)1);
- LT.push(Line1);
- LT.push(Line2);
- LT.push(LineEntry(StartAddr+0x120, FileIdx, 900));
- LT.push(LineEntry(StartAddr+0x120, FileIdx, 2000));
- LT.push(LineEntry(StartAddr+0x121, FileIdx, 2001));
- LT.push(LineEntry(StartAddr+0x122, FileIdx, 2002));
- LT.push(LineEntry(StartAddr+0x123, FileIdx, 2003));
- ASSERT_FALSE(LT.empty());
- ASSERT_EQ(LT.size(), (size_t)8);
- // Test operator[].
- ASSERT_EQ(LT[0], Line0);
- ASSERT_EQ(LT[1], Line1);
- ASSERT_EQ(LT[2], Line2);
- // Test encoding and decoding line tables.
- TestLineTableHelper(llvm::support::little, LT);
- TestLineTableHelper(llvm::support::big, LT);
- // Verify the clear method works as expected.
- LT.clear();
- ASSERT_TRUE(LT.empty());
- ASSERT_EQ(LT.size(), (size_t)0);
- LineTable LT1;
- LineTable LT2;
- // Test that two empty line tables are equal and neither are less than
- // each other.
- ASSERT_EQ(LT1, LT2);
- ASSERT_FALSE(LT1 < LT2);
- ASSERT_FALSE(LT2 < LT2);
- // Test that a line table with less number of line entries is less than a
- // line table with more line entries and that they are not equal.
- LT2.push(Line0);
- ASSERT_LT(LT1, LT2);
- ASSERT_NE(LT1, LT2);
- // Test that two line tables with the same entries are equal.
- LT1.push(Line0);
- ASSERT_EQ(LT1, LT2);
- ASSERT_FALSE(LT1 < LT2);
- ASSERT_FALSE(LT2 < LT2);
- }
- static void TestLineTableDecodeError(llvm::support::endianness ByteOrder,
- std::string Bytes,
- const uint64_t BaseAddr,
- std::string ExpectedErrorMsg) {
- uint8_t AddressSize = 4;
- DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
- llvm::Expected<LineTable> Decoded = LineTable::decode(Data, BaseAddr);
- // Make sure decoding fails.
- ASSERT_FALSE((bool)Decoded);
- // Make sure decoded object is the same as the one we encoded.
- checkError(ExpectedErrorMsg, Decoded.takeError());
- }
- TEST(GSYMTest, TestLineTableDecodeErrors) {
- // Test decoding InlineInfo objects that ensure we report an appropriate
- // error message.
- const llvm::support::endianness ByteOrder = llvm::support::little;
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- const uint64_t BaseAddr = 0x100;
- TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000000: missing LineTable MinDelta");
- FW.writeU8(1); // MinDelta (ULEB)
- TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000001: missing LineTable MaxDelta");
- FW.writeU8(10); // MaxDelta (ULEB)
- TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000002: missing LineTable FirstLine");
- FW.writeU8(20); // FirstLine (ULEB)
- TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000003: EOF found before EndSequence");
- // Test a SetFile with the argument missing from the stream
- FW.writeU8(1); // SetFile opcode (uint8_t)
- TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000004: EOF found before SetFile value");
- FW.writeU8(5); // SetFile value as index (ULEB)
- // Test a AdvancePC with the argument missing from the stream
- FW.writeU8(2); // AdvancePC opcode (uint8_t)
- TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000006: EOF found before AdvancePC value");
- FW.writeU8(20); // AdvancePC value as offset (ULEB)
- // Test a AdvancePC with the argument missing from the stream
- FW.writeU8(3); // AdvanceLine opcode (uint8_t)
- TestLineTableDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
- "0x00000008: EOF found before AdvanceLine value");
- FW.writeU8(20); // AdvanceLine value as offset (LLEB)
- }
- TEST(GSYMTest, TestLineTableEncodeErrors) {
- const uint64_t BaseAddr = 0x1000;
- const uint32_t FileIdx = 1;
- const llvm::support::endianness ByteOrder = llvm::support::little;
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- LineTable LT;
- checkError("attempted to encode invalid LineTable object",
- LT.encode(FW, BaseAddr));
- // Try to encode a line table where a line entry has an address that is less
- // than BaseAddr and verify we get an appropriate error.
- LineEntry Line0(BaseAddr+0x000, FileIdx, 10);
- LineEntry Line1(BaseAddr+0x010, FileIdx, 11);
- LT.push(Line0);
- LT.push(Line1);
- checkError("LineEntry has address 0x1000 which is less than the function "
- "start address 0x1010", LT.encode(FW, BaseAddr+0x10));
- LT.clear();
- // Try to encode a line table where a line entries has an address that is less
- // than BaseAddr and verify we get an appropriate error.
- LT.push(Line1);
- LT.push(Line0);
- checkError("LineEntry in LineTable not in ascending order",
- LT.encode(FW, BaseAddr));
- LT.clear();
- }
- static void TestHeaderEncodeError(const Header &H,
- std::string ExpectedErrorMsg) {
- const support::endianness ByteOrder = llvm::support::little;
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- llvm::Error Err = H.encode(FW);
- checkError(ExpectedErrorMsg, std::move(Err));
- }
- static void TestHeaderDecodeError(std::string Bytes,
- std::string ExpectedErrorMsg) {
- const support::endianness ByteOrder = llvm::support::little;
- uint8_t AddressSize = 4;
- DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
- llvm::Expected<Header> Decoded = Header::decode(Data);
- // Make sure decoding fails.
- ASSERT_FALSE((bool)Decoded);
- // Make sure decoded object is the same as the one we encoded.
- checkError(ExpectedErrorMsg, Decoded.takeError());
- }
- // Populate a GSYM header with valid values.
- static void InitHeader(Header &H) {
- H.Magic = GSYM_MAGIC;
- H.Version = GSYM_VERSION;
- H.AddrOffSize = 4;
- H.UUIDSize = 16;
- H.BaseAddress = 0x1000;
- H.NumAddresses = 1;
- H.StrtabOffset= 0x2000;
- H.StrtabSize = 0x1000;
- for (size_t i=0; i<GSYM_MAX_UUID_SIZE; ++i) {
- if (i < H.UUIDSize)
- H.UUID[i] = i;
- else
- H.UUID[i] = 0;
- }
- }
- TEST(GSYMTest, TestHeaderEncodeErrors) {
- Header H;
- InitHeader(H);
- H.Magic = 12;
- TestHeaderEncodeError(H, "invalid GSYM magic 0x0000000c");
- InitHeader(H);
- H.Version = 12;
- TestHeaderEncodeError(H, "unsupported GSYM version 12");
- InitHeader(H);
- H.AddrOffSize = 12;
- TestHeaderEncodeError(H, "invalid address offset size 12");
- InitHeader(H);
- H.UUIDSize = 128;
- TestHeaderEncodeError(H, "invalid UUID size 128");
- }
- TEST(GSYMTest, TestHeaderDecodeErrors) {
- const llvm::support::endianness ByteOrder = llvm::support::little;
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- Header H;
- InitHeader(H);
- llvm::Error Err = H.encode(FW);
- ASSERT_FALSE(Err);
- FW.fixup32(12, offsetof(Header, Magic));
- TestHeaderDecodeError(OutStrm.str(), "invalid GSYM magic 0x0000000c");
- FW.fixup32(GSYM_MAGIC, offsetof(Header, Magic));
- FW.fixup32(12, offsetof(Header, Version));
- TestHeaderDecodeError(OutStrm.str(), "unsupported GSYM version 12");
- FW.fixup32(GSYM_VERSION, offsetof(Header, Version));
- FW.fixup32(12, offsetof(Header, AddrOffSize));
- TestHeaderDecodeError(OutStrm.str(), "invalid address offset size 12");
- FW.fixup32(4, offsetof(Header, AddrOffSize));
- FW.fixup32(128, offsetof(Header, UUIDSize));
- TestHeaderDecodeError(OutStrm.str(), "invalid UUID size 128");
- }
- static void TestHeaderEncodeDecode(const Header &H,
- support::endianness ByteOrder) {
- uint8_t AddressSize = 4;
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- llvm::Error Err = H.encode(FW);
- ASSERT_FALSE(Err);
- std::string Bytes(OutStrm.str());
- DataExtractor Data(Bytes, ByteOrder == llvm::support::little, AddressSize);
- llvm::Expected<Header> Decoded = Header::decode(Data);
- // Make sure decoding succeeded.
- ASSERT_TRUE((bool)Decoded);
- EXPECT_EQ(H, Decoded.get());
- }
- TEST(GSYMTest, TestHeaderEncodeDecode) {
- Header H;
- InitHeader(H);
- TestHeaderEncodeDecode(H, llvm::support::little);
- TestHeaderEncodeDecode(H, llvm::support::big);
- }
- static void TestGsymCreatorEncodeError(llvm::support::endianness ByteOrder,
- const GsymCreator &GC,
- std::string ExpectedErrorMsg) {
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- llvm::Error Err = GC.encode(FW);
- ASSERT_TRUE(bool(Err));
- checkError(ExpectedErrorMsg, std::move(Err));
- }
- TEST(GSYMTest, TestGsymCreatorEncodeErrors) {
- const uint8_t ValidUUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
- 14, 15, 16};
- const uint8_t InvalidUUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
- 14, 15, 16, 17, 18, 19, 20, 21};
- // Verify we get an error when trying to encode an GsymCreator with no
- // function infos. We shouldn't be saving a GSYM file in this case since
- // there is nothing inside of it.
- GsymCreator GC;
- TestGsymCreatorEncodeError(llvm::support::little, GC,
- "no functions to encode");
- const uint64_t FuncAddr = 0x1000;
- const uint64_t FuncSize = 0x100;
- const uint32_t FuncName = GC.insertString("foo");
- // Verify we get an error trying to encode a GsymCreator that isn't
- // finalized.
- GC.addFunctionInfo(FunctionInfo(FuncAddr, FuncSize, FuncName));
- TestGsymCreatorEncodeError(llvm::support::little, GC,
- "GsymCreator wasn't finalized prior to encoding");
- std::string finalizeIssues;
- raw_string_ostream OS(finalizeIssues);
- llvm::Error finalizeErr = GC.finalize(OS);
- ASSERT_FALSE(bool(finalizeErr));
- finalizeErr = GC.finalize(OS);
- ASSERT_TRUE(bool(finalizeErr));
- checkError("already finalized", std::move(finalizeErr));
- // Verify we get an error trying to encode a GsymCreator with a UUID that is
- // too long.
- GC.setUUID(InvalidUUID);
- TestGsymCreatorEncodeError(llvm::support::little, GC,
- "invalid UUID size 21");
- GC.setUUID(ValidUUID);
- // Verify errors are propagated when we try to encoding an invalid line
- // table.
- GC.forEachFunctionInfo([](FunctionInfo &FI) -> bool {
- FI.OptLineTable = LineTable(); // Invalid line table.
- return false; // Stop iterating
- });
- TestGsymCreatorEncodeError(llvm::support::little, GC,
- "attempted to encode invalid LineTable object");
- // Verify errors are propagated when we try to encoding an invalid inline
- // info.
- GC.forEachFunctionInfo([](FunctionInfo &FI) -> bool {
- FI.OptLineTable = llvm::None;
- FI.Inline = InlineInfo(); // Invalid InlineInfo.
- return false; // Stop iterating
- });
- TestGsymCreatorEncodeError(llvm::support::little, GC,
- "attempted to encode invalid InlineInfo object");
- }
- static void Compare(const GsymCreator &GC, const GsymReader &GR) {
- // Verify that all of the data in a GsymCreator is correctly decoded from
- // a GsymReader. To do this, we iterator over
- GC.forEachFunctionInfo([&](const FunctionInfo &FI) -> bool {
- auto DecodedFI = GR.getFunctionInfo(FI.Range.Start);
- EXPECT_TRUE(bool(DecodedFI));
- EXPECT_EQ(FI, *DecodedFI);
- return true; // Keep iterating over all FunctionInfo objects.
- });
- }
- static void TestEncodeDecode(const GsymCreator &GC,
- support::endianness ByteOrder, uint16_t Version,
- uint8_t AddrOffSize, uint64_t BaseAddress,
- uint32_t NumAddresses, ArrayRef<uint8_t> UUID) {
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- llvm::Error Err = GC.encode(FW);
- ASSERT_FALSE((bool)Err);
- Expected<GsymReader> GR = GsymReader::copyBuffer(OutStrm.str());
- ASSERT_TRUE(bool(GR));
- const Header &Hdr = GR->getHeader();
- EXPECT_EQ(Hdr.Version, Version);
- EXPECT_EQ(Hdr.AddrOffSize, AddrOffSize);
- EXPECT_EQ(Hdr.UUIDSize, UUID.size());
- EXPECT_EQ(Hdr.BaseAddress, BaseAddress);
- EXPECT_EQ(Hdr.NumAddresses, NumAddresses);
- EXPECT_EQ(ArrayRef<uint8_t>(Hdr.UUID, Hdr.UUIDSize), UUID);
- Compare(GC, GR.get());
- }
- TEST(GSYMTest, TestGsymCreator1ByteAddrOffsets) {
- uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
- GsymCreator GC;
- GC.setUUID(UUID);
- constexpr uint64_t BaseAddr = 0x1000;
- constexpr uint8_t AddrOffSize = 1;
- const uint32_t Func1Name = GC.insertString("foo");
- const uint32_t Func2Name = GC.insertString("bar");
- GC.addFunctionInfo(FunctionInfo(BaseAddr+0x00, 0x10, Func1Name));
- GC.addFunctionInfo(FunctionInfo(BaseAddr+0x20, 0x10, Func2Name));
- Error Err = GC.finalize(llvm::nulls());
- ASSERT_FALSE(Err);
- TestEncodeDecode(GC, llvm::support::little,
- GSYM_VERSION,
- AddrOffSize,
- BaseAddr,
- 2, // NumAddresses
- ArrayRef<uint8_t>(UUID));
- TestEncodeDecode(GC, llvm::support::big,
- GSYM_VERSION,
- AddrOffSize,
- BaseAddr,
- 2, // NumAddresses
- ArrayRef<uint8_t>(UUID));
- }
- TEST(GSYMTest, TestGsymCreator2ByteAddrOffsets) {
- uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
- GsymCreator GC;
- GC.setUUID(UUID);
- constexpr uint64_t BaseAddr = 0x1000;
- constexpr uint8_t AddrOffSize = 2;
- const uint32_t Func1Name = GC.insertString("foo");
- const uint32_t Func2Name = GC.insertString("bar");
- GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name));
- GC.addFunctionInfo(FunctionInfo(BaseAddr+0x200, 0x100, Func2Name));
- Error Err = GC.finalize(llvm::nulls());
- ASSERT_FALSE(Err);
- TestEncodeDecode(GC, llvm::support::little,
- GSYM_VERSION,
- AddrOffSize,
- BaseAddr,
- 2, // NumAddresses
- ArrayRef<uint8_t>(UUID));
- TestEncodeDecode(GC, llvm::support::big,
- GSYM_VERSION,
- AddrOffSize,
- BaseAddr,
- 2, // NumAddresses
- ArrayRef<uint8_t>(UUID));
- }
- TEST(GSYMTest, TestGsymCreator4ByteAddrOffsets) {
- uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
- GsymCreator GC;
- GC.setUUID(UUID);
- constexpr uint64_t BaseAddr = 0x1000;
- constexpr uint8_t AddrOffSize = 4;
- const uint32_t Func1Name = GC.insertString("foo");
- const uint32_t Func2Name = GC.insertString("bar");
- GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name));
- GC.addFunctionInfo(FunctionInfo(BaseAddr+0x20000, 0x100, Func2Name));
- Error Err = GC.finalize(llvm::nulls());
- ASSERT_FALSE(Err);
- TestEncodeDecode(GC, llvm::support::little,
- GSYM_VERSION,
- AddrOffSize,
- BaseAddr,
- 2, // NumAddresses
- ArrayRef<uint8_t>(UUID));
- TestEncodeDecode(GC, llvm::support::big,
- GSYM_VERSION,
- AddrOffSize,
- BaseAddr,
- 2, // NumAddresses
- ArrayRef<uint8_t>(UUID));
- }
- TEST(GSYMTest, TestGsymCreator8ByteAddrOffsets) {
- uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
- GsymCreator GC;
- GC.setUUID(UUID);
- constexpr uint64_t BaseAddr = 0x1000;
- constexpr uint8_t AddrOffSize = 8;
- const uint32_t Func1Name = GC.insertString("foo");
- const uint32_t Func2Name = GC.insertString("bar");
- GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name));
- GC.addFunctionInfo(FunctionInfo(BaseAddr+0x100000000, 0x100, Func2Name));
- Error Err = GC.finalize(llvm::nulls());
- ASSERT_FALSE(Err);
- TestEncodeDecode(GC, llvm::support::little,
- GSYM_VERSION,
- AddrOffSize,
- BaseAddr,
- 2, // NumAddresses
- ArrayRef<uint8_t>(UUID));
- TestEncodeDecode(GC, llvm::support::big,
- GSYM_VERSION,
- AddrOffSize,
- BaseAddr,
- 2, // NumAddresses
- ArrayRef<uint8_t>(UUID));
- }
- static void VerifyFunctionInfo(const GsymReader &GR, uint64_t Addr,
- const FunctionInfo &FI) {
- auto ExpFI = GR.getFunctionInfo(Addr);
- ASSERT_TRUE(bool(ExpFI));
- ASSERT_EQ(FI, ExpFI.get());
- }
- static void VerifyFunctionInfoError(const GsymReader &GR, uint64_t Addr,
- std::string ErrMessage) {
- auto ExpFI = GR.getFunctionInfo(Addr);
- ASSERT_FALSE(bool(ExpFI));
- checkError(ErrMessage, ExpFI.takeError());
- }
- TEST(GSYMTest, TestGsymReader) {
- uint8_t UUID[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
- GsymCreator GC;
- GC.setUUID(UUID);
- constexpr uint64_t BaseAddr = 0x1000;
- constexpr uint64_t Func1Addr = BaseAddr;
- constexpr uint64_t Func2Addr = BaseAddr+0x20;
- constexpr uint64_t FuncSize = 0x10;
- const uint32_t Func1Name = GC.insertString("foo");
- const uint32_t Func2Name = GC.insertString("bar");
- const auto ByteOrder = support::endian::system_endianness();
- GC.addFunctionInfo(FunctionInfo(Func1Addr, FuncSize, Func1Name));
- GC.addFunctionInfo(FunctionInfo(Func2Addr, FuncSize, Func2Name));
- Error FinalizeErr = GC.finalize(llvm::nulls());
- ASSERT_FALSE(FinalizeErr);
- SmallString<512> Str;
- raw_svector_ostream OutStrm(Str);
- FileWriter FW(OutStrm, ByteOrder);
- llvm::Error Err = GC.encode(FW);
- ASSERT_FALSE((bool)Err);
- if (auto ExpectedGR = GsymReader::copyBuffer(OutStrm.str())) {
- const GsymReader &GR = ExpectedGR.get();
- VerifyFunctionInfoError(GR, Func1Addr-1, "address 0xfff not in GSYM");
- FunctionInfo Func1(Func1Addr, FuncSize, Func1Name);
- VerifyFunctionInfo(GR, Func1Addr, Func1);
- VerifyFunctionInfo(GR, Func1Addr+1, Func1);
- VerifyFunctionInfo(GR, Func1Addr+FuncSize-1, Func1);
- VerifyFunctionInfoError(GR, Func1Addr+FuncSize,
- "address 0x1010 not in GSYM");
- VerifyFunctionInfoError(GR, Func2Addr-1, "address 0x101f not in GSYM");
- FunctionInfo Func2(Func2Addr, FuncSize, Func2Name);
- VerifyFunctionInfo(GR, Func2Addr, Func2);
- VerifyFunctionInfo(GR, Func2Addr+1, Func2);
- VerifyFunctionInfo(GR, Func2Addr+FuncSize-1, Func2);
- VerifyFunctionInfoError(GR, Func2Addr+FuncSize,
- "address 0x1030 not in GSYM");
- }
- }
|