diff options
Diffstat (limited to 'tools/profiler/tests/gtest')
-rw-r--r-- | tools/profiler/tests/gtest/LulTest.cpp | 51 | ||||
-rw-r--r-- | tools/profiler/tests/gtest/LulTestDwarf.cpp | 2597 | ||||
-rw-r--r-- | tools/profiler/tests/gtest/LulTestInfrastructure.cpp | 491 | ||||
-rw-r--r-- | tools/profiler/tests/gtest/LulTestInfrastructure.h | 666 | ||||
-rw-r--r-- | tools/profiler/tests/gtest/ThreadProfileTest.cpp | 75 | ||||
-rw-r--r-- | tools/profiler/tests/gtest/moz.build | 30 |
6 files changed, 0 insertions, 3910 deletions
diff --git a/tools/profiler/tests/gtest/LulTest.cpp b/tools/profiler/tests/gtest/LulTest.cpp deleted file mode 100644 index 8a165ab34..000000000 --- a/tools/profiler/tests/gtest/LulTest.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "gtest/gtest.h" -#include "mozilla/Atomics.h" -#include "LulMain.h" -#include "GeckoProfiler.h" // for TracingMetadata -#include "platform-linux-lul.h" // for read_procmaps - -// Set this to 0 to make LUL be completely silent during tests. -// Set it to 1 to get logging output from LUL, presumably for -// the purpose of debugging it. -#define DEBUG_LUL_TEST 0 - -// LUL needs a callback for its logging sink. -static void -gtest_logging_sink_for_LulIntegration(const char* str) { - if (DEBUG_LUL_TEST == 0) { - return; - } - // Ignore any trailing \n, since LOG will add one anyway. - size_t n = strlen(str); - if (n > 0 && str[n-1] == '\n') { - char* tmp = strdup(str); - tmp[n-1] = 0; - fprintf(stderr, "LUL-in-gtest: %s\n", tmp); - free(tmp); - } else { - fprintf(stderr, "LUL-in-gtest: %s\n", str); - } -} - -TEST(LulIntegration, unwind_consistency) { - // Set up LUL and get it to read unwind info for libxul.so, which is - // all we care about here, plus (incidentally) practically every - // other object in the process too. - lul::LUL* lul = new lul::LUL(gtest_logging_sink_for_LulIntegration); - read_procmaps(lul); - - // Run unwind tests and receive information about how many there - // were and how many were successful. - lul->EnableUnwinding(); - int nTests = 0, nTestsPassed = 0; - RunLulUnitTests(&nTests, &nTestsPassed, lul); - EXPECT_TRUE(nTests == 6) << "Unexpected number of tests"; - EXPECT_TRUE(nTestsPassed == nTests) << "Not all tests passed"; - - delete lul; -} diff --git a/tools/profiler/tests/gtest/LulTestDwarf.cpp b/tools/profiler/tests/gtest/LulTestDwarf.cpp deleted file mode 100644 index 5cfd71fd4..000000000 --- a/tools/profiler/tests/gtest/LulTestDwarf.cpp +++ /dev/null @@ -1,2597 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "gtest/gtest.h" -#include "gmock/gmock.h" -#include "LulCommonExt.h" -#include "LulDwarfExt.h" -#include "LulDwarfInt.h" -#include "LulTestInfrastructure.h" - -using testing::Test; -using testing::Return; -using testing::Sequence; -using testing::InSequence; -using testing::_; -using lul_test::CFISection; -using lul_test::test_assembler::kBigEndian; -using lul_test::test_assembler::kLittleEndian; -using lul_test::test_assembler::Label; - -#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section) /**/ -#define PERHAPS_WRITE_EH_FRAME_FILE(name, section) /**/ - -// Set this to 0 to make LUL be completely silent during tests. -// Set it to 1 to get logging output from LUL, presumably for -// the purpose of debugging it. -#define DEBUG_LUL_TEST_DWARF 0 - -// LUL needs a callback for its logging sink. -static void -gtest_logging_sink_for_LulTestDwarf(const char* str) { - if (DEBUG_LUL_TEST_DWARF == 0) { - return; - } - // Ignore any trailing \n, since LOG will add one anyway. - size_t n = strlen(str); - if (n > 0 && str[n-1] == '\n') { - char* tmp = strdup(str); - tmp[n-1] = 0; - fprintf(stderr, "LUL-in-gtest: %s\n", tmp); - free(tmp); - } else { - fprintf(stderr, "LUL-in-gtest: %s\n", str); - } -} - -namespace lul { - -class MockCallFrameInfoHandler : public CallFrameInfo::Handler { - public: - MOCK_METHOD6(Entry, bool(size_t offset, uint64 address, uint64 length, - uint8 version, const std::string &augmentation, - unsigned return_address)); - MOCK_METHOD2(UndefinedRule, bool(uint64 address, int reg)); - MOCK_METHOD2(SameValueRule, bool(uint64 address, int reg)); - MOCK_METHOD4(OffsetRule, bool(uint64 address, int reg, int base_register, - long offset)); - MOCK_METHOD4(ValOffsetRule, bool(uint64 address, int reg, int base_register, - long offset)); - MOCK_METHOD3(RegisterRule, bool(uint64 address, int reg, int base_register)); - MOCK_METHOD3(ExpressionRule, bool(uint64 address, int reg, - const std::string &expression)); - MOCK_METHOD3(ValExpressionRule, bool(uint64 address, int reg, - const std::string &expression)); - MOCK_METHOD0(End, bool()); - MOCK_METHOD2(PersonalityRoutine, bool(uint64 address, bool indirect)); - MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64 address, bool indirect)); - MOCK_METHOD0(SignalHandler, bool()); -}; - -class MockCallFrameErrorReporter : public CallFrameInfo::Reporter { - public: - MockCallFrameErrorReporter() - : Reporter(gtest_logging_sink_for_LulTestDwarf, - "mock filename", "mock section") - { } - MOCK_METHOD2(Incomplete, void(uint64, CallFrameInfo::EntryKind)); - MOCK_METHOD1(EarlyEHTerminator, void(uint64)); - MOCK_METHOD2(CIEPointerOutOfRange, void(uint64, uint64)); - MOCK_METHOD2(BadCIEId, void(uint64, uint64)); - MOCK_METHOD2(UnrecognizedVersion, void(uint64, int version)); - MOCK_METHOD2(UnrecognizedAugmentation, void(uint64, const string &)); - MOCK_METHOD2(InvalidPointerEncoding, void(uint64, uint8)); - MOCK_METHOD2(UnusablePointerEncoding, void(uint64, uint8)); - MOCK_METHOD2(RestoreInCIE, void(uint64, uint64)); - MOCK_METHOD3(BadInstruction, void(uint64, CallFrameInfo::EntryKind, uint64)); - MOCK_METHOD3(NoCFARule, void(uint64, CallFrameInfo::EntryKind, uint64)); - MOCK_METHOD3(EmptyStateStack, void(uint64, CallFrameInfo::EntryKind, uint64)); - MOCK_METHOD3(ClearingCFARule, void(uint64, CallFrameInfo::EntryKind, uint64)); -}; - -struct CFIFixture { - - enum { kCFARegister = CallFrameInfo::Handler::kCFARegister }; - - CFIFixture() { - // Default expectations for the data handler. - // - // - Leave Entry and End without expectations, as it's probably a - // good idea to set those explicitly in each test. - // - // - Expect the *Rule functions to not be called, - // so that each test can simply list the calls they expect. - // - // I gather I could use StrictMock for this, but the manual seems - // to suggest using that only as a last resort, and this isn't so - // bad. - EXPECT_CALL(handler, UndefinedRule(_, _)).Times(0); - EXPECT_CALL(handler, SameValueRule(_, _)).Times(0); - EXPECT_CALL(handler, OffsetRule(_, _, _, _)).Times(0); - EXPECT_CALL(handler, ValOffsetRule(_, _, _, _)).Times(0); - EXPECT_CALL(handler, RegisterRule(_, _, _)).Times(0); - EXPECT_CALL(handler, ExpressionRule(_, _, _)).Times(0); - EXPECT_CALL(handler, ValExpressionRule(_, _, _)).Times(0); - EXPECT_CALL(handler, PersonalityRoutine(_, _)).Times(0); - EXPECT_CALL(handler, LanguageSpecificDataArea(_, _)).Times(0); - EXPECT_CALL(handler, SignalHandler()).Times(0); - - // Default expectations for the error/warning reporer. - EXPECT_CALL(reporter, Incomplete(_, _)).Times(0); - EXPECT_CALL(reporter, EarlyEHTerminator(_)).Times(0); - EXPECT_CALL(reporter, CIEPointerOutOfRange(_, _)).Times(0); - EXPECT_CALL(reporter, BadCIEId(_, _)).Times(0); - EXPECT_CALL(reporter, UnrecognizedVersion(_, _)).Times(0); - EXPECT_CALL(reporter, UnrecognizedAugmentation(_, _)).Times(0); - EXPECT_CALL(reporter, InvalidPointerEncoding(_, _)).Times(0); - EXPECT_CALL(reporter, UnusablePointerEncoding(_, _)).Times(0); - EXPECT_CALL(reporter, RestoreInCIE(_, _)).Times(0); - EXPECT_CALL(reporter, BadInstruction(_, _, _)).Times(0); - EXPECT_CALL(reporter, NoCFARule(_, _, _)).Times(0); - EXPECT_CALL(reporter, EmptyStateStack(_, _, _)).Times(0); - EXPECT_CALL(reporter, ClearingCFARule(_, _, _)).Times(0); - } - - MockCallFrameInfoHandler handler; - MockCallFrameErrorReporter reporter; -}; - -class LulDwarfCFI: public CFIFixture, public Test { }; - -TEST_F(LulDwarfCFI, EmptyRegion) { - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - static const char data[1] = { 42 }; - - ByteReader reader(ENDIANNESS_BIG); - CallFrameInfo parser(data, 0, &reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -TEST_F(LulDwarfCFI, IncompleteLength32) { - CFISection section(kBigEndian, 8); - section - // Not even long enough for an initial length. - .D16(0xa0f) - // Padding to keep valgrind happy. We subtract these off when we - // construct the parser. - .D16(0); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) - .WillOnce(Return()); - - string contents; - ASSERT_TRUE(section.GetContents(&contents)); - - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(8); - CallFrameInfo parser(contents.data(), contents.size() - 2, - &reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -TEST_F(LulDwarfCFI, IncompleteLength64) { - CFISection section(kLittleEndian, 4); - section - // An incomplete 64-bit DWARF initial length. - .D32(0xffffffff).D32(0x71fbaec2) - // Padding to keep valgrind happy. We subtract these off when we - // construct the parser. - .D32(0); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) - .WillOnce(Return()); - - string contents; - ASSERT_TRUE(section.GetContents(&contents)); - - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(4); - CallFrameInfo parser(contents.data(), contents.size() - 4, - &reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -TEST_F(LulDwarfCFI, IncompleteId32) { - CFISection section(kBigEndian, 8); - section - .D32(3) // Initial length, not long enough for id - .D8(0xd7).D8(0xe5).D8(0xf1) // incomplete id - .CIEHeader(8727, 3983, 8889, 3, "") - .FinishEntry(); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) - .WillOnce(Return()); - - string contents; - ASSERT_TRUE(section.GetContents(&contents)); - - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(8); - CallFrameInfo parser(contents.data(), contents.size(), - &reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -TEST_F(LulDwarfCFI, BadId32) { - CFISection section(kBigEndian, 8); - section - .D32(0x100) // Initial length - .D32(0xe802fade) // bogus ID - .Append(0x100 - 4, 0x42); // make the length true - section - .CIEHeader(1672, 9872, 8529, 3, "") - .FinishEntry(); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - EXPECT_CALL(reporter, CIEPointerOutOfRange(_, 0xe802fade)) - .WillOnce(Return()); - - string contents; - ASSERT_TRUE(section.GetContents(&contents)); - - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(8); - CallFrameInfo parser(contents.data(), contents.size(), - &reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -// A lone CIE shouldn't cause any handler calls. -TEST_F(LulDwarfCFI, SingleCIE) { - CFISection section(kLittleEndian, 4); - section.CIEHeader(0xffe799a8, 0x3398dcdd, 0x6e9683de, 3, ""); - section.Append(10, lul::DW_CFA_nop); - section.FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("SingleCIE", section); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(4); - CallFrameInfo parser(contents.data(), contents.size(), - &reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// One FDE, one CIE. -TEST_F(LulDwarfCFI, OneFDE) { - CFISection section(kBigEndian, 4); - Label cie; - section - .Mark(&cie) - .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "") - .FinishEntry() - .FDEHeader(cie, 0x7714740d, 0x3d5a10cd) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("OneFDE", section); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0x7714740d, 0x3d5a10cd, 3, "", 0x6b6efb87)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(4); - CallFrameInfo parser(contents.data(), contents.size(), - &reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// Two FDEs share a CIE. -TEST_F(LulDwarfCFI, TwoFDEsOneCIE) { - CFISection section(kBigEndian, 4); - Label cie; - section - // First FDE. readelf complains about this one because it makes - // a forward reference to its CIE. - .FDEHeader(cie, 0xa42744df, 0xa3b42121) - .FinishEntry() - // CIE. - .Mark(&cie) - .CIEHeader(0x04f7dc7b, 0x3d00c05f, 0xbd43cb59, 3, "") - .FinishEntry() - // Second FDE. - .FDEHeader(cie, 0x6057d391, 0x700f608d) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsOneCIE", section); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0xa42744df, 0xa3b42121, 3, "", 0xbd43cb59)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0x6057d391, 0x700f608d, 3, "", 0xbd43cb59)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(4); - CallFrameInfo parser(contents.data(), contents.size(), - &reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// Two FDEs, two CIEs. -TEST_F(LulDwarfCFI, TwoFDEsTwoCIEs) { - CFISection section(kLittleEndian, 8); - Label cie1, cie2; - section - // First CIE. - .Mark(&cie1) - .CIEHeader(0x694d5d45, 0x4233221b, 0xbf45e65a, 3, "") - .FinishEntry() - // First FDE which cites second CIE. readelf complains about - // this one because it makes a forward reference to its CIE. - .FDEHeader(cie2, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL) - .FinishEntry() - // Second FDE, which cites first CIE. - .FDEHeader(cie1, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL) - .FinishEntry() - // Second CIE. - .Mark(&cie2) - .CIEHeader(0xfba3fad7, 0x6287e1fd, 0x61d2c581, 2, "") - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsTwoCIEs", section); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL, 2, - "", 0x61d2c581)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL, 3, - "", 0xbf45e65a)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(8); - CallFrameInfo parser(contents.data(), contents.size(), - &reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// An FDE whose CIE specifies a version we don't recognize. -TEST_F(LulDwarfCFI, BadVersion) { - CFISection section(kBigEndian, 4); - Label cie1, cie2; - section - .Mark(&cie1) - .CIEHeader(0xca878cf0, 0x7698ec04, 0x7b616f54, 0x52, "") - .FinishEntry() - // We should skip this entry, as its CIE specifies a version we - // don't recognize. - .FDEHeader(cie1, 0x08852292, 0x2204004a) - .FinishEntry() - // Despite the above, we should visit this entry. - .Mark(&cie2) - .CIEHeader(0x7c3ae7c9, 0xb9b9a512, 0x96cb3264, 3, "") - .FinishEntry() - .FDEHeader(cie2, 0x2094735a, 0x6e875501) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("BadVersion", section); - - EXPECT_CALL(reporter, UnrecognizedVersion(_, 0x52)) - .WillOnce(Return()); - - { - InSequence s; - // We should see no mention of the first FDE, but we should get - // a call to Entry for the second. - EXPECT_CALL(handler, Entry(_, 0x2094735a, 0x6e875501, 3, "", - 0x96cb3264)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(4); - CallFrameInfo parser(contents.data(), contents.size(), - &reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -// An FDE whose CIE specifies an augmentation we don't recognize. -TEST_F(LulDwarfCFI, BadAugmentation) { - CFISection section(kBigEndian, 4); - Label cie1, cie2; - section - .Mark(&cie1) - .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "spaniels!") - .FinishEntry() - // We should skip this entry, as its CIE specifies an - // augmentation we don't recognize. - .FDEHeader(cie1, 0x7714740d, 0x3d5a10cd) - .FinishEntry() - // Despite the above, we should visit this entry. - .Mark(&cie2) - .CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 3, "") - .FinishEntry() - .FDEHeader(cie2, 0x7bf0fda0, 0xcbcd28d8) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("BadAugmentation", section); - - EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "spaniels!")) - .WillOnce(Return()); - - { - InSequence s; - // We should see no mention of the first FDE, but we should get - // a call to Entry for the second. - EXPECT_CALL(handler, Entry(_, 0x7bf0fda0, 0xcbcd28d8, 3, "", - 0xf2f519b2)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(4); - CallFrameInfo parser(contents.data(), contents.size(), - &reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -// The return address column field is a byte in CFI version 1 -// (DWARF2), but a ULEB128 value in version 3 (DWARF3). -TEST_F(LulDwarfCFI, CIEVersion1ReturnColumn) { - CFISection section(kBigEndian, 4); - Label cie; - section - // CIE, using the version 1 format: return column is a ubyte. - .Mark(&cie) - // Use a value for the return column that is parsed differently - // as a ubyte and as a ULEB128. - .CIEHeader(0xbcdea24f, 0x5be28286, 0x9f, 1, "") - .FinishEntry() - // FDE, citing that CIE. - .FDEHeader(cie, 0xb8d347b5, 0x825e55dc) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion1ReturnColumn", section); - - { - InSequence s; - EXPECT_CALL(handler, Entry(_, 0xb8d347b5, 0x825e55dc, 1, "", 0x9f)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(4); - CallFrameInfo parser(contents.data(), contents.size(), - &reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// The return address column field is a byte in CFI version 1 -// (DWARF2), but a ULEB128 value in version 3 (DWARF3). -TEST_F(LulDwarfCFI, CIEVersion3ReturnColumn) { - CFISection section(kBigEndian, 4); - Label cie; - section - // CIE, using the version 3 format: return column is a ULEB128. - .Mark(&cie) - // Use a value for the return column that is parsed differently - // as a ubyte and as a ULEB128. - .CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 3, "") - .FinishEntry() - // FDE, citing that CIE. - .FDEHeader(cie, 0x86763f2b, 0x2a66dc23) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section); - - { - InSequence s; - EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 3, "", 0x89)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(4); - CallFrameInfo parser(contents.data(), contents.size(), - &reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -struct CFIInsnFixture: public CFIFixture { - CFIInsnFixture() : CFIFixture() { - data_factor = 0xb6f; - return_register = 0x9be1ed9f; - version = 3; - cfa_base_register = 0x383a3aa; - cfa_offset = 0xf748; - } - - // Prepare SECTION to receive FDE instructions. - // - // - Append a stock CIE header that establishes the fixture's - // code_factor, data_factor, return_register, version, and - // augmentation values. - // - Have the CIE set up a CFA rule using cfa_base_register and - // cfa_offset. - // - Append a stock FDE header, referring to the above CIE, for the - // fde_size bytes at fde_start. Choose fde_start and fde_size - // appropriately for the section's address size. - // - Set appropriate expectations on handler in sequence s for the - // frame description entry and the CIE's CFA rule. - // - // On return, SECTION is ready to have FDE instructions appended to - // it, and its FinishEntry member called. - void StockCIEAndFDE(CFISection *section) { - // Choose appropriate constants for our address size. - if (section->AddressSize() == 4) { - fde_start = 0xc628ecfbU; - fde_size = 0x5dee04a2; - code_factor = 0x60b; - } else { - assert(section->AddressSize() == 8); - fde_start = 0x0005c57ce7806bd3ULL; - fde_size = 0x2699521b5e333100ULL; - code_factor = 0x01008e32855274a8ULL; - } - - // Create the CIE. - (*section) - .Mark(&cie_label) - .CIEHeader(code_factor, data_factor, return_register, version, - "") - .D8(lul::DW_CFA_def_cfa) - .ULEB128(cfa_base_register) - .ULEB128(cfa_offset) - .FinishEntry(); - - // Create the FDE. - section->FDEHeader(cie_label, fde_start, fde_size); - - // Expect an Entry call for the FDE and a ValOffsetRule call for the - // CIE's CFA rule. - EXPECT_CALL(handler, Entry(_, fde_start, fde_size, version, "", - return_register)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start, kCFARegister, - cfa_base_register, cfa_offset)) - .InSequence(s) - .WillOnce(Return(true)); - } - - // Run the contents of SECTION through a CallFrameInfo parser, - // expecting parser.Start to return SUCCEEDS. Caller may optionally - // supply, via READER, its own ByteReader. If that's absent, a - // local one is used. - void ParseSection(CFISection *section, - bool succeeds = true, ByteReader* reader = nullptr) { - string contents; - EXPECT_TRUE(section->GetContents(&contents)); - lul::Endianness endianness; - if (section->endianness() == kBigEndian) - endianness = ENDIANNESS_BIG; - else { - assert(section->endianness() == kLittleEndian); - endianness = ENDIANNESS_LITTLE; - } - ByteReader local_reader(endianness); - ByteReader* reader_to_use = reader ? reader : &local_reader; - reader_to_use->SetAddressSize(section->AddressSize()); - CallFrameInfo parser(contents.data(), contents.size(), - reader_to_use, &handler, &reporter); - if (succeeds) - EXPECT_TRUE(parser.Start()); - else - EXPECT_FALSE(parser.Start()); - } - - Label cie_label; - Sequence s; - uint64 code_factor; - int data_factor; - unsigned return_register; - unsigned version; - unsigned cfa_base_register; - int cfa_offset; - uint64 fde_start, fde_size; -}; - -class LulDwarfCFIInsn: public CFIInsnFixture, public Test { }; - -TEST_F(LulDwarfCFIInsn, DW_CFA_set_loc) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_set_loc).D32(0xb1ee3e7a) - // Use DW_CFA_def_cfa to force a handler call that we can use to - // check the effect of the DW_CFA_set_loc. - .D8(lul::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_set_loc", section); - - EXPECT_CALL(handler, - ValOffsetRule(0xb1ee3e7a, kCFARegister, 0x4defb431, 0x6d17b0ee)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_advance_loc) { - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_advance_loc | 0x2a) - // Use DW_CFA_def_cfa to force a handler call that we can use to - // check the effect of the DW_CFA_advance_loc. - .D8(lul::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc", section); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start + 0x2a * code_factor, - kCFARegister, 0x5bbb3715, 0x0186c7bf)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_advance_loc1) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_advance_loc1).D8(0xd8) - .D8(lul::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc1", section); - - EXPECT_CALL(handler, - ValOffsetRule((fde_start + 0xd8 * code_factor), - kCFARegister, 0x69d5696a, 0x1eb7fc93)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_advance_loc2) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_advance_loc2).D16(0x3adb) - .D8(lul::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc2", section); - - EXPECT_CALL(handler, - ValOffsetRule((fde_start + 0x3adb * code_factor), - kCFARegister, 0x3a368bed, 0x3194ee37)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_advance_loc4) { - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_advance_loc4).D32(0x15813c88) - .D8(lul::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc4", section); - - EXPECT_CALL(handler, - ValOffsetRule((fde_start + 0x15813c88ULL * code_factor), - kCFARegister, 0x135270c5, 0x24bad7cb)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_MIPS_advance_loc8) { - code_factor = 0x2d; - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL) - .D8(lul::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc8", section); - - EXPECT_CALL(handler, - ValOffsetRule((fde_start + 0x3c4f3945b92c14ULL * code_factor), - kCFARegister, 0xe17ed602, 0x3d162e7f)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_def_cfa", section); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x4e363a85, 0x815f9aa7)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_sf) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea) - .D8(lul::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x8ccb32b7, - 0x9ea * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x9b40f5da, - -0x40a2 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_register) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x3e7e9363, cfa_offset)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -// DW_CFA_def_cfa_register should have no effect when applied to a -// non-base/offset rule. -TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_registerBadRule) { - ByteReader reader(ENDIANNESS_BIG); - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_def_cfa_expression).Block("needle in a haystack") - .D8(lul::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49) - .FinishEntry(); - - EXPECT_CALL(handler, - ValExpressionRule(fde_start, kCFARegister, - "needle in a haystack")) - .WillRepeatedly(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion, true, &reader); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_offset) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, cfa_base_register, - 0x1e8e3b9b)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_offset_sf) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_def_cfa_offset_sf).LEB128(0x970) - .D8(lul::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, cfa_base_register, - 0x970 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, cfa_base_register, - -0x2cd * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -// DW_CFA_def_cfa_offset should have no effect when applied to a -// non-base/offset rule. -TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_offsetBadRule) { - ByteReader reader(ENDIANNESS_BIG); - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_def_cfa_expression).Block("six ways to Sunday") - .D8(lul::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) - .FinishEntry(); - - EXPECT_CALL(handler, - ValExpressionRule(fde_start, kCFARegister, - "six ways to Sunday")) - .WillRepeatedly(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion, true, &reader); -} - - -TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_expression) { - ByteReader reader(ENDIANNESS_LITTLE); - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_def_cfa_expression).Block("eating crow") - .FinishEntry(); - - EXPECT_CALL(handler, ValExpressionRule(fde_start, kCFARegister, - "eating crow")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion, true, &reader); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_undefined) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_undefined).ULEB128(0x300ce45d) - .FinishEntry(); - - EXPECT_CALL(handler, UndefinedRule(fde_start, 0x300ce45d)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_same_value) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_same_value).ULEB128(0x3865a760) - .FinishEntry(); - - EXPECT_CALL(handler, SameValueRule(fde_start, 0x3865a760)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_offset) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_offset | 0x2c).ULEB128(0x9f6) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x2c, kCFARegister, 0x9f6 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_offset_extended) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, - 0x402b, kCFARegister, 0xb48 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_offset_extended_sf) { - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_offset_extended_sf) - .ULEB128(0x997c23ee).LEB128(0x2d00) - .D8(lul::DW_CFA_offset_extended_sf) - .ULEB128(0x9519eb82).LEB128(-0xa77) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x997c23ee, - kCFARegister, 0x2d00 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x9519eb82, - kCFARegister, -0xa77 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_val_offset) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, 0x623562fe, - kCFARegister, 0x673 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_val_offset_sf) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab) - .D8(lul::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, 0x6f4f, - kCFARegister, 0xaab * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, - ValOffsetRule(fde_start, 0x2483, - kCFARegister, -0x8a2 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_register) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414) - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0x278d18f9, 0x1a684414)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_expression) { - ByteReader reader(ENDIANNESS_BIG); - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_expression).ULEB128(0xa1619fb2) - .Block("plus ça change, plus c'est la même chose") - .FinishEntry(); - - EXPECT_CALL(handler, - ExpressionRule(fde_start, 0xa1619fb2, - "plus ça change, plus c'est la même chose")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion, true, &reader); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_val_expression) { - ByteReader reader(ENDIANNESS_BIG); - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_val_expression).ULEB128(0xc5e4a9e3) - .Block("he who has the gold makes the rules") - .FinishEntry(); - - EXPECT_CALL(handler, - ValExpressionRule(fde_start, 0xc5e4a9e3, - "he who has the gold makes the rules")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion, true, &reader); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_restore) { - CFISection section(kLittleEndian, 8); - code_factor = 0x01bd188a9b1fa083ULL; - data_factor = -0x1ac8; - return_register = 0x8c35b049; - version = 2; - fde_start = 0x2d70fe998298bbb1ULL; - fde_size = 0x46ccc2e63cf0b108ULL; - Label cie; - section - .Mark(&cie) - .CIEHeader(code_factor, data_factor, return_register, version, - "") - // Provide a CFA rule, because register rules require them. - .D8(lul::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8) - // Provide an offset(N) rule for register 0x3c. - .D8(lul::DW_CFA_offset | 0x3c).ULEB128(0xb348) - .FinishEntry() - // In the FDE... - .FDEHeader(cie, fde_start, fde_size) - // At a second address, provide a new offset(N) rule for register 0x3c. - .D8(lul::DW_CFA_advance_loc | 0x13) - .D8(lul::DW_CFA_offset | 0x3c).ULEB128(0x9a50) - // At a third address, restore the original rule for register 0x3c. - .D8(lul::DW_CFA_advance_loc | 0x01) - .D8(lul::DW_CFA_restore | 0x3c) - .FinishEntry(); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, fde_start, fde_size, version, "", return_register)) - .WillOnce(Return(true)); - // CIE's CFA rule. - EXPECT_CALL(handler, - ValOffsetRule(fde_start, - kCFARegister, 0x6ca1d50e, 0x372e38e8)) - .WillOnce(Return(true)); - // CIE's rule for register 0x3c. - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x3c, - kCFARegister, 0xb348 * data_factor)) - .WillOnce(Return(true)); - // FDE's rule for register 0x3c. - EXPECT_CALL(handler, - OffsetRule(fde_start + 0x13 * code_factor, 0x3c, - kCFARegister, 0x9a50 * data_factor)) - .WillOnce(Return(true)); - // Restore CIE's rule for register 0x3c. - EXPECT_CALL(handler, - OffsetRule(fde_start + (0x13 + 0x01) * code_factor, 0x3c, - kCFARegister, 0xb348 * data_factor)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_restoreNoRule) { - CFISection section(kBigEndian, 4); - code_factor = 0x005f78143c1c3b82ULL; - data_factor = 0x25d0; - return_register = 0xe8; - version = 1; - fde_start = 0x4062e30f; - fde_size = 0x5302a389; - Label cie; - section - .Mark(&cie) - .CIEHeader(code_factor, data_factor, return_register, version, "") - // Provide a CFA rule, because register rules require them. - .D8(lul::DW_CFA_def_cfa).ULEB128(0x470aa334).ULEB128(0x099ef127) - .FinishEntry() - // In the FDE... - .FDEHeader(cie, fde_start, fde_size) - // At a second address, provide an offset(N) rule for register 0x2c. - .D8(lul::DW_CFA_advance_loc | 0x7) - .D8(lul::DW_CFA_offset | 0x2c).ULEB128(0x1f47) - // At a third address, restore the (missing) CIE rule for register 0x2c. - .D8(lul::DW_CFA_advance_loc | 0xb) - .D8(lul::DW_CFA_restore | 0x2c) - .FinishEntry(); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, fde_start, fde_size, version, "", return_register)) - .WillOnce(Return(true)); - // CIE's CFA rule. - EXPECT_CALL(handler, - ValOffsetRule(fde_start, - kCFARegister, 0x470aa334, 0x099ef127)) - .WillOnce(Return(true)); - // FDE's rule for register 0x2c. - EXPECT_CALL(handler, - OffsetRule(fde_start + 0x7 * code_factor, 0x2c, - kCFARegister, 0x1f47 * data_factor)) - .WillOnce(Return(true)); - // Restore CIE's (missing) rule for register 0x2c. - EXPECT_CALL(handler, - SameValueRule(fde_start + (0x7 + 0xb) * code_factor, 0x2c)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_restore_extended) { - CFISection section(kBigEndian, 4); - code_factor = 0x126e; - data_factor = -0xd8b; - return_register = 0x77711787; - version = 3; - fde_start = 0x01f55a45; - fde_size = 0x452adb80; - Label cie; - section - .Mark(&cie) - .CIEHeader(code_factor, data_factor, return_register, version, - "", true /* dwarf64 */ ) - // Provide a CFA rule, because register rules require them. - .D8(lul::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5) - // Provide an offset(N) rule for register 0x0f9b8a1c. - .D8(lul::DW_CFA_offset_extended) - .ULEB128(0x0f9b8a1c).ULEB128(0xc979) - .FinishEntry() - // In the FDE... - .FDEHeader(cie, fde_start, fde_size) - // At a second address, provide a new offset(N) rule for reg 0x0f9b8a1c. - .D8(lul::DW_CFA_advance_loc | 0x3) - .D8(lul::DW_CFA_offset_extended) - .ULEB128(0x0f9b8a1c).ULEB128(0x3b7b) - // At a third address, restore the original rule for register 0x0f9b8a1c. - .D8(lul::DW_CFA_advance_loc | 0x04) - .D8(lul::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c) - .FinishEntry(); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, fde_start, fde_size, version, "", return_register)) - .WillOnce(Return(true)); - // CIE's CFA rule. - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x56fa0edd, 0x097f78a5)) - .WillOnce(Return(true)); - // CIE's rule for register 0x0f9b8a1c. - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x0f9b8a1c, kCFARegister, - 0xc979 * data_factor)) - .WillOnce(Return(true)); - // FDE's rule for register 0x0f9b8a1c. - EXPECT_CALL(handler, - OffsetRule(fde_start + 0x3 * code_factor, 0x0f9b8a1c, - kCFARegister, 0x3b7b * data_factor)) - .WillOnce(Return(true)); - // Restore CIE's rule for register 0x0f9b8a1c. - EXPECT_CALL(handler, - OffsetRule(fde_start + (0x3 + 0x4) * code_factor, 0x0f9b8a1c, - kCFARegister, 0xc979 * data_factor)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_remember_and_restore_state) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - - // We create a state, save it, modify it, and then restore. We - // refer to the state that is overridden the restore as the - // "outgoing" state, and the restored state the "incoming" state. - // - // Register outgoing incoming expect - // 1 offset(N) no rule new "same value" rule - // 2 register(R) offset(N) report changed rule - // 3 offset(N) offset(M) report changed offset - // 4 offset(N) offset(N) no report - // 5 offset(N) no rule new "same value" rule - section - // Create the "incoming" state, which we will save and later restore. - .D8(lul::DW_CFA_offset | 2).ULEB128(0x9806) - .D8(lul::DW_CFA_offset | 3).ULEB128(0x995d) - .D8(lul::DW_CFA_offset | 4).ULEB128(0x7055) - .D8(lul::DW_CFA_remember_state) - // Advance to a new instruction; an implementation could legitimately - // ignore all but the final rule for a given register at a given address. - .D8(lul::DW_CFA_advance_loc | 1) - // Create the "outgoing" state, which we will discard. - .D8(lul::DW_CFA_offset | 1).ULEB128(0xea1a) - .D8(lul::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767) - .D8(lul::DW_CFA_offset | 3).ULEB128(0xdd29) - .D8(lul::DW_CFA_offset | 5).ULEB128(0xf1ce) - // At a third address, restore the incoming state. - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - uint64 addr = fde_start; - - // Expect the incoming rules to be reported. - EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 4, kCFARegister, 0x7055 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - - addr += code_factor; - - // After the save, we establish the outgoing rule set. - EXPECT_CALL(handler, OffsetRule(addr, 1, kCFARegister, 0xea1a * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(addr, 2, 0x1d2a3767)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0xdd29 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 5, kCFARegister, 0xf1ce * data_factor)) - .InSequence(s).WillOnce(Return(true)); - - addr += code_factor; - - // Finally, after the restore, expect to see the differences from - // the outgoing to the incoming rules reported. - EXPECT_CALL(handler, SameValueRule(addr, 1)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SameValueRule(addr, 5)) - .InSequence(s).WillOnce(Return(true)); - - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -// Check that restoring a rule set reports changes to the CFA rule. -TEST_F(LulDwarfCFIInsn, DW_CFA_remember_and_restore_stateCFA) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - - section - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_def_cfa_offset).ULEB128(0x90481102) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, kCFARegister, - cfa_base_register, 0x90481102)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor * 2, kCFARegister, - cfa_base_register, cfa_offset)) - .InSequence(s).WillOnce(Return(true)); - - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_nop) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_nop) - .D8(lul::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b) - .D8(lul::DW_CFA_nop) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x3fb8d4f1, 0x078dc67b)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_GNU_window_save) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_GNU_window_save) - .FinishEntry(); - - // Don't include all the rules in any particular sequence. - - // The caller's %o0-%o7 have become the callee's %i0-%i7. This is - // the GCC register numbering. - for (int i = 8; i < 16; i++) - EXPECT_CALL(handler, RegisterRule(fde_start, i, i + 16)) - .WillOnce(Return(true)); - // The caller's %l0-%l7 and %i0-%i7 have been saved at the top of - // its frame. - for (int i = 16; i < 32; i++) - EXPECT_CALL(handler, OffsetRule(fde_start, i, kCFARegister, (i-16) * 4)) - .WillOnce(Return(true)); - - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_GNU_args_size) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_GNU_args_size).ULEB128(0xeddfa520) - // Verify that we see this, meaning we parsed the above properly. - .D8(lul::DW_CFA_offset | 0x23).ULEB128(0x269) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x23, kCFARegister, 0x269 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIInsn, DW_CFA_GNU_negative_offset_extended) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_GNU_negative_offset_extended) - .ULEB128(0x430cc87a).ULEB128(0x613) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x430cc87a, - kCFARegister, -0x613 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -// Three FDEs: skip the second -TEST_F(LulDwarfCFIInsn, SkipFDE) { - CFISection section(kBigEndian, 4); - Label cie; - section - // CIE, used by all FDEs. - .Mark(&cie) - .CIEHeader(0x010269f2, 0x9177, 0xedca5849, 2, "") - .D8(lul::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad) - .FinishEntry() - // First FDE. - .FDEHeader(cie, 0xa870ebdd, 0x60f6aa4) - .D8(lul::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf) - .FinishEntry() - // Second FDE. - .FDEHeader(cie, 0xc534f7c0, 0xf6552e9, true /* dwarf64 */) - .D8(lul::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18) - .FinishEntry() - // Third FDE. - .FDEHeader(cie, 0xf681cfc8, 0x7e4594e) - .D8(lul::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4) - .FinishEntry(); - - { - InSequence s; - - // Process the first FDE. - EXPECT_CALL(handler, Entry(_, 0xa870ebdd, 0x60f6aa4, 2, "", 0xedca5849)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0xa870ebdd, kCFARegister, - 0x42ed390b, 0x98f43aad)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(0xa870ebdd, 0x3a860351, 0x6c9a6bcf)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .WillOnce(Return(true)); - - // Skip the second FDE. - EXPECT_CALL(handler, Entry(_, 0xc534f7c0, 0xf6552e9, 2, "", 0xedca5849)) - .WillOnce(Return(false)); - - // Process the third FDE. - EXPECT_CALL(handler, Entry(_, 0xf681cfc8, 0x7e4594e, 2, "", 0xedca5849)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0xf681cfc8, kCFARegister, - 0x42ed390b, 0x98f43aad)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(0xf681cfc8, 0x26c53934, 0x18eeb8a4)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .WillOnce(Return(true)); - } - - ParseSection(§ion); -} - -// Quit processing in the middle of an entry's instructions. -TEST_F(LulDwarfCFIInsn, QuitMidentry) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431) - .D8(lul::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat") - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0xe0cf850d, 0x15aab431)) - .InSequence(s).WillOnce(Return(false)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion, false); -} - -class LulDwarfCFIRestore: public CFIInsnFixture, public Test { }; - -TEST_F(LulDwarfCFIRestore, RestoreUndefinedRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_undefined).ULEB128(0x0bac878e) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, UndefinedRule(fde_start, 0x0bac878e)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreUndefinedRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_undefined).ULEB128(0x7dedff5f) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_same_value).ULEB128(0x7dedff5f) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, UndefinedRule(fde_start, 0x7dedff5f)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SameValueRule(fde_start + code_factor, 0x7dedff5f)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + 2 * code_factor, 0x7dedff5f)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreSameValueRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_same_value).ULEB128(0xadbc9b3a) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, SameValueRule(fde_start, 0xadbc9b3a)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreSameValueRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_same_value).ULEB128(0x3d90dcb5) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_undefined).ULEB128(0x3d90dcb5) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, SameValueRule(fde_start, 0x3d90dcb5)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x3d90dcb5)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SameValueRule(fde_start + 2 * code_factor, 0x3d90dcb5)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreOffsetRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_offset | 0x14).ULEB128(0xb6f) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, OffsetRule(fde_start, 0x14, - kCFARegister, 0xb6f * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreOffsetRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_offset | 0x21).ULEB128(0xeb7) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_undefined).ULEB128(0x21) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, - kCFARegister, 0xeb7 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x21)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21, - kCFARegister, 0xeb7 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreOffsetRuleChangedOffset) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_offset | 0x21).ULEB128(0x134) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_offset | 0x21).ULEB128(0xf4f) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, - kCFARegister, 0x134 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(fde_start + code_factor, 0x21, - kCFARegister, 0xf4f * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21, - kCFARegister, 0x134 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreValOffsetRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x829caee6, - kCFARegister, 0xe4c * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreValOffsetRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_undefined).ULEB128(0xf17c36d6) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValOffsetRule(fde_start, 0xf17c36d6, - kCFARegister, 0xeb7 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xf17c36d6)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0xf17c36d6, - kCFARegister, 0xeb7 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreValOffsetRuleChangedValOffset) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x2cf0ab1b, - kCFARegister, 0x562 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, 0x2cf0ab1b, - kCFARegister, 0xe88 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0x2cf0ab1b, - kCFARegister, 0x562 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreRegisterRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0x77514acc, 0x464de4ce)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreRegisterRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_undefined).ULEB128(0xe39acce5) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0xe39acce5, 0x095f1559)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xe39acce5)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xe39acce5, - 0x095f1559)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreRegisterRuleChangedRegister) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a) - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0xd40e21b1, 0x16607d6a)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(fde_start + code_factor, 0xd40e21b1, - 0xbabb4742)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xd40e21b1, - 0x16607d6a)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(LulDwarfCFIRestore, RestoreExpressionRuleUnchanged) { - ByteReader reader(ENDIANNESS_LITTLE); - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf") - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ExpressionRule(fde_start, 0x666ae152, "dwarf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion, true, &reader); -} - -TEST_F(LulDwarfCFIRestore, RestoreExpressionRuleChanged) { - ByteReader reader(ENDIANNESS_LITTLE); - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf") - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_undefined).ULEB128(0xb5ca5c46) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ExpressionRule(fde_start, 0xb5ca5c46, "elf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46, - "elf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion, true, &reader); -} - -TEST_F(LulDwarfCFIRestore, RestoreExpressionRuleChangedExpression) { - ByteReader reader(ENDIANNESS_LITTLE); - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf") - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_expression).ULEB128(0x500f5739).Block("orc") - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ExpressionRule(fde_start, 0x500f5739, "smurf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ExpressionRule(fde_start + code_factor, 0x500f5739, - "orc")) - .InSequence(s).WillOnce(Return(true)); - // Expectations are not wishes. - EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0x500f5739, - "smurf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion, true, &reader); -} - -TEST_F(LulDwarfCFIRestore, RestoreValExpressionRuleUnchanged) { - ByteReader reader(ENDIANNESS_LITTLE); - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_val_expression).ULEB128(0x666ae152) - .Block("hideous") - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x666ae152, "hideous")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion, true, &reader); -} - -TEST_F(LulDwarfCFIRestore, RestoreValExpressionRuleChanged) { - ByteReader reader(ENDIANNESS_LITTLE); - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_val_expression).ULEB128(0xb5ca5c46) - .Block("revolting") - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_undefined).ULEB128(0xb5ca5c46) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChanged", section); - - EXPECT_CALL(handler, ValExpressionRule(fde_start, 0xb5ca5c46, "revolting")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46, - "revolting")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion, true, &reader); -} - -TEST_F(LulDwarfCFIRestore, RestoreValExpressionRuleChangedValExpression) { - ByteReader reader(ENDIANNESS_LITTLE); - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(lul::DW_CFA_val_expression).ULEB128(0x500f5739) - .Block("repulsive") - .D8(lul::DW_CFA_remember_state) - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_val_expression).ULEB128(0x500f5739) - .Block("nauseous") - .D8(lul::DW_CFA_advance_loc | 1) - .D8(lul::DW_CFA_restore_state) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChangedValExpression", - section); - - EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x500f5739, "repulsive")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValExpressionRule(fde_start + code_factor, 0x500f5739, - "nauseous")) - .InSequence(s).WillOnce(Return(true)); - // Expectations are not wishes. - EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0x500f5739, - "repulsive")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion, true, &reader); -} - -struct EHFrameFixture: public CFIInsnFixture { - EHFrameFixture() - : CFIInsnFixture(), section(kBigEndian, 4, true) { - encoded_pointer_bases.cfi = 0x7f496cb2; - encoded_pointer_bases.text = 0x540f67b6; - encoded_pointer_bases.data = 0xe3eab768; - section.SetEncodedPointerBases(encoded_pointer_bases); - } - CFISection section; - CFISection::EncodedPointerBases encoded_pointer_bases; - - // Parse CFIInsnFixture::ParseSection, but parse the section as - // .eh_frame data, supplying stock base addresses. - void ParseEHFrameSection(CFISection *section, bool succeeds = true) { - EXPECT_TRUE(section->ContainsEHFrame()); - string contents; - EXPECT_TRUE(section->GetContents(&contents)); - lul::Endianness endianness; - if (section->endianness() == kBigEndian) - endianness = ENDIANNESS_BIG; - else { - assert(section->endianness() == kLittleEndian); - endianness = ENDIANNESS_LITTLE; - } - ByteReader reader(endianness); - reader.SetAddressSize(section->AddressSize()); - reader.SetCFIDataBase(encoded_pointer_bases.cfi, contents.data()); - reader.SetTextBase(encoded_pointer_bases.text); - reader.SetDataBase(encoded_pointer_bases.data); - CallFrameInfo parser(contents.data(), contents.size(), - &reader, &handler, &reporter, true); - if (succeeds) - EXPECT_TRUE(parser.Start()); - else - EXPECT_FALSE(parser.Start()); - } - -}; - -class LulDwarfEHFrame: public EHFrameFixture, public Test { }; - -// A simple CIE, an FDE, and a terminator. -TEST_F(LulDwarfEHFrame, Terminator) { - Label cie; - section - .Mark(&cie) - .CIEHeader(9968, 2466, 67, 1, "") - .D8(lul::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372) - .FinishEntry() - .FDEHeader(cie, 0x848037a1, 0x7b30475e) - .D8(lul::DW_CFA_set_loc).D32(0x17713850) - .D8(lul::DW_CFA_undefined).ULEB128(5721) - .FinishEntry() - .D32(0) // Terminate the sequence. - // This FDE should be ignored. - .FDEHeader(cie, 0xf19629fe, 0x439fb09b) - .FinishEntry(); - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.Terminator", section); - - EXPECT_CALL(handler, Entry(_, 0x848037a1, 0x7b30475e, 1, "", 67)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0x848037a1, kCFARegister, 3772, 1372)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(0x17713850, 5721)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(reporter, EarlyEHTerminator(_)) - .InSequence(s).WillOnce(Return()); - - ParseEHFrameSection(§ion); -} - -// The parser should recognize the Linux Standards Base 'z' augmentations. -TEST_F(LulDwarfEHFrame, SimpleFDE) { - lul::DwarfPointerEncoding lsda_encoding = - lul::DwarfPointerEncoding(lul::DW_EH_PE_indirect - | lul::DW_EH_PE_datarel - | lul::DW_EH_PE_sdata2); - lul::DwarfPointerEncoding fde_encoding = - lul::DwarfPointerEncoding(lul::DW_EH_PE_textrel - | lul::DW_EH_PE_udata2); - - section.SetPointerEncoding(fde_encoding); - section.SetEncodedPointerBases(encoded_pointer_bases); - Label cie; - section - .Mark(&cie) - .CIEHeader(4873, 7012, 100, 1, "zSLPR") - .ULEB128(7) // Augmentation data length - .D8(lsda_encoding) // LSDA pointer format - .D8(lul::DW_EH_PE_pcrel) // personality pointer format - .EncodedPointer(0x97baa00, lul::DW_EH_PE_pcrel) // and value - .D8(fde_encoding) // FDE pointer format - .D8(lul::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31) - .FinishEntry() - .FDEHeader(cie, 0x540f6b56, 0xf686) - .ULEB128(2) // Augmentation data length - .EncodedPointer(0xe3eab475, lsda_encoding) // LSDA pointer, signed - .D8(lul::DW_CFA_set_loc) - .EncodedPointer(0x540fa4ce, fde_encoding) - .D8(lul::DW_CFA_undefined).ULEB128(0x675e) - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.SimpleFDE", section); - - EXPECT_CALL(handler, Entry(_, 0x540f6b56, 0xf686, 1, "zSLPR", 100)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, PersonalityRoutine(0x97baa00, false)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, LanguageSpecificDataArea(0xe3eab475, true)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SignalHandler()) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0x540f6b56, kCFARegister, 6706, 31)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(0x540fa4ce, 0x675e)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -// Check that we can handle an empty 'z' augmentation. -TEST_F(LulDwarfEHFrame, EmptyZ) { - Label cie; - section - .Mark(&cie) - .CIEHeader(5955, 5805, 228, 1, "z") - .ULEB128(0) // Augmentation data length - .D8(lul::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247) - .FinishEntry() - .FDEHeader(cie, 0xda007738, 0xfb55c641) - .ULEB128(0) // Augmentation data length - .D8(lul::DW_CFA_advance_loc1).D8(11) - .D8(lul::DW_CFA_undefined).ULEB128(3769) - .FinishEntry(); - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.EmptyZ", section); - - EXPECT_CALL(handler, Entry(_, 0xda007738, 0xfb55c641, 1, "z", 228)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0xda007738, kCFARegister, 3629, 247)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(0xda007738 + 11 * 5955, 3769)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -// Check that we recognize bad 'z' augmentation characters. -TEST_F(LulDwarfEHFrame, BadZ) { - Label cie; - section - .Mark(&cie) - .CIEHeader(6937, 1045, 142, 1, "zQ") - .ULEB128(0) // Augmentation data length - .D8(lul::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725) - .FinishEntry() - .FDEHeader(cie, 0x1293efa8, 0x236f53f2) - .ULEB128(0) // Augmentation data length - .D8(lul::DW_CFA_advance_loc | 12) - .D8(lul::DW_CFA_register).ULEB128(5667).ULEB128(3462) - .FinishEntry(); - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.BadZ", section); - - EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "zQ")) - .WillOnce(Return()); - - ParseEHFrameSection(§ion, false); -} - -TEST_F(LulDwarfEHFrame, zL) { - Label cie; - lul::DwarfPointerEncoding lsda_encoding = - lul::DwarfPointerEncoding(lul::DW_EH_PE_funcrel | lul::DW_EH_PE_udata2); - section - .Mark(&cie) - .CIEHeader(9285, 9959, 54, 1, "zL") - .ULEB128(1) // Augmentation data length - .D8(lsda_encoding) // encoding for LSDA pointer in FDE - - .FinishEntry() - .FDEHeader(cie, 0xd40091aa, 0x9aa6e746) - .ULEB128(2) // Augmentation data length - .EncodedPointer(0xd40099cd, lsda_encoding) // LSDA pointer - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zL", section); - - EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zL", 54)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, LanguageSpecificDataArea(0xd40099cd, false)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -TEST_F(LulDwarfEHFrame, zP) { - Label cie; - lul::DwarfPointerEncoding personality_encoding = - lul::DwarfPointerEncoding(lul::DW_EH_PE_datarel | lul::DW_EH_PE_udata2); - section - .Mark(&cie) - .CIEHeader(1097, 6313, 17, 1, "zP") - .ULEB128(3) // Augmentation data length - .D8(personality_encoding) // encoding for personality routine - .EncodedPointer(0xe3eaccac, personality_encoding) // value - .FinishEntry() - .FDEHeader(cie, 0x0c8350c9, 0xbef11087) - .ULEB128(0) // Augmentation data length - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zP", section); - - EXPECT_CALL(handler, Entry(_, 0x0c8350c9, 0xbef11087, 1, "zP", 17)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, PersonalityRoutine(0xe3eaccac, false)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -TEST_F(LulDwarfEHFrame, zR) { - Label cie; - lul::DwarfPointerEncoding pointer_encoding = - lul::DwarfPointerEncoding(lul::DW_EH_PE_textrel | lul::DW_EH_PE_sdata2); - section.SetPointerEncoding(pointer_encoding); - section - .Mark(&cie) - .CIEHeader(8011, 5496, 75, 1, "zR") - .ULEB128(1) // Augmentation data length - .D8(pointer_encoding) // encoding for FDE addresses - .FinishEntry() - .FDEHeader(cie, 0x540f9431, 0xbd0) - .ULEB128(0) // Augmentation data length - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zR", section); - - EXPECT_CALL(handler, Entry(_, 0x540f9431, 0xbd0, 1, "zR", 75)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -TEST_F(LulDwarfEHFrame, zS) { - Label cie; - section - .Mark(&cie) - .CIEHeader(9217, 7694, 57, 1, "zS") - .ULEB128(0) // Augmentation data length - .FinishEntry() - .FDEHeader(cie, 0xd40091aa, 0x9aa6e746) - .ULEB128(0) // Augmentation data length - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zS", section); - - EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zS", 57)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SignalHandler()) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -// These tests require manual inspection of the test output. -struct CFIReporterFixture { - CFIReporterFixture() : reporter(gtest_logging_sink_for_LulTestDwarf, - "test file name", "test section name") { } - CallFrameInfo::Reporter reporter; -}; - -class LulDwarfCFIReporter: public CFIReporterFixture, public Test { }; - -TEST_F(LulDwarfCFIReporter, Incomplete) { - reporter.Incomplete(0x0102030405060708ULL, CallFrameInfo::kUnknown); -} - -TEST_F(LulDwarfCFIReporter, EarlyEHTerminator) { - reporter.EarlyEHTerminator(0x0102030405060708ULL); -} - -TEST_F(LulDwarfCFIReporter, CIEPointerOutOfRange) { - reporter.CIEPointerOutOfRange(0x0123456789abcdefULL, 0xfedcba9876543210ULL); -} - -TEST_F(LulDwarfCFIReporter, BadCIEId) { - reporter.BadCIEId(0x0123456789abcdefULL, 0xfedcba9876543210ULL); -} - -TEST_F(LulDwarfCFIReporter, UnrecognizedVersion) { - reporter.UnrecognizedVersion(0x0123456789abcdefULL, 43); -} - -TEST_F(LulDwarfCFIReporter, UnrecognizedAugmentation) { - reporter.UnrecognizedAugmentation(0x0123456789abcdefULL, "poodles"); -} - -TEST_F(LulDwarfCFIReporter, InvalidPointerEncoding) { - reporter.InvalidPointerEncoding(0x0123456789abcdefULL, 0x42); -} - -TEST_F(LulDwarfCFIReporter, UnusablePointerEncoding) { - reporter.UnusablePointerEncoding(0x0123456789abcdefULL, 0x42); -} - -TEST_F(LulDwarfCFIReporter, RestoreInCIE) { - reporter.RestoreInCIE(0x0123456789abcdefULL, 0xfedcba9876543210ULL); -} - -TEST_F(LulDwarfCFIReporter, BadInstruction) { - reporter.BadInstruction(0x0123456789abcdefULL, CallFrameInfo::kFDE, - 0xfedcba9876543210ULL); -} - -TEST_F(LulDwarfCFIReporter, NoCFARule) { - reporter.NoCFARule(0x0123456789abcdefULL, CallFrameInfo::kCIE, - 0xfedcba9876543210ULL); -} - -TEST_F(LulDwarfCFIReporter, EmptyStateStack) { - reporter.EmptyStateStack(0x0123456789abcdefULL, CallFrameInfo::kTerminator, - 0xfedcba9876543210ULL); -} - -TEST_F(LulDwarfCFIReporter, ClearingCFARule) { - reporter.ClearingCFARule(0x0123456789abcdefULL, CallFrameInfo::kFDE, - 0xfedcba9876543210ULL); -} -class LulDwarfExpr : public Test { }; - -class MockSummariser : public Summariser { -public: - MockSummariser() : Summariser(nullptr, 0, nullptr) {} - MOCK_METHOD2(Entry, void(uintptr_t, uintptr_t)); - MOCK_METHOD0(End, void()); - MOCK_METHOD5(Rule, void(uintptr_t, int, LExprHow, int16_t, int64_t)); - MOCK_METHOD1(AddPfxInstr, uint32_t(PfxInstr)); -}; - -TEST_F(LulDwarfExpr, SimpleTransliteration) { - MockSummariser summ; - ByteReader reader(ENDIANNESS_LITTLE); - - CFISection section(kLittleEndian, 8); - section - .D8(DW_OP_lit0) - .D8(DW_OP_lit31) - .D8(DW_OP_breg0 + 17).LEB128(-1234) - .D8(DW_OP_const4s).D32(0xFEDC9876) - .D8(DW_OP_deref) - .D8(DW_OP_and) - .D8(DW_OP_plus) - .D8(DW_OP_minus) - .D8(DW_OP_shl) - .D8(DW_OP_ge); - string expr; - bool ok = section.GetContents(&expr); - EXPECT_TRUE(ok); - - { - InSequence s; - // required start marker - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_Start, 0))); - // DW_OP_lit0 - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_SImm32, 0))); - // DW_OP_lit31 - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_SImm32, 31))); - // DW_OP_breg17 -1234 - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_DwReg, 17))); - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_SImm32, -1234))); - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_Add))); - // DW_OP_const4s 0xFEDC9876 - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_SImm32, 0xFEDC9876))); - // DW_OP_deref - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_Deref))); - // DW_OP_and - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_And))); - // DW_OP_plus - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_Add))); - // DW_OP_minus - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_Sub))); - // DW_OP_shl - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_Shl))); - // DW_OP_ge - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_CmpGES))); - // required end marker - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_End))); - } - - int32_t ix = parseDwarfExpr(&summ, &reader, expr, false, false, false); - EXPECT_TRUE(ix >= 0); -} - -TEST_F(LulDwarfExpr, UnknownOpcode) { - MockSummariser summ; - ByteReader reader(ENDIANNESS_LITTLE); - - CFISection section(kLittleEndian, 8); - section - .D8(DW_OP_lo_user - 1); - string expr; - bool ok = section.GetContents(&expr); - EXPECT_TRUE(ok); - - { - InSequence s; - // required start marker - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_Start, 0))); - } - - int32_t ix = parseDwarfExpr(&summ, &reader, expr, false, false, false); - EXPECT_TRUE(ix == -1); -} - -TEST_F(LulDwarfExpr, ExpressionOverrun) { - MockSummariser summ; - ByteReader reader(ENDIANNESS_LITTLE); - - CFISection section(kLittleEndian, 8); - section - .D8(DW_OP_const4s).D8(0x12).D8(0x34).D8(0x56); - string expr; - bool ok = section.GetContents(&expr); - EXPECT_TRUE(ok); - - { - InSequence s; - // required start marker - EXPECT_CALL(summ, AddPfxInstr(PfxInstr(PX_Start, 0))); - // DW_OP_const4s followed by 3 (a.k.a. not enough) bytes - // We expect PfxInstr(PX_Simm32, not-known-for-sure-32-bit-immediate) - // Hence must use _ as the argument. - EXPECT_CALL(summ, AddPfxInstr(_)); - } - - int32_t ix = parseDwarfExpr(&summ, &reader, expr, false, false, false); - EXPECT_TRUE(ix == -1); -} - -// We'll need to mention specific Dwarf registers in the EvaluatePfxExpr tests, -// and those names are arch-specific, so a bit of macro magic is helpful. -#if defined(LUL_ARCH_arm) -# define TESTED_REG_STRUCT_NAME r11 -# define TESTED_REG_DWARF_NAME DW_REG_ARM_R11 -#elif defined(LUL_ARCH_x64) || defined(LUL_ARCH_x86) -# define TESTED_REG_STRUCT_NAME xbp -# define TESTED_REG_DWARF_NAME DW_REG_INTEL_XBP -#else -# error "Unknown plat" -#endif - -struct EvaluatePfxExprFixture { - // Creates: - // initial stack, AVMA 0x12345678, at offset 4 bytes = 0xdeadbeef - // initial regs, with XBP = 0x14141356 - // initial CFA = 0x5432ABCD - EvaluatePfxExprFixture() { - // The test stack. - si.mStartAvma = 0x12345678; - si.mLen = 0; -# define XX(_byte) do { si.mContents[si.mLen++] = (_byte); } while (0) - XX(0x55); XX(0x55); XX(0x55); XX(0x55); - if (sizeof(void*) == 8) { - // le64 - XX(0xEF); XX(0xBE); XX(0xAD); XX(0xDE); XX(0); XX(0); XX(0); XX(0); - } else { - // le32 - XX(0xEF); XX(0xBE); XX(0xAD); XX(0xDE); - } - XX(0xAA); XX(0xAA); XX(0xAA); XX(0xAA); -# undef XX - // The initial CFA. - initialCFA = TaggedUWord(0x5432ABCD); - // The initial register state. - memset(®s, 0, sizeof(regs)); - regs.TESTED_REG_STRUCT_NAME = TaggedUWord(0x14141356); - } - - StackImage si; - TaggedUWord initialCFA; - UnwindRegs regs; -}; - -class LulDwarfEvaluatePfxExpr : public EvaluatePfxExprFixture, public Test { }; - -TEST_F(LulDwarfEvaluatePfxExpr, NormalEvaluation) { - vector<PfxInstr> instrs; - // Put some junk at the start of the insn sequence. - instrs.push_back(PfxInstr(PX_End)); - instrs.push_back(PfxInstr(PX_End)); - - // Now the real sequence - // stack is empty - instrs.push_back(PfxInstr(PX_Start, 1)); - // 0x5432ABCD - instrs.push_back(PfxInstr(PX_SImm32, 0x31415927)); - // 0x5432ABCD 0x31415927 - instrs.push_back(PfxInstr(PX_DwReg, TESTED_REG_DWARF_NAME)); - // 0x5432ABCD 0x31415927 0x14141356 - instrs.push_back(PfxInstr(PX_SImm32, 42)); - // 0x5432ABCD 0x31415927 0x14141356 42 - instrs.push_back(PfxInstr(PX_Sub)); - // 0x5432ABCD 0x31415927 0x1414132c - instrs.push_back(PfxInstr(PX_Add)); - // 0x5432ABCD 0x45556c53 - instrs.push_back(PfxInstr(PX_SImm32, si.mStartAvma + 4)); - // 0x5432ABCD 0x45556c53 0x1234567c - instrs.push_back(PfxInstr(PX_Deref)); - // 0x5432ABCD 0x45556c53 0xdeadbeef - instrs.push_back(PfxInstr(PX_SImm32, 0xFE01DC23)); - // 0x5432ABCD 0x45556c53 0xdeadbeef 0xFE01DC23 - instrs.push_back(PfxInstr(PX_And)); - // 0x5432ABCD 0x45556c53 0xde019c23 - instrs.push_back(PfxInstr(PX_SImm32, 7)); - // 0x5432ABCD 0x45556c53 0xde019c23 7 - instrs.push_back(PfxInstr(PX_Shl)); - // 0x5432ABCD 0x45556c53 0x6f00ce1180 - instrs.push_back(PfxInstr(PX_SImm32, 0x7fffffff)); - // 0x5432ABCD 0x45556c53 0x6f00ce1180 7fffffff - instrs.push_back(PfxInstr(PX_And)); - // 0x5432ABCD 0x45556c53 0x00ce1180 - instrs.push_back(PfxInstr(PX_Add)); - // 0x5432ABCD 0x46237dd3 - instrs.push_back(PfxInstr(PX_Sub)); - // 0xe0f2dfa - - instrs.push_back(PfxInstr(PX_End)); - - TaggedUWord res = EvaluatePfxExpr(2/*offset of start insn*/, - ®s, initialCFA, &si, instrs); - EXPECT_TRUE(res.Valid()); - EXPECT_TRUE(res.Value() == 0xe0f2dfa); -} - -TEST_F(LulDwarfEvaluatePfxExpr, EmptySequence) { - vector<PfxInstr> instrs; - TaggedUWord res = EvaluatePfxExpr(0, ®s, initialCFA, &si, instrs); - EXPECT_FALSE(res.Valid()); -} - -TEST_F(LulDwarfEvaluatePfxExpr, BogusStartPoint) { - vector<PfxInstr> instrs; - instrs.push_back(PfxInstr(PX_SImm32, 42)); - instrs.push_back(PfxInstr(PX_SImm32, 24)); - instrs.push_back(PfxInstr(PX_SImm32, 4224)); - TaggedUWord res = EvaluatePfxExpr(1, ®s, initialCFA, &si, instrs); - EXPECT_FALSE(res.Valid()); -} - -TEST_F(LulDwarfEvaluatePfxExpr, MissingEndMarker) { - vector<PfxInstr> instrs; - instrs.push_back(PfxInstr(PX_Start, 0)); - instrs.push_back(PfxInstr(PX_SImm32, 24)); - TaggedUWord res = EvaluatePfxExpr(0, ®s, initialCFA, &si, instrs); - EXPECT_FALSE(res.Valid()); -} - -TEST_F(LulDwarfEvaluatePfxExpr, StackUnderflow) { - vector<PfxInstr> instrs; - instrs.push_back(PfxInstr(PX_Start, 0)); - instrs.push_back(PfxInstr(PX_End)); - TaggedUWord res = EvaluatePfxExpr(0, ®s, initialCFA, &si, instrs); - EXPECT_FALSE(res.Valid()); -} - -TEST_F(LulDwarfEvaluatePfxExpr, StackNoUnderflow) { - vector<PfxInstr> instrs; - instrs.push_back(PfxInstr(PX_Start, 1/*push the initial CFA*/)); - instrs.push_back(PfxInstr(PX_End)); - TaggedUWord res = EvaluatePfxExpr(0, ®s, initialCFA, &si, instrs); - EXPECT_TRUE(res.Valid()); - EXPECT_TRUE(res == initialCFA); -} - -TEST_F(LulDwarfEvaluatePfxExpr, StackOverflow) { - vector<PfxInstr> instrs; - instrs.push_back(PfxInstr(PX_Start, 0)); - for (int i = 0; i < 10+1; i++) { - instrs.push_back(PfxInstr(PX_SImm32, i + 100)); - } - instrs.push_back(PfxInstr(PX_End)); - TaggedUWord res = EvaluatePfxExpr(0, ®s, initialCFA, &si, instrs); - EXPECT_FALSE(res.Valid()); -} - -TEST_F(LulDwarfEvaluatePfxExpr, StackNoOverflow) { - vector<PfxInstr> instrs; - instrs.push_back(PfxInstr(PX_Start, 0)); - for (int i = 0; i < 10+0; i++) { - instrs.push_back(PfxInstr(PX_SImm32, i + 100)); - } - instrs.push_back(PfxInstr(PX_End)); - TaggedUWord res = EvaluatePfxExpr(0, ®s, initialCFA, &si, instrs); - EXPECT_TRUE(res.Valid()); - EXPECT_TRUE(res == TaggedUWord(109)); -} - -TEST_F(LulDwarfEvaluatePfxExpr, OutOfRangeShl) { - vector<PfxInstr> instrs; - instrs.push_back(PfxInstr(PX_Start, 0)); - instrs.push_back(PfxInstr(PX_SImm32, 1234)); - instrs.push_back(PfxInstr(PX_SImm32, 5678)); - instrs.push_back(PfxInstr(PX_Shl)); - TaggedUWord res = EvaluatePfxExpr(0, ®s, initialCFA, &si, instrs); - EXPECT_TRUE(!res.Valid()); -} - -TEST_F(LulDwarfEvaluatePfxExpr, TestCmpGES) { - const int32_t argsL[6] = { 0, 0, 1, -2, -1, -2 }; - const int32_t argsR[6] = { 0, 1, 0, -2, -2, -1 }; - // expecting: t f t t t f = 101110 = 0x2E - vector<PfxInstr> instrs; - instrs.push_back(PfxInstr(PX_Start, 0)); - // The "running total" - instrs.push_back(PfxInstr(PX_SImm32, 0)); - for (unsigned int i = 0; i < sizeof(argsL)/sizeof(argsL[0]); i++) { - // Shift the "running total" at the bottom of the stack left by one bit - instrs.push_back(PfxInstr(PX_SImm32, 1)); - instrs.push_back(PfxInstr(PX_Shl)); - // Push both test args and do the comparison - instrs.push_back(PfxInstr(PX_SImm32, argsL[i])); - instrs.push_back(PfxInstr(PX_SImm32, argsR[i])); - instrs.push_back(PfxInstr(PX_CmpGES)); - // Or the result into the running total - instrs.push_back(PfxInstr(PX_Or)); - } - instrs.push_back(PfxInstr(PX_End)); - TaggedUWord res = EvaluatePfxExpr(0, ®s, initialCFA, &si, instrs); - EXPECT_TRUE(res.Valid()); - EXPECT_TRUE(res == TaggedUWord(0x2E)); -} - -} // namespace lul diff --git a/tools/profiler/tests/gtest/LulTestInfrastructure.cpp b/tools/profiler/tests/gtest/LulTestInfrastructure.cpp deleted file mode 100644 index ba8e2e41e..000000000 --- a/tools/profiler/tests/gtest/LulTestInfrastructure.cpp +++ /dev/null @@ -1,491 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// Derived from: -// test_assembler.cc: Implementation of google_breakpad::TestAssembler. -// See test_assembler.h for details. - -// Derived from: -// cfi_assembler.cc: Implementation of google_breakpad::CFISection class. -// See cfi_assembler.h for details. - -#include "LulTestInfrastructure.h" - -namespace lul_test { -namespace test_assembler { - -using std::back_insert_iterator; - -Label::Label() : value_(new Binding()) { } -Label::Label(uint64_t value) : value_(new Binding(value)) { } -Label::Label(const Label &label) { - value_ = label.value_; - value_->Acquire(); -} -Label::~Label() { - if (value_->Release()) delete value_; -} - -Label &Label::operator=(uint64_t value) { - value_->Set(NULL, value); - return *this; -} - -Label &Label::operator=(const Label &label) { - value_->Set(label.value_, 0); - return *this; -} - -Label Label::operator+(uint64_t addend) const { - Label l; - l.value_->Set(this->value_, addend); - return l; -} - -Label Label::operator-(uint64_t subtrahend) const { - Label l; - l.value_->Set(this->value_, -subtrahend); - return l; -} - -// When NDEBUG is #defined, assert doesn't evaluate its argument. This -// means you can't simply use assert to check the return value of a -// function with necessary side effects. -// -// ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether -// NDEBUG is #defined; when NDEBUG is not #defined, it further asserts -// that x is true. -#ifdef NDEBUG -#define ALWAYS_EVALUATE_AND_ASSERT(x) x -#else -#define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x) -#endif - -uint64_t Label::operator-(const Label &label) const { - uint64_t offset; - ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset)); - return offset; -} - -bool Label::IsKnownConstant(uint64_t *value_p) const { - Binding *base; - uint64_t addend; - value_->Get(&base, &addend); - if (base != NULL) return false; - if (value_p) *value_p = addend; - return true; -} - -bool Label::IsKnownOffsetFrom(const Label &label, uint64_t *offset_p) const -{ - Binding *label_base, *this_base; - uint64_t label_addend, this_addend; - label.value_->Get(&label_base, &label_addend); - value_->Get(&this_base, &this_addend); - // If this and label are related, Get will find their final - // common ancestor, regardless of how indirect the relation is. This - // comparison also handles the constant vs. constant case. - if (this_base != label_base) return false; - if (offset_p) *offset_p = this_addend - label_addend; - return true; -} - -Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { } - -Label::Binding::Binding(uint64_t addend) - : base_(NULL), addend_(addend), reference_count_(1) { } - -Label::Binding::~Binding() { - assert(reference_count_ == 0); - if (base_ && base_ != this && base_->Release()) - delete base_; -} - -void Label::Binding::Set(Binding *binding, uint64_t addend) { - if (!base_ && !binding) { - // We're equating two constants. This could be okay. - assert(addend_ == addend); - } else if (!base_) { - // We are a known constant, but BINDING may not be, so turn the - // tables and try to set BINDING's value instead. - binding->Set(NULL, addend_ - addend); - } else { - if (binding) { - // Find binding's final value. Since the final value is always either - // completely unconstrained or a constant, never a reference to - // another variable (otherwise, it wouldn't be final), this - // guarantees we won't create cycles here, even for code like this: - // l = m, m = n, n = l; - uint64_t binding_addend; - binding->Get(&binding, &binding_addend); - addend += binding_addend; - } - - // It seems likely that setting a binding to itself is a bug - // (although I can imagine this might turn out to be helpful to - // permit). - assert(binding != this); - - if (base_ != this) { - // Set the other bindings on our chain as well. Note that this - // is sufficient even though binding relationships form trees: - // All binding operations traverse their chains to the end, and - // all bindings related to us share some tail of our chain, so - // they will see the changes we make here. - base_->Set(binding, addend - addend_); - // We're not going to use base_ any more. - if (base_->Release()) delete base_; - } - - // Adopt BINDING as our base. Note that it should be correct to - // acquire here, after the release above, even though the usual - // reference-counting rules call for acquiring first, and then - // releasing: the self-reference assertion above should have - // complained if BINDING were 'this' or anywhere along our chain, - // so we didn't release BINDING. - if (binding) binding->Acquire(); - base_ = binding; - addend_ = addend; - } -} - -void Label::Binding::Get(Binding **base, uint64_t *addend) { - if (base_ && base_ != this) { - // Recurse to find the end of our reference chain (the root of our - // tree), and then rewrite every binding along the chain to refer - // to it directly, adjusting addends appropriately. (This is why - // this member function isn't this-const.) - Binding *final_base; - uint64_t final_addend; - base_->Get(&final_base, &final_addend); - if (final_base) final_base->Acquire(); - if (base_->Release()) delete base_; - base_ = final_base; - addend_ += final_addend; - } - *base = base_; - *addend = addend_; -} - -template<typename Inserter> -static inline void InsertEndian(test_assembler::Endianness endianness, - size_t size, uint64_t number, Inserter dest) { - assert(size > 0); - if (endianness == kLittleEndian) { - for (size_t i = 0; i < size; i++) { - *dest++ = (char) (number & 0xff); - number >>= 8; - } - } else { - assert(endianness == kBigEndian); - // The loop condition is odd, but it's correct for size_t. - for (size_t i = size - 1; i < size; i--) - *dest++ = (char) ((number >> (i * 8)) & 0xff); - } -} - -Section &Section::Append(Endianness endianness, size_t size, uint64_t number) { - InsertEndian(endianness, size, number, - back_insert_iterator<string>(contents_)); - return *this; -} - -Section &Section::Append(Endianness endianness, size_t size, - const Label &label) { - // If this label's value is known, there's no reason to waste an - // entry in references_ on it. - uint64_t value; - if (label.IsKnownConstant(&value)) - return Append(endianness, size, value); - - // This will get caught when the references are resolved, but it's - // nicer to find out earlier. - assert(endianness != kUnsetEndian); - - references_.push_back(Reference(contents_.size(), endianness, size, label)); - contents_.append(size, 0); - return *this; -} - -#define ENDIANNESS_L kLittleEndian -#define ENDIANNESS_B kBigEndian -#define ENDIANNESS(e) ENDIANNESS_ ## e - -#define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ - Section &Section::e ## bits(uint ## bits ## _t v) { \ - InsertEndian(ENDIANNESS(e), bits / 8, v, \ - back_insert_iterator<string>(contents_)); \ - return *this; \ - } - -#define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \ - Section &Section::e ## bits(const Label &v) { \ - return Append(ENDIANNESS(e), bits / 8, v); \ - } - -// Define L16, B32, and friends. -#define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \ - DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ - DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) - -DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8); -DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8); -DEFINE_SHORT_APPEND_ENDIAN(L, 16); -DEFINE_SHORT_APPEND_ENDIAN(L, 32); -DEFINE_SHORT_APPEND_ENDIAN(L, 64); -DEFINE_SHORT_APPEND_ENDIAN(B, 16); -DEFINE_SHORT_APPEND_ENDIAN(B, 32); -DEFINE_SHORT_APPEND_ENDIAN(B, 64); - -#define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ - Section &Section::D ## bits(uint ## bits ## _t v) { \ - InsertEndian(endianness_, bits / 8, v, \ - back_insert_iterator<string>(contents_)); \ - return *this; \ - } -#define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \ - Section &Section::D ## bits(const Label &v) { \ - return Append(endianness_, bits / 8, v); \ - } -#define DEFINE_SHORT_APPEND_DEFAULT(bits) \ - DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ - DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) - -DEFINE_SHORT_APPEND_LABEL_DEFAULT(8) -DEFINE_SHORT_APPEND_DEFAULT(16); -DEFINE_SHORT_APPEND_DEFAULT(32); -DEFINE_SHORT_APPEND_DEFAULT(64); - -Section &Section::LEB128(long long value) { - while (value < -0x40 || 0x3f < value) { - contents_ += (value & 0x7f) | 0x80; - if (value < 0) - value = (value >> 7) | ~(((unsigned long long) -1) >> 7); - else - value = (value >> 7); - } - contents_ += value & 0x7f; - return *this; -} - -Section &Section::ULEB128(uint64_t value) { - while (value > 0x7f) { - contents_ += (value & 0x7f) | 0x80; - value = (value >> 7); - } - contents_ += value; - return *this; -} - -Section &Section::Align(size_t alignment, uint8_t pad_byte) { - // ALIGNMENT must be a power of two. - assert(((alignment - 1) & alignment) == 0); - size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1); - contents_.append(new_size - contents_.size(), pad_byte); - assert((contents_.size() & (alignment - 1)) == 0); - return *this; -} - -bool Section::GetContents(string *contents) { - // For each label reference, find the label's value, and patch it into - // the section's contents. - for (size_t i = 0; i < references_.size(); i++) { - Reference &r = references_[i]; - uint64_t value; - if (!r.label.IsKnownConstant(&value)) { - fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset); - return false; - } - assert(r.offset < contents_.size()); - assert(contents_.size() - r.offset >= r.size); - InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset); - } - contents->clear(); - std::swap(contents_, *contents); - references_.clear(); - return true; -} - -} // namespace test_assembler -} // namespace lul_test - - -namespace lul_test { - -CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor, - int data_alignment_factor, - unsigned return_address_register, - uint8_t version, - const string &augmentation, - bool dwarf64) { - assert(!entry_length_); - entry_length_ = new PendingLength(); - in_fde_ = false; - - if (dwarf64) { - D32(kDwarf64InitialLengthMarker); - D64(entry_length_->length); - entry_length_->start = Here(); - D64(eh_frame_ ? kEHFrame64CIEIdentifier : kDwarf64CIEIdentifier); - } else { - D32(entry_length_->length); - entry_length_->start = Here(); - D32(eh_frame_ ? kEHFrame32CIEIdentifier : kDwarf32CIEIdentifier); - } - D8(version); - AppendCString(augmentation); - ULEB128(code_alignment_factor); - LEB128(data_alignment_factor); - if (version == 1) - D8(return_address_register); - else - ULEB128(return_address_register); - return *this; -} - -CFISection &CFISection::FDEHeader(Label cie_pointer, - uint64_t initial_location, - uint64_t address_range, - bool dwarf64) { - assert(!entry_length_); - entry_length_ = new PendingLength(); - in_fde_ = true; - fde_start_address_ = initial_location; - - if (dwarf64) { - D32(0xffffffff); - D64(entry_length_->length); - entry_length_->start = Here(); - if (eh_frame_) - D64(Here() - cie_pointer); - else - D64(cie_pointer); - } else { - D32(entry_length_->length); - entry_length_->start = Here(); - if (eh_frame_) - D32(Here() - cie_pointer); - else - D32(cie_pointer); - } - EncodedPointer(initial_location); - // The FDE length in an .eh_frame section uses the same encoding as the - // initial location, but ignores the base address (selected by the upper - // nybble of the encoding), as it's a length, not an address that can be - // made relative. - EncodedPointer(address_range, - DwarfPointerEncoding(pointer_encoding_ & 0x0f)); - return *this; -} - -CFISection &CFISection::FinishEntry() { - assert(entry_length_); - Align(address_size_, lul::DW_CFA_nop); - entry_length_->length = Here() - entry_length_->start; - delete entry_length_; - entry_length_ = NULL; - in_fde_ = false; - return *this; -} - -CFISection &CFISection::EncodedPointer(uint64_t address, - DwarfPointerEncoding encoding, - const EncodedPointerBases &bases) { - // Omitted data is extremely easy to emit. - if (encoding == lul::DW_EH_PE_omit) - return *this; - - // If (encoding & lul::DW_EH_PE_indirect) != 0, then we assume - // that ADDRESS is the address at which the pointer is stored --- in - // other words, that bit has no effect on how we write the pointer. - encoding = DwarfPointerEncoding(encoding & ~lul::DW_EH_PE_indirect); - - // Find the base address to which this pointer is relative. The upper - // nybble of the encoding specifies this. - uint64_t base; - switch (encoding & 0xf0) { - case lul::DW_EH_PE_absptr: base = 0; break; - case lul::DW_EH_PE_pcrel: base = bases.cfi + Size(); break; - case lul::DW_EH_PE_textrel: base = bases.text; break; - case lul::DW_EH_PE_datarel: base = bases.data; break; - case lul::DW_EH_PE_funcrel: base = fde_start_address_; break; - case lul::DW_EH_PE_aligned: base = 0; break; - default: abort(); - }; - - // Make ADDRESS relative. Yes, this is appropriate even for "absptr" - // values; see gcc/unwind-pe.h. - address -= base; - - // Align the pointer, if required. - if ((encoding & 0xf0) == lul::DW_EH_PE_aligned) - Align(AddressSize()); - - // Append ADDRESS to this section in the appropriate form. For the - // fixed-width forms, we don't need to differentiate between signed and - // unsigned encodings, because ADDRESS has already been extended to 64 - // bits before it was passed to us. - switch (encoding & 0x0f) { - case lul::DW_EH_PE_absptr: - Address(address); - break; - - case lul::DW_EH_PE_uleb128: - ULEB128(address); - break; - - case lul::DW_EH_PE_sleb128: - LEB128(address); - break; - - case lul::DW_EH_PE_udata2: - case lul::DW_EH_PE_sdata2: - D16(address); - break; - - case lul::DW_EH_PE_udata4: - case lul::DW_EH_PE_sdata4: - D32(address); - break; - - case lul::DW_EH_PE_udata8: - case lul::DW_EH_PE_sdata8: - D64(address); - break; - - default: - abort(); - } - - return *this; -}; - -} // namespace lul_test diff --git a/tools/profiler/tests/gtest/LulTestInfrastructure.h b/tools/profiler/tests/gtest/LulTestInfrastructure.h deleted file mode 100644 index 37b1b7d49..000000000 --- a/tools/profiler/tests/gtest/LulTestInfrastructure.h +++ /dev/null @@ -1,666 +0,0 @@ -// -*- mode: C++ -*- - -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// Derived from: -// cfi_assembler.h: Define CFISection, a class for creating properly -// (and improperly) formatted DWARF CFI data for unit tests. - -// Derived from: -// test-assembler.h: interface to class for building complex binary streams. - -// To test the Breakpad symbol dumper and processor thoroughly, for -// all combinations of host system and minidump processor -// architecture, we need to be able to easily generate complex test -// data like debugging information and minidump files. -// -// For example, if we want our unit tests to provide full code -// coverage for stack walking, it may be difficult to persuade the -// compiler to generate every possible sort of stack walking -// information that we want to support; there are probably DWARF CFI -// opcodes that GCC never emits. Similarly, if we want to test our -// error handling, we will need to generate damaged minidumps or -// debugging information that (we hope) the client or compiler will -// never produce on its own. -// -// google_breakpad::TestAssembler provides a predictable and -// (relatively) simple way to generate complex formatted data streams -// like minidumps and CFI. Furthermore, because TestAssembler is -// portable, developers without access to (say) Visual Studio or a -// SPARC assembler can still work on test data for those targets. - -#ifndef LUL_TEST_INFRASTRUCTURE_H -#define LUL_TEST_INFRASTRUCTURE_H - -#include <string> -#include <vector> - -using std::string; -using std::vector; - -namespace lul_test { -namespace test_assembler { - -// A Label represents a value not yet known that we need to store in a -// section. As long as all the labels a section refers to are defined -// by the time we retrieve its contents as bytes, we can use undefined -// labels freely in that section's construction. -// -// A label can be in one of three states: -// - undefined, -// - defined as the sum of some other label and a constant, or -// - a constant. -// -// A label's value never changes, but it can accumulate constraints. -// Adding labels and integers is permitted, and yields a label. -// Subtracting a constant from a label is permitted, and also yields a -// label. Subtracting two labels that have some relationship to each -// other is permitted, and yields a constant. -// -// For example: -// -// Label a; // a's value is undefined -// Label b; // b's value is undefined -// { -// Label c = a + 4; // okay, even though a's value is unknown -// b = c + 4; // also okay; b is now a+8 -// } -// Label d = b - 2; // okay; d == a+6, even though c is gone -// d.Value(); // error: d's value is not yet known -// d - a; // is 6, even though their values are not known -// a = 12; // now b == 20, and d == 18 -// d.Value(); // 18: no longer an error -// b.Value(); // 20 -// d = 10; // error: d is already defined. -// -// Label objects' lifetimes are unconstrained: notice that, in the -// above example, even though a and b are only related through c, and -// c goes out of scope, the assignment to a sets b's value as well. In -// particular, it's not necessary to ensure that a Label lives beyond -// Sections that refer to it. -class Label { - public: - Label(); // An undefined label. - explicit Label(uint64_t value); // A label with a fixed value - Label(const Label &value); // A label equal to another. - ~Label(); - - Label &operator=(uint64_t value); - Label &operator=(const Label &value); - Label operator+(uint64_t addend) const; - Label operator-(uint64_t subtrahend) const; - uint64_t operator-(const Label &subtrahend) const; - - // We could also provide == and != that work on undefined, but - // related, labels. - - // Return true if this label's value is known. If VALUE_P is given, - // set *VALUE_P to the known value if returning true. - bool IsKnownConstant(uint64_t *value_p = NULL) const; - - // Return true if the offset from LABEL to this label is known. If - // OFFSET_P is given, set *OFFSET_P to the offset when returning true. - // - // You can think of l.KnownOffsetFrom(m, &d) as being like 'd = l-m', - // except that it also returns a value indicating whether the - // subtraction is possible given what we currently know of l and m. - // It can be possible even if we don't know l and m's values. For - // example: - // - // Label l, m; - // m = l + 10; - // l.IsKnownConstant(); // false - // m.IsKnownConstant(); // false - // uint64_t d; - // l.IsKnownOffsetFrom(m, &d); // true, and sets d to -10. - // l-m // -10 - // m-l // 10 - // m.Value() // error: m's value is not known - bool IsKnownOffsetFrom(const Label &label, uint64_t *offset_p = NULL) const; - - private: - // A label's value, or if that is not yet known, how the value is - // related to other labels' values. A binding may be: - // - a known constant, - // - constrained to be equal to some other binding plus a constant, or - // - unconstrained, and free to take on any value. - // - // Many labels may point to a single binding, and each binding may - // refer to another, so bindings and labels form trees whose leaves - // are labels, whose interior nodes (and roots) are bindings, and - // where links point from children to parents. Bindings are - // reference counted, allowing labels to be lightweight, copyable, - // assignable, placed in containers, and so on. - class Binding { - public: - Binding(); - explicit Binding(uint64_t addend); - ~Binding(); - - // Increment our reference count. - void Acquire() { reference_count_++; }; - // Decrement our reference count, and return true if it is zero. - bool Release() { return --reference_count_ == 0; } - - // Set this binding to be equal to BINDING + ADDEND. If BINDING is - // NULL, then set this binding to the known constant ADDEND. - // Update every binding on this binding's chain to point directly - // to BINDING, or to be a constant, with addends adjusted - // appropriately. - void Set(Binding *binding, uint64_t value); - - // Return what we know about the value of this binding. - // - If this binding's value is a known constant, set BASE to - // NULL, and set ADDEND to its value. - // - If this binding is not a known constant but related to other - // bindings, set BASE to the binding at the end of the relation - // chain (which will always be unconstrained), and set ADDEND to the - // value to add to that binding's value to get this binding's - // value. - // - If this binding is unconstrained, set BASE to this, and leave - // ADDEND unchanged. - void Get(Binding **base, uint64_t *addend); - - private: - // There are three cases: - // - // - A binding representing a known constant value has base_ NULL, - // and addend_ equal to the value. - // - // - A binding representing a completely unconstrained value has - // base_ pointing to this; addend_ is unused. - // - // - A binding whose value is related to some other binding's - // value has base_ pointing to that other binding, and addend_ - // set to the amount to add to that binding's value to get this - // binding's value. We only represent relationships of the form - // x = y+c. - // - // Thus, the bind_ links form a chain terminating in either a - // known constant value or a completely unconstrained value. Most - // operations on bindings do path compression: they change every - // binding on the chain to point directly to the final value, - // adjusting addends as appropriate. - Binding *base_; - uint64_t addend_; - - // The number of Labels and Bindings pointing to this binding. - // (When a binding points to itself, indicating a completely - // unconstrained binding, that doesn't count as a reference.) - int reference_count_; - }; - - // This label's value. - Binding *value_; -}; - -// Conventions for representing larger numbers as sequences of bytes. -enum Endianness { - kBigEndian, // Big-endian: the most significant byte comes first. - kLittleEndian, // Little-endian: the least significant byte comes first. - kUnsetEndian, // used internally -}; - -// A section is a sequence of bytes, constructed by appending bytes -// to the end. Sections have a convenient and flexible set of member -// functions for appending data in various formats: big-endian and -// little-endian signed and unsigned values of different sizes; -// LEB128 and ULEB128 values (see below), and raw blocks of bytes. -// -// If you need to append a value to a section that is not convenient -// to compute immediately, you can create a label, append the -// label's value to the section, and then set the label's value -// later, when it's convenient to do so. Once a label's value is -// known, the section class takes care of updating all previously -// appended references to it. -// -// Once all the labels to which a section refers have had their -// values determined, you can get a copy of the section's contents -// as a string. -// -// Note that there is no specified "start of section" label. This is -// because there are typically several different meanings for "the -// start of a section": the offset of the section within an object -// file, the address in memory at which the section's content appear, -// and so on. It's up to the code that uses the Section class to -// keep track of these explicitly, as they depend on the application. -class Section { - public: - explicit Section(Endianness endianness = kUnsetEndian) - : endianness_(endianness) { }; - - // A base class destructor should be either public and virtual, - // or protected and nonvirtual. - virtual ~Section() { }; - - // Return the default endianness of this section. - Endianness endianness() const { return endianness_; } - - // Append the SIZE bytes at DATA to the end of this section. Return - // a reference to this section. - Section &Append(const string &data) { - contents_.append(data); - return *this; - }; - - // Append SIZE copies of BYTE to the end of this section. Return a - // reference to this section. - Section &Append(size_t size, uint8_t byte) { - contents_.append(size, (char) byte); - return *this; - } - - // Append NUMBER to this section. ENDIANNESS is the endianness to - // use to write the number. SIZE is the length of the number in - // bytes. Return a reference to this section. - Section &Append(Endianness endianness, size_t size, uint64_t number); - Section &Append(Endianness endianness, size_t size, const Label &label); - - // Append SECTION to the end of this section. The labels SECTION - // refers to need not be defined yet. - // - // Note that this has no effect on any Labels' values, or on - // SECTION. If placing SECTION within 'this' provides new - // constraints on existing labels' values, then it's up to the - // caller to fiddle with those labels as needed. - Section &Append(const Section §ion); - - // Append the contents of DATA as a series of bytes terminated by - // a NULL character. - Section &AppendCString(const string &data) { - Append(data); - contents_ += '\0'; - return *this; - } - - // Append VALUE or LABEL to this section, with the given bit width and - // endianness. Return a reference to this section. - // - // The names of these functions have the form <ENDIANNESS><BITWIDTH>: - // <ENDIANNESS> is either 'L' (little-endian, least significant byte first), - // 'B' (big-endian, most significant byte first), or - // 'D' (default, the section's default endianness) - // <BITWIDTH> is 8, 16, 32, or 64. - // - // Since endianness doesn't matter for a single byte, all the - // <BITWIDTH>=8 functions are equivalent. - // - // These can be used to write both signed and unsigned values, as - // the compiler will properly sign-extend a signed value before - // passing it to the function, at which point the function's - // behavior is the same either way. - Section &L8(uint8_t value) { contents_ += value; return *this; } - Section &B8(uint8_t value) { contents_ += value; return *this; } - Section &D8(uint8_t value) { contents_ += value; return *this; } - Section &L16(uint16_t), &L32(uint32_t), &L64(uint64_t), - &B16(uint16_t), &B32(uint32_t), &B64(uint64_t), - &D16(uint16_t), &D32(uint32_t), &D64(uint64_t); - Section &L8(const Label &label), &L16(const Label &label), - &L32(const Label &label), &L64(const Label &label), - &B8(const Label &label), &B16(const Label &label), - &B32(const Label &label), &B64(const Label &label), - &D8(const Label &label), &D16(const Label &label), - &D32(const Label &label), &D64(const Label &label); - - // Append VALUE in a signed LEB128 (Little-Endian Base 128) form. - // - // The signed LEB128 representation of an integer N is a variable - // number of bytes: - // - // - If N is between -0x40 and 0x3f, then its signed LEB128 - // representation is a single byte whose value is N. - // - // - Otherwise, its signed LEB128 representation is (N & 0x7f) | - // 0x80, followed by the signed LEB128 representation of N / 128, - // rounded towards negative infinity. - // - // In other words, we break VALUE into groups of seven bits, put - // them in little-endian order, and then write them as eight-bit - // bytes with the high bit on all but the last. - // - // Note that VALUE cannot be a Label (we would have to implement - // relaxation). - Section &LEB128(long long value); - - // Append VALUE in unsigned LEB128 (Little-Endian Base 128) form. - // - // The unsigned LEB128 representation of an integer N is a variable - // number of bytes: - // - // - If N is between 0 and 0x7f, then its unsigned LEB128 - // representation is a single byte whose value is N. - // - // - Otherwise, its unsigned LEB128 representation is (N & 0x7f) | - // 0x80, followed by the unsigned LEB128 representation of N / - // 128, rounded towards negative infinity. - // - // Note that VALUE cannot be a Label (we would have to implement - // relaxation). - Section &ULEB128(uint64_t value); - - // Jump to the next location aligned on an ALIGNMENT-byte boundary, - // relative to the start of the section. Fill the gap with PAD_BYTE. - // ALIGNMENT must be a power of two. Return a reference to this - // section. - Section &Align(size_t alignment, uint8_t pad_byte = 0); - - // Return the current size of the section. - size_t Size() const { return contents_.size(); } - - // Return a label representing the start of the section. - // - // It is up to the user whether this label represents the section's - // position in an object file, the section's address in memory, or - // what have you; some applications may need both, in which case - // this simple-minded interface won't be enough. This class only - // provides a single start label, for use with the Here and Mark - // member functions. - // - // Ideally, we'd provide this in a subclass that actually knows more - // about the application at hand and can provide an appropriate - // collection of start labels. But then the appending member - // functions like Append and D32 would return a reference to the - // base class, not the derived class, and the chaining won't work. - // Since the only value here is in pretty notation, that's a fatal - // flaw. - Label start() const { return start_; } - - // Return a label representing the point at which the next Appended - // item will appear in the section, relative to start(). - Label Here() const { return start_ + Size(); } - - // Set *LABEL to Here, and return a reference to this section. - Section &Mark(Label *label) { *label = Here(); return *this; } - - // If there are no undefined label references left in this - // section, set CONTENTS to the contents of this section, as a - // string, and clear this section. Return true on success, or false - // if there were still undefined labels. - bool GetContents(string *contents); - - private: - // Used internally. A reference to a label's value. - struct Reference { - Reference(size_t set_offset, Endianness set_endianness, size_t set_size, - const Label &set_label) - : offset(set_offset), endianness(set_endianness), size(set_size), - label(set_label) { } - - // The offset of the reference within the section. - size_t offset; - - // The endianness of the reference. - Endianness endianness; - - // The size of the reference. - size_t size; - - // The label to which this is a reference. - Label label; - }; - - // The default endianness of this section. - Endianness endianness_; - - // The contents of the section. - string contents_; - - // References to labels within those contents. - vector<Reference> references_; - - // A label referring to the beginning of the section. - Label start_; -}; - -} // namespace test_assembler -} // namespace lul_test - - -namespace lul_test { - -using lul::DwarfPointerEncoding; -using lul_test::test_assembler::Endianness; -using lul_test::test_assembler::Label; -using lul_test::test_assembler::Section; - -class CFISection: public Section { - public: - - // CFI augmentation strings beginning with 'z', defined by the - // Linux/IA-64 C++ ABI, can specify interesting encodings for - // addresses appearing in FDE headers and call frame instructions (and - // for additional fields whose presence the augmentation string - // specifies). In particular, pointers can be specified to be relative - // to various base address: the start of the .text section, the - // location holding the address itself, and so on. These allow the - // frame data to be position-independent even when they live in - // write-protected pages. These variants are specified at the - // following two URLs: - // - // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html - // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html - // - // CFISection leaves the production of well-formed 'z'-augmented CIEs and - // FDEs to the user, but does provide EncodedPointer, to emit - // properly-encoded addresses for a given pointer encoding. - // EncodedPointer uses an instance of this structure to find the base - // addresses it should use; you can establish a default for all encoded - // pointers appended to this section with SetEncodedPointerBases. - struct EncodedPointerBases { - EncodedPointerBases() : cfi(), text(), data() { } - - // The starting address of this CFI section in memory, for - // DW_EH_PE_pcrel. DW_EH_PE_pcrel pointers may only be used in data - // that has is loaded into the program's address space. - uint64_t cfi; - - // The starting address of this file's .text section, for DW_EH_PE_textrel. - uint64_t text; - - // The starting address of this file's .got or .eh_frame_hdr section, - // for DW_EH_PE_datarel. - uint64_t data; - }; - - // Create a CFISection whose endianness is ENDIANNESS, and where - // machine addresses are ADDRESS_SIZE bytes long. If EH_FRAME is - // true, use the .eh_frame format, as described by the Linux - // Standards Base Core Specification, instead of the DWARF CFI - // format. - CFISection(Endianness endianness, size_t address_size, - bool eh_frame = false) - : Section(endianness), address_size_(address_size), eh_frame_(eh_frame), - pointer_encoding_(lul::DW_EH_PE_absptr), - encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) { - // The 'start', 'Here', and 'Mark' members of a CFISection all refer - // to section offsets. - start() = 0; - } - - // Return this CFISection's address size. - size_t AddressSize() const { return address_size_; } - - // Return true if this CFISection uses the .eh_frame format, or - // false if it contains ordinary DWARF CFI data. - bool ContainsEHFrame() const { return eh_frame_; } - - // Use ENCODING for pointers in calls to FDEHeader and EncodedPointer. - void SetPointerEncoding(DwarfPointerEncoding encoding) { - pointer_encoding_ = encoding; - } - - // Use the addresses in BASES as the base addresses for encoded - // pointers in subsequent calls to FDEHeader or EncodedPointer. - // This function makes a copy of BASES. - void SetEncodedPointerBases(const EncodedPointerBases &bases) { - encoded_pointer_bases_ = bases; - } - - // Append a Common Information Entry header to this section with the - // given values. If dwarf64 is true, use the 64-bit DWARF initial - // length format for the CIE's initial length. Return a reference to - // this section. You should call FinishEntry after writing the last - // instruction for the CIE. - // - // Before calling this function, you will typically want to use Mark - // or Here to make a label to pass to FDEHeader that refers to this - // CIE's position in the section. - CFISection &CIEHeader(uint64_t code_alignment_factor, - int data_alignment_factor, - unsigned return_address_register, - uint8_t version = 3, - const string &augmentation = "", - bool dwarf64 = false); - - // Append a Frame Description Entry header to this section with the - // given values. If dwarf64 is true, use the 64-bit DWARF initial - // length format for the CIE's initial length. Return a reference to - // this section. You should call FinishEntry after writing the last - // instruction for the CIE. - // - // This function doesn't support entries that are longer than - // 0xffffff00 bytes. (The "initial length" is always a 32-bit - // value.) Nor does it support .debug_frame sections longer than - // 0xffffff00 bytes. - CFISection &FDEHeader(Label cie_pointer, - uint64_t initial_location, - uint64_t address_range, - bool dwarf64 = false); - - // Note the current position as the end of the last CIE or FDE we - // started, after padding with DW_CFA_nops for alignment. This - // defines the label representing the entry's length, cited in the - // entry's header. Return a reference to this section. - CFISection &FinishEntry(); - - // Append the contents of BLOCK as a DW_FORM_block value: an - // unsigned LEB128 length, followed by that many bytes of data. - CFISection &Block(const string &block) { - ULEB128(block.size()); - Append(block); - return *this; - } - - // Append ADDRESS to this section, in the appropriate size and - // endianness. Return a reference to this section. - CFISection &Address(uint64_t address) { - Section::Append(endianness(), address_size_, address); - return *this; - } - - // Append ADDRESS to this section, using ENCODING and BASES. ENCODING - // defaults to this section's default encoding, established by - // SetPointerEncoding. BASES defaults to this section's bases, set by - // SetEncodedPointerBases. If the DW_EH_PE_indirect bit is set in the - // encoding, assume that ADDRESS is where the true address is stored. - // Return a reference to this section. - // - // (C++ doesn't let me use default arguments here, because I want to - // refer to members of *this in the default argument expression.) - CFISection &EncodedPointer(uint64_t address) { - return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_); - } - CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) { - return EncodedPointer(address, encoding, encoded_pointer_bases_); - } - CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding, - const EncodedPointerBases &bases); - - // Restate some member functions, to keep chaining working nicely. - CFISection &Mark(Label *label) { Section::Mark(label); return *this; } - CFISection &D8(uint8_t v) { Section::D8(v); return *this; } - CFISection &D16(uint16_t v) { Section::D16(v); return *this; } - CFISection &D16(Label v) { Section::D16(v); return *this; } - CFISection &D32(uint32_t v) { Section::D32(v); return *this; } - CFISection &D32(const Label &v) { Section::D32(v); return *this; } - CFISection &D64(uint64_t v) { Section::D64(v); return *this; } - CFISection &D64(const Label &v) { Section::D64(v); return *this; } - CFISection &LEB128(long long v) { Section::LEB128(v); return *this; } - CFISection &ULEB128(uint64_t v) { Section::ULEB128(v); return *this; } - - private: - // A length value that we've appended to the section, but is not yet - // known. LENGTH is the appended value; START is a label referring - // to the start of the data whose length was cited. - struct PendingLength { - Label length; - Label start; - }; - - // Constants used in CFI/.eh_frame data: - - // If the first four bytes of an "initial length" are this constant, then - // the data uses the 64-bit DWARF format, and the length itself is the - // subsequent eight bytes. - static const uint32_t kDwarf64InitialLengthMarker = 0xffffffffU; - - // The CIE identifier for 32- and 64-bit DWARF CFI and .eh_frame data. - static const uint32_t kDwarf32CIEIdentifier = ~(uint32_t)0; - static const uint64_t kDwarf64CIEIdentifier = ~(uint64_t)0; - static const uint32_t kEHFrame32CIEIdentifier = 0; - static const uint64_t kEHFrame64CIEIdentifier = 0; - - // The size of a machine address for the data in this section. - size_t address_size_; - - // If true, we are generating a Linux .eh_frame section, instead of - // a standard DWARF .debug_frame section. - bool eh_frame_; - - // The encoding to use for FDE pointers. - DwarfPointerEncoding pointer_encoding_; - - // The base addresses to use when emitting encoded pointers. - EncodedPointerBases encoded_pointer_bases_; - - // The length value for the current entry. - // - // Oddly, this must be dynamically allocated. Labels never get new - // values; they only acquire constraints on the value they already - // have, or assert if you assign them something incompatible. So - // each header needs truly fresh Label objects to cite in their - // headers and track their positions. The alternative is explicit - // destructor invocation and a placement new. Ick. - PendingLength *entry_length_; - - // True if we are currently emitting an FDE --- that is, we have - // called FDEHeader but have not yet called FinishEntry. - bool in_fde_; - - // If in_fde_ is true, this is its starting address. We use this for - // emitting DW_EH_PE_funcrel pointers. - uint64_t fde_start_address_; -}; - -} // namespace lul_test - -#endif // LUL_TEST_INFRASTRUCTURE_H diff --git a/tools/profiler/tests/gtest/ThreadProfileTest.cpp b/tools/profiler/tests/gtest/ThreadProfileTest.cpp deleted file mode 100644 index 4399a5bc2..000000000 --- a/tools/profiler/tests/gtest/ThreadProfileTest.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "gtest/gtest.h" - -#include "ProfileEntry.h" -#include "ThreadProfile.h" - -// Make sure we can initialize our ThreadProfile -TEST(ThreadProfile, Initialization) { - PseudoStack* stack = PseudoStack::create(); - Thread::tid_t tid = 1000; - ThreadInfo info("testThread", tid, true, stack, nullptr); - RefPtr<ProfileBuffer> pb = new ProfileBuffer(10); - ThreadProfile tp(&info, pb); -} - -// Make sure we can record one tag and read it -TEST(ThreadProfile, InsertOneTag) { - PseudoStack* stack = PseudoStack::create(); - Thread::tid_t tid = 1000; - ThreadInfo info("testThread", tid, true, stack, nullptr); - RefPtr<ProfileBuffer> pb = new ProfileBuffer(10); - pb->addTag(ProfileEntry('t', 123.1)); - ASSERT_TRUE(pb->mEntries != nullptr); - ASSERT_TRUE(pb->mEntries[pb->mReadPos].mTagName == 't'); - ASSERT_TRUE(pb->mEntries[pb->mReadPos].mTagDouble == 123.1); -} - -// See if we can insert some tags -TEST(ThreadProfile, InsertTagsNoWrap) { - PseudoStack* stack = PseudoStack::create(); - Thread::tid_t tid = 1000; - ThreadInfo info("testThread", tid, true, stack, nullptr); - RefPtr<ProfileBuffer> pb = new ProfileBuffer(100); - int test_size = 50; - for (int i = 0; i < test_size; i++) { - pb->addTag(ProfileEntry('t', i)); - } - ASSERT_TRUE(pb->mEntries != nullptr); - int readPos = pb->mReadPos; - while (readPos != pb->mWritePos) { - ASSERT_TRUE(pb->mEntries[readPos].mTagName == 't'); - ASSERT_TRUE(pb->mEntries[readPos].mTagInt == readPos); - readPos = (readPos + 1) % pb->mEntrySize; - } -} - -// See if wrapping works as it should in the basic case -TEST(ThreadProfile, InsertTagsWrap) { - PseudoStack* stack = PseudoStack::create(); - Thread::tid_t tid = 1000; - // we can fit only 24 tags in this buffer because of the empty slot - int tags = 24; - int buffer_size = tags + 1; - ThreadInfo info("testThread", tid, true, stack, nullptr); - RefPtr<ProfileBuffer> pb = new ProfileBuffer(buffer_size); - int test_size = 43; - for (int i = 0; i < test_size; i++) { - pb->addTag(ProfileEntry('t', i)); - } - ASSERT_TRUE(pb->mEntries != nullptr); - int readPos = pb->mReadPos; - int ctr = 0; - while (readPos != pb->mWritePos) { - ASSERT_TRUE(pb->mEntries[readPos].mTagName == 't'); - // the first few tags were discarded when we wrapped - ASSERT_TRUE(pb->mEntries[readPos].mTagInt == ctr + (test_size - tags)); - ctr++; - readPos = (readPos + 1) % pb->mEntrySize; - } -} - diff --git a/tools/profiler/tests/gtest/moz.build b/tools/profiler/tests/gtest/moz.build deleted file mode 100644 index 33aded164..000000000 --- a/tools/profiler/tests/gtest/moz.build +++ /dev/null @@ -1,30 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, you can obtain one at http://mozilla.org/MPL/2.0/. - -if CONFIG['OS_TARGET'] in ('Android', 'Linux'): - UNIFIED_SOURCES += [ - 'LulTestDwarf.cpp', - 'LulTestInfrastructure.cpp', - ] - if CONFIG['CPU_ARCH'] != 'x86': - UNIFIED_SOURCES += [ - 'LulTest.cpp', - ] - -LOCAL_INCLUDES += [ - '/tools/profiler/core', - '/tools/profiler/gecko', - '/tools/profiler/lul', -] - -UNIFIED_SOURCES += [ - 'ThreadProfileTest.cpp', -] - -FINAL_LIBRARY = 'xul-gtest' - -if CONFIG['GNU_CXX']: - CXXFLAGS += ['-Wno-error=shadow'] |