summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc')
-rw-r--r--toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc370
1 files changed, 370 insertions, 0 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc
new file mode 100644
index 0000000000..8984449ab6
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc
@@ -0,0 +1,370 @@
+// Copyright (c) 2011 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: Ted Mielczarek <ted.mielczarek@gmail.com>
+
+// elf_symbols_to_module_unittest.cc:
+// Unittests for google_breakpad::ELFSymbolsToModule
+
+#include <elf.h>
+
+#include <string>
+#include <vector>
+
+#include "breakpad_googletest_includes.h"
+#include "common/linux/elf_symbols_to_module.h"
+#include "common/linux/synth_elf.h"
+#include "common/module.h"
+#include "common/test_assembler.h"
+#include "common/using_std_string.h"
+
+using google_breakpad::Module;
+using google_breakpad::synth_elf::StringTable;
+using google_breakpad::test_assembler::Endianness;
+using google_breakpad::test_assembler::kBigEndian;
+using google_breakpad::test_assembler::kLittleEndian;
+using google_breakpad::test_assembler::Label;
+using google_breakpad::test_assembler::Section;
+using ::testing::Test;
+using ::testing::TestWithParam;
+using std::vector;
+
+class ELFSymbolsToModuleTestFixture {
+public:
+ ELFSymbolsToModuleTestFixture(Endianness endianness,
+ size_t value_size) : module("a", "b", "c", "d"),
+ section(endianness),
+ table(endianness),
+ value_size(value_size) {}
+
+ bool ProcessSection() {
+ string section_contents, table_contents;
+ section.GetContents(&section_contents);
+ table.GetContents(&table_contents);
+
+ bool ret = ELFSymbolsToModule(reinterpret_cast<const uint8_t*>(section_contents.data()),
+ section_contents.size(),
+ reinterpret_cast<const uint8_t*>(table_contents.data()),
+ table_contents.size(),
+ section.endianness() == kBigEndian,
+ value_size,
+ &module);
+ module.GetExterns(&externs, externs.end());
+ return ret;
+ }
+
+ Module module;
+ Section section;
+ StringTable table;
+ string section_contents;
+ // 4 or 8 (bytes)
+ size_t value_size;
+
+ vector<Module::Extern *> externs;
+};
+
+class ELFSymbolsToModuleTest32 : public ELFSymbolsToModuleTestFixture,
+ public TestWithParam<Endianness> {
+public:
+ ELFSymbolsToModuleTest32() : ELFSymbolsToModuleTestFixture(GetParam(), 4) {}
+
+ void AddElf32Sym(const string& name, uint32_t value,
+ uint32_t size, unsigned info, uint16_t shndx) {
+ section
+ .D32(table.Add(name))
+ .D32(value)
+ .D32(size)
+ .D8(info)
+ .D8(0) // other
+ .D16(shndx);
+ }
+};
+
+TEST_P(ELFSymbolsToModuleTest32, NoFuncs) {
+ ProcessSection();
+
+ ASSERT_EQ((size_t)0, externs.size());
+}
+
+TEST_P(ELFSymbolsToModuleTest32, OneFunc) {
+ const string kFuncName = "superfunc";
+ const uint32_t kFuncAddr = 0x1000;
+ const uint32_t kFuncSize = 0x10;
+
+ AddElf32Sym(kFuncName, kFuncAddr, kFuncSize,
+ ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
+ // Doesn't really matter, just can't be SHN_UNDEF.
+ SHN_UNDEF + 1);
+
+ ProcessSection();
+
+ ASSERT_EQ((size_t)1, externs.size());
+ Module::Extern *extern1 = externs[0];
+ EXPECT_EQ(kFuncName, extern1->name);
+ EXPECT_EQ((Module::Address)kFuncAddr, extern1->address);
+}
+
+TEST_P(ELFSymbolsToModuleTest32, NameOutOfBounds) {
+ const string kFuncName = "";
+ const uint32_t kFuncAddr = 0x1000;
+ const uint32_t kFuncSize = 0x10;
+
+ table.Add("Foo");
+ table.Add("Bar");
+ // Can't use AddElf32Sym because it puts in a valid string offset.
+ section
+ .D32((uint32_t)table.Here().Value() + 1)
+ .D32(kFuncAddr)
+ .D32(kFuncSize)
+ .D8(ELF32_ST_INFO(STB_GLOBAL, STT_FUNC))
+ .D8(0) // other
+ .D16(SHN_UNDEF + 1);
+
+ ProcessSection();
+
+ ASSERT_EQ((size_t)1, externs.size());
+ Module::Extern *extern1 = externs[0];
+ EXPECT_EQ(kFuncName, extern1->name);
+ EXPECT_EQ((Module::Address)kFuncAddr, extern1->address);
+}
+
+TEST_P(ELFSymbolsToModuleTest32, NonTerminatedStringTable) {
+ const string kFuncName = "";
+ const uint32_t kFuncAddr = 0x1000;
+ const uint32_t kFuncSize = 0x10;
+
+ table.Add("Foo");
+ table.Add("Bar");
+ // Add a non-null-terminated string to the end of the string table
+ Label l;
+ table
+ .Mark(&l)
+ .Append("Unterminated");
+ // Can't use AddElf32Sym because it puts in a valid string offset.
+ section
+ .D32((uint32_t)l.Value())
+ .D32(kFuncAddr)
+ .D32(kFuncSize)
+ .D8(ELF32_ST_INFO(STB_GLOBAL, STT_FUNC))
+ .D8(0) // other
+ .D16(SHN_UNDEF + 1);
+
+ ProcessSection();
+
+ ASSERT_EQ((size_t)1, externs.size());
+ Module::Extern *extern1 = externs[0];
+ EXPECT_EQ(kFuncName, extern1->name);
+ EXPECT_EQ((Module::Address)kFuncAddr, extern1->address);
+}
+
+TEST_P(ELFSymbolsToModuleTest32, MultipleFuncs) {
+ const string kFuncName1 = "superfunc";
+ const uint32_t kFuncAddr1 = 0x10001000;
+ const uint32_t kFuncSize1 = 0x10;
+ const string kFuncName2 = "awesomefunc";
+ const uint32_t kFuncAddr2 = 0x20002000;
+ const uint32_t kFuncSize2 = 0x2f;
+ const string kFuncName3 = "megafunc";
+ const uint32_t kFuncAddr3 = 0x30003000;
+ const uint32_t kFuncSize3 = 0x3c;
+
+ AddElf32Sym(kFuncName1, kFuncAddr1, kFuncSize1,
+ ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
+ // Doesn't really matter, just can't be SHN_UNDEF.
+ SHN_UNDEF + 1);
+ AddElf32Sym(kFuncName2, kFuncAddr2, kFuncSize2,
+ ELF32_ST_INFO(STB_LOCAL, STT_FUNC),
+ // Doesn't really matter, just can't be SHN_UNDEF.
+ SHN_UNDEF + 2);
+ AddElf32Sym(kFuncName3, kFuncAddr3, kFuncSize3,
+ ELF32_ST_INFO(STB_LOCAL, STT_FUNC),
+ // Doesn't really matter, just can't be SHN_UNDEF.
+ SHN_UNDEF + 3);
+
+ ProcessSection();
+
+ ASSERT_EQ((size_t)3, externs.size());
+ Module::Extern *extern1 = externs[0];
+ EXPECT_EQ(kFuncName1, extern1->name);
+ EXPECT_EQ((Module::Address)kFuncAddr1, extern1->address);
+ Module::Extern *extern2 = externs[1];
+ EXPECT_EQ(kFuncName2, extern2->name);
+ EXPECT_EQ((Module::Address)kFuncAddr2, extern2->address);
+ Module::Extern *extern3 = externs[2];
+ EXPECT_EQ(kFuncName3, extern3->name);
+ EXPECT_EQ((Module::Address)kFuncAddr3, extern3->address);
+}
+
+TEST_P(ELFSymbolsToModuleTest32, SkipStuff) {
+ const string kFuncName = "superfunc";
+ const uint32_t kFuncAddr = 0x1000;
+ const uint32_t kFuncSize = 0x10;
+
+ // Should skip functions in SHN_UNDEF
+ AddElf32Sym("skipme", 0xFFFF, 0x10,
+ ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
+ SHN_UNDEF);
+ AddElf32Sym(kFuncName, kFuncAddr, kFuncSize,
+ ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
+ // Doesn't really matter, just can't be SHN_UNDEF.
+ SHN_UNDEF + 1);
+ // Should skip non-STT_FUNC entries.
+ AddElf32Sym("skipmetoo", 0xAAAA, 0x10,
+ ELF32_ST_INFO(STB_GLOBAL, STT_FILE),
+ SHN_UNDEF + 1);
+
+ ProcessSection();
+
+ ASSERT_EQ((size_t)1, externs.size());
+ Module::Extern *extern1 = externs[0];
+ EXPECT_EQ(kFuncName, extern1->name);
+ EXPECT_EQ((Module::Address)kFuncAddr, extern1->address);
+}
+
+// Run all the 32-bit tests with both endianness
+INSTANTIATE_TEST_CASE_P(Endian,
+ ELFSymbolsToModuleTest32,
+ ::testing::Values(kLittleEndian, kBigEndian));
+
+// Similar tests, but with 64-bit values. Ostensibly this could be
+// shoehorned into the parameterization by using ::testing::Combine,
+// but that would make it difficult to get the types right since these
+// actual test cases aren't parameterized. This could also be written
+// as a type-parameterized test, but combining that with a value-parameterized
+// test seemed really ugly, and also makes it harder to test 64-bit
+// values.
+class ELFSymbolsToModuleTest64 : public ELFSymbolsToModuleTestFixture,
+ public TestWithParam<Endianness> {
+public:
+ ELFSymbolsToModuleTest64() : ELFSymbolsToModuleTestFixture(GetParam(), 8) {}
+
+ void AddElf64Sym(const string& name, uint64_t value,
+ uint64_t size, unsigned info, uint16_t shndx) {
+ section
+ .D32(table.Add(name))
+ .D8(info)
+ .D8(0) // other
+ .D16(shndx)
+ .D64(value)
+ .D64(size);
+ }
+};
+
+TEST_P(ELFSymbolsToModuleTest64, NoFuncs) {
+ ProcessSection();
+
+ ASSERT_EQ((size_t)0, externs.size());
+}
+
+TEST_P(ELFSymbolsToModuleTest64, OneFunc) {
+ const string kFuncName = "superfunc";
+ const uint64_t kFuncAddr = 0x1000200030004000ULL;
+ const uint64_t kFuncSize = 0x1000;
+
+ AddElf64Sym(kFuncName, kFuncAddr, kFuncSize,
+ ELF64_ST_INFO(STB_GLOBAL, STT_FUNC),
+ // Doesn't really matter, just can't be SHN_UNDEF.
+ SHN_UNDEF + 1);
+
+ ProcessSection();
+
+ ASSERT_EQ((size_t)1, externs.size());
+ Module::Extern *extern1 = externs[0];
+ EXPECT_EQ(kFuncName, extern1->name);
+ EXPECT_EQ((Module::Address)kFuncAddr, extern1->address);
+}
+
+TEST_P(ELFSymbolsToModuleTest64, MultipleFuncs) {
+ const string kFuncName1 = "superfunc";
+ const uint64_t kFuncAddr1 = 0x1000100010001000ULL;
+ const uint64_t kFuncSize1 = 0x1000;
+ const string kFuncName2 = "awesomefunc";
+ const uint64_t kFuncAddr2 = 0x2000200020002000ULL;
+ const uint64_t kFuncSize2 = 0x2f00;
+ const string kFuncName3 = "megafunc";
+ const uint64_t kFuncAddr3 = 0x3000300030003000ULL;
+ const uint64_t kFuncSize3 = 0x3c00;
+
+ AddElf64Sym(kFuncName1, kFuncAddr1, kFuncSize1,
+ ELF64_ST_INFO(STB_GLOBAL, STT_FUNC),
+ // Doesn't really matter, just can't be SHN_UNDEF.
+ SHN_UNDEF + 1);
+ AddElf64Sym(kFuncName2, kFuncAddr2, kFuncSize2,
+ ELF64_ST_INFO(STB_LOCAL, STT_FUNC),
+ // Doesn't really matter, just can't be SHN_UNDEF.
+ SHN_UNDEF + 2);
+ AddElf64Sym(kFuncName3, kFuncAddr3, kFuncSize3,
+ ELF64_ST_INFO(STB_LOCAL, STT_FUNC),
+ // Doesn't really matter, just can't be SHN_UNDEF.
+ SHN_UNDEF + 3);
+
+ ProcessSection();
+
+ ASSERT_EQ((size_t)3, externs.size());
+ Module::Extern *extern1 = externs[0];
+ EXPECT_EQ(kFuncName1, extern1->name);
+ EXPECT_EQ((Module::Address)kFuncAddr1, extern1->address);
+ Module::Extern *extern2 = externs[1];
+ EXPECT_EQ(kFuncName2, extern2->name);
+ EXPECT_EQ((Module::Address)kFuncAddr2, extern2->address);
+ Module::Extern *extern3 = externs[2];
+ EXPECT_EQ(kFuncName3, extern3->name);
+ EXPECT_EQ((Module::Address)kFuncAddr3, extern3->address);
+}
+
+TEST_P(ELFSymbolsToModuleTest64, SkipStuff) {
+ const string kFuncName = "superfunc";
+ const uint64_t kFuncAddr = 0x1000100010001000ULL;
+ const uint64_t kFuncSize = 0x1000;
+
+ // Should skip functions in SHN_UNDEF
+ AddElf64Sym("skipme", 0xFFFF, 0x10,
+ ELF64_ST_INFO(STB_GLOBAL, STT_FUNC),
+ SHN_UNDEF);
+ AddElf64Sym(kFuncName, kFuncAddr, kFuncSize,
+ ELF64_ST_INFO(STB_GLOBAL, STT_FUNC),
+ // Doesn't really matter, just can't be SHN_UNDEF.
+ SHN_UNDEF + 1);
+ // Should skip non-STT_FUNC entries.
+ AddElf64Sym("skipmetoo", 0xAAAA, 0x10,
+ ELF64_ST_INFO(STB_GLOBAL, STT_FILE),
+ SHN_UNDEF + 1);
+
+ ProcessSection();
+
+ ASSERT_EQ((size_t)1, externs.size());
+ Module::Extern *extern1 = externs[0];
+ EXPECT_EQ(kFuncName, extern1->name);
+ EXPECT_EQ((Module::Address)kFuncAddr, extern1->address);
+}
+
+// Run all the 64-bit tests with both endianness
+INSTANTIATE_TEST_CASE_P(Endian,
+ ELFSymbolsToModuleTest64,
+ ::testing::Values(kLittleEndian, kBigEndian));