michael@0: // Copyright (c) 2010 Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: // Original author: Jim Blandy michael@0: michael@0: // module_unittest.cc: Unit tests for google_breakpad::Module. michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "breakpad_googletest_includes.h" michael@0: #include "common/module.h" michael@0: #include "common/using_std_string.h" michael@0: michael@0: using google_breakpad::Module; michael@0: using google_breakpad::ToUniqueString; michael@0: using google_breakpad::ustr__ZDcfa; michael@0: using std::stringstream; michael@0: using std::vector; michael@0: using testing::ContainerEq; michael@0: michael@0: static Module::Function *generate_duplicate_function(const string &name) { michael@0: const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cLL; michael@0: const Module::Address DUP_SIZE = 0x200b26e605f99071LL; michael@0: const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL; michael@0: michael@0: Module::Function *function = new(Module::Function); michael@0: function->name = name; michael@0: function->address = DUP_ADDRESS; michael@0: function->size = DUP_SIZE; michael@0: function->parameter_size = DUP_PARAMETER_SIZE; michael@0: return function; michael@0: } michael@0: michael@0: #define MODULE_NAME "name with spaces" michael@0: #define MODULE_OS "os-name" michael@0: #define MODULE_ARCH "architecture" michael@0: #define MODULE_ID "id-string" michael@0: michael@0: TEST(Write, Header) { michael@0: stringstream s; michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: m.Write(s, ALL_SYMBOL_DATA); michael@0: string contents = s.str(); michael@0: EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n", michael@0: contents.c_str()); michael@0: } michael@0: michael@0: TEST(Write, OneLineFunc) { michael@0: stringstream s; michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: Module::File *file = m.FindFile("file_name.cc"); michael@0: Module::Function *function = new(Module::Function); michael@0: function->name = "function_name"; michael@0: function->address = 0xe165bf8023b9d9abLL; michael@0: function->size = 0x1e4bb0eb1cbf5b09LL; michael@0: function->parameter_size = 0x772beee89114358aLL; michael@0: Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL, michael@0: file, 67519080 }; michael@0: function->lines.push_back(line); michael@0: m.AddFunction(function); michael@0: michael@0: m.Write(s, ALL_SYMBOL_DATA); michael@0: string contents = s.str(); michael@0: EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" michael@0: "FILE 0 file_name.cc\n" michael@0: "FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a" michael@0: " function_name\n" michael@0: "e165bf8023b9d9ab 1e4bb0eb1cbf5b09 67519080 0\n", michael@0: contents.c_str()); michael@0: } michael@0: michael@0: TEST(Write, RelativeLoadAddress) { michael@0: stringstream s; michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: // Some source files. We will expect to see them in lexicographic order. michael@0: Module::File *file1 = m.FindFile("filename-b.cc"); michael@0: Module::File *file2 = m.FindFile("filename-a.cc"); michael@0: michael@0: // A function. michael@0: Module::Function *function = new(Module::Function); michael@0: function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)"; michael@0: function->address = 0xbec774ea5dd935f3LL; michael@0: function->size = 0x2922088f98d3f6fcLL; michael@0: function->parameter_size = 0xe5e9aa008bd5f0d0LL; michael@0: michael@0: // Some source lines. The module should not sort these. michael@0: Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, michael@0: file1, 41676901 }; michael@0: Module::Line line2 = { 0xdaf35bc123885c04LL, 0xcf621b8d324d0ebLL, michael@0: file2, 67519080 }; michael@0: function->lines.push_back(line2); michael@0: function->lines.push_back(line1); michael@0: michael@0: m.AddFunction(function); michael@0: michael@0: // Some stack information. michael@0: Module::StackFrameEntry *entry = new Module::StackFrameEntry(); michael@0: entry->address = 0x30f9e5c83323973dULL; michael@0: entry->size = 0x49fc9ca7c7c13dc2ULL; michael@0: entry->initial_rules[ustr__ZDcfa()] = Module::Expr("he was a handsome man"); michael@0: entry->initial_rules[ToUniqueString("and")] = michael@0: Module::Expr("what i want to know is"); michael@0: entry->initial_rules[ToUniqueString("stallion")] = michael@0: Module::Expr(ToUniqueString("and break"), 8, false); michael@0: entry->initial_rules[ToUniqueString("onetwothreefourfive")] = michael@0: Module::Expr(ToUniqueString("pigeonsjustlikethat"), 42, true); michael@0: entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("how")] = michael@0: Module::Expr("do you like your blueeyed boy"); michael@0: entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("Mister")] = michael@0: Module::Expr("Death"); michael@0: m.AddStackFrameEntry(entry); michael@0: michael@0: // Set the load address. Doing this after adding all the data to michael@0: // the module must work fine. michael@0: m.SetLoadAddress(0x2ab698b0b6407073LL); michael@0: michael@0: m.Write(s, ALL_SYMBOL_DATA); michael@0: string contents = s.str(); michael@0: EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" michael@0: "FILE 0 filename-a.cc\n" michael@0: "FILE 1 filename-b.cc\n" michael@0: "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" michael@0: " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" michael@0: "b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n" michael@0: "9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n" michael@0: "STACK CFI INIT 6434d177ce326ca 49fc9ca7c7c13dc2" michael@0: " .cfa: he was a handsome man" michael@0: " and: what i want to know is" michael@0: " onetwothreefourfive: pigeonsjustlikethat 42 + ^" michael@0: " stallion: and break 8 +\n" michael@0: "STACK CFI 6434d177ce326cb" michael@0: " Mister: Death" michael@0: " how: do you like your blueeyed boy\n", michael@0: contents.c_str()); michael@0: } michael@0: michael@0: TEST(Write, OmitUnusedFiles) { michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: // Create some source files. michael@0: Module::File *file1 = m.FindFile("filename1"); michael@0: m.FindFile("filename2"); // not used by any line michael@0: Module::File *file3 = m.FindFile("filename3"); michael@0: michael@0: // Create a function. michael@0: Module::Function *function = new(Module::Function); michael@0: function->name = "function_name"; michael@0: function->address = 0x9b926d464f0b9384LL; michael@0: function->size = 0x4f524a4ba795e6a6LL; michael@0: function->parameter_size = 0xbbe8133a6641c9b7LL; michael@0: michael@0: // Source files that refer to some files, but not others. michael@0: Module::Line line1 = { 0x595fa44ebacc1086LL, 0x1e1e0191b066c5b3LL, michael@0: file1, 137850127 }; michael@0: Module::Line line2 = { 0x401ce8c8a12d25e3LL, 0x895751c41b8d2ce2LL, michael@0: file3, 28113549 }; michael@0: function->lines.push_back(line1); michael@0: function->lines.push_back(line2); michael@0: m.AddFunction(function); michael@0: michael@0: m.AssignSourceIds(); michael@0: michael@0: vector vec; michael@0: m.GetFiles(&vec); michael@0: EXPECT_EQ((size_t) 3, vec.size()); michael@0: EXPECT_STREQ("filename1", vec[0]->name.c_str()); michael@0: EXPECT_NE(-1, vec[0]->source_id); michael@0: // Expect filename2 not to be used. michael@0: EXPECT_STREQ("filename2", vec[1]->name.c_str()); michael@0: EXPECT_EQ(-1, vec[1]->source_id); michael@0: EXPECT_STREQ("filename3", vec[2]->name.c_str()); michael@0: EXPECT_NE(-1, vec[2]->source_id); michael@0: michael@0: stringstream s; michael@0: m.Write(s, ALL_SYMBOL_DATA); michael@0: string contents = s.str(); michael@0: EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" michael@0: "FILE 0 filename1\n" michael@0: "FILE 1 filename3\n" michael@0: "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7" michael@0: " function_name\n" michael@0: "595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n" michael@0: "401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n", michael@0: contents.c_str()); michael@0: } michael@0: michael@0: TEST(Write, NoCFI) { michael@0: stringstream s; michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: // Some source files. We will expect to see them in lexicographic order. michael@0: Module::File *file1 = m.FindFile("filename.cc"); michael@0: michael@0: // A function. michael@0: Module::Function *function = new(Module::Function); michael@0: function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)"; michael@0: function->address = 0xbec774ea5dd935f3LL; michael@0: function->size = 0x2922088f98d3f6fcLL; michael@0: function->parameter_size = 0xe5e9aa008bd5f0d0LL; michael@0: michael@0: // Some source lines. The module should not sort these. michael@0: Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, michael@0: file1, 41676901 }; michael@0: function->lines.push_back(line1); michael@0: michael@0: m.AddFunction(function); michael@0: michael@0: // Some stack information. michael@0: Module::StackFrameEntry *entry = new Module::StackFrameEntry(); michael@0: entry->address = 0x30f9e5c83323973dULL; michael@0: entry->size = 0x49fc9ca7c7c13dc2ULL; michael@0: entry->initial_rules[ustr__ZDcfa()] = Module::Expr("he was a handsome man"); michael@0: entry->initial_rules[ToUniqueString("and")] = michael@0: Module::Expr("what i want to know is"); michael@0: entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("how")] = michael@0: Module::Expr("do you like your blueeyed boy"); michael@0: entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("Mister")] = michael@0: Module::Expr("Death"); michael@0: m.AddStackFrameEntry(entry); michael@0: michael@0: // Set the load address. Doing this after adding all the data to michael@0: // the module must work fine. michael@0: m.SetLoadAddress(0x2ab698b0b6407073LL); michael@0: michael@0: m.Write(s, NO_CFI); michael@0: string contents = s.str(); michael@0: EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" michael@0: "FILE 0 filename.cc\n" michael@0: "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" michael@0: " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" michael@0: "9410dc39a798c580 1c2be6d6c5af2611 41676901 0\n", michael@0: contents.c_str()); michael@0: } michael@0: michael@0: TEST(Construct, AddFunctions) { michael@0: stringstream s; michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: // Two functions. michael@0: Module::Function *function1 = new(Module::Function); michael@0: function1->name = "_without_form"; michael@0: function1->address = 0xd35024aa7ca7da5cLL; michael@0: function1->size = 0x200b26e605f99071LL; michael@0: function1->parameter_size = 0xf14ac4fed48c4a99LL; michael@0: michael@0: Module::Function *function2 = new(Module::Function); michael@0: function2->name = "_and_void"; michael@0: function2->address = 0x2987743d0b35b13fLL; michael@0: function2->size = 0xb369db048deb3010LL; michael@0: function2->parameter_size = 0x938e556cb5a79988LL; michael@0: michael@0: // Put them in a vector. michael@0: vector vec; michael@0: vec.push_back(function1); michael@0: vec.push_back(function2); michael@0: michael@0: m.AddFunctions(vec.begin(), vec.end()); michael@0: michael@0: m.Write(s, ALL_SYMBOL_DATA); michael@0: string contents = s.str(); michael@0: EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" michael@0: "FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988" michael@0: " _and_void\n" michael@0: "FUNC d35024aa7ca7da5c 200b26e605f99071 f14ac4fed48c4a99" michael@0: " _without_form\n", michael@0: contents.c_str()); michael@0: michael@0: // Check that m.GetFunctions returns the functions we expect. michael@0: vec.clear(); michael@0: m.GetFunctions(&vec, vec.end()); michael@0: EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function1)); michael@0: EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function2)); michael@0: EXPECT_EQ((size_t) 2, vec.size()); michael@0: } michael@0: michael@0: TEST(Construct, AddFrames) { michael@0: stringstream s; michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: // First STACK CFI entry, with no initial rules or deltas. michael@0: Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); michael@0: entry1->address = 0xddb5f41285aa7757ULL; michael@0: entry1->size = 0x1486493370dc5073ULL; michael@0: m.AddStackFrameEntry(entry1); michael@0: michael@0: // Second STACK CFI entry, with initial rules but no deltas. michael@0: Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); michael@0: entry2->address = 0x8064f3af5e067e38ULL; michael@0: entry2->size = 0x0de2a5ee55509407ULL; michael@0: entry2->initial_rules[ustr__ZDcfa()] = michael@0: Module::Expr("I think that I shall never see"); michael@0: entry2->initial_rules[ToUniqueString("stromboli")] = michael@0: Module::Expr("a poem lovely as a tree"); michael@0: entry2->initial_rules[ToUniqueString("cannoli")] = michael@0: Module::Expr("a tree whose hungry mouth is prest"); michael@0: m.AddStackFrameEntry(entry2); michael@0: michael@0: // Third STACK CFI entry, with initial rules and deltas. michael@0: Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); michael@0: entry3->address = 0x5e8d0db0a7075c6cULL; michael@0: entry3->size = 0x1c7edb12a7aea229ULL; michael@0: entry3->initial_rules[ustr__ZDcfa()] = Module::Expr("Whose woods are these"); michael@0: entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] = michael@0: Module::Expr("the village though"); michael@0: entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] = michael@0: Module::Expr("he will not see me stopping here"); michael@0: entry3->rule_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] = michael@0: Module::Expr("his house is in"); michael@0: entry3->rule_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] = michael@0: Module::Expr("I think I know"); michael@0: m.AddStackFrameEntry(entry3); michael@0: michael@0: // Check that Write writes STACK CFI records properly. michael@0: m.Write(s, ALL_SYMBOL_DATA); michael@0: string contents = s.str(); michael@0: EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" michael@0: "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" michael@0: " .cfa: Whose woods are these\n" michael@0: "STACK CFI 36682fad3763ffff" michael@0: " .cfa: I think I know" michael@0: " stromboli: his house is in\n" michael@0: "STACK CFI 47ceb0f63c269d7f" michael@0: " calzone: the village though" michael@0: " cannoli: he will not see me stopping here\n" michael@0: "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" michael@0: " .cfa: I think that I shall never see" michael@0: " cannoli: a tree whose hungry mouth is prest" michael@0: " stromboli: a poem lovely as a tree\n" michael@0: "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n", michael@0: contents.c_str()); michael@0: michael@0: // Check that GetStackFrameEntries works. michael@0: vector entries; michael@0: m.GetStackFrameEntries(&entries); michael@0: ASSERT_EQ(3U, entries.size()); michael@0: // Check first entry. michael@0: EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[0]->address); michael@0: EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[0]->size); michael@0: Module::RuleMap entry1_initial; michael@0: entry1_initial[ustr__ZDcfa()] = Module::Expr("Whose woods are these"); michael@0: EXPECT_THAT(entries[0]->initial_rules, ContainerEq(entry1_initial)); michael@0: Module::RuleChangeMap entry1_changes; michael@0: entry1_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] = michael@0: Module::Expr("I think I know"); michael@0: entry1_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] = michael@0: Module::Expr("his house is in"); michael@0: entry1_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] = michael@0: Module::Expr("the village though"); michael@0: entry1_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] = michael@0: Module::Expr("he will not see me stopping here"); michael@0: EXPECT_THAT(entries[0]->rule_changes, ContainerEq(entry1_changes)); michael@0: // Check second entry. michael@0: EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); michael@0: EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); michael@0: ASSERT_EQ(3U, entries[1]->initial_rules.size()); michael@0: Module::RuleMap entry2_initial; michael@0: entry2_initial[ustr__ZDcfa()] = michael@0: Module::Expr("I think that I shall never see"); michael@0: entry2_initial[ToUniqueString("stromboli")] = michael@0: Module::Expr("a poem lovely as a tree"); michael@0: entry2_initial[ToUniqueString("cannoli")] = michael@0: Module::Expr("a tree whose hungry mouth is prest"); michael@0: EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); michael@0: ASSERT_EQ(0U, entries[1]->rule_changes.size()); michael@0: // Check third entry. michael@0: EXPECT_EQ(0xddb5f41285aa7757ULL, entries[2]->address); michael@0: EXPECT_EQ(0x1486493370dc5073ULL, entries[2]->size); michael@0: ASSERT_EQ(0U, entries[2]->initial_rules.size()); michael@0: ASSERT_EQ(0U, entries[2]->rule_changes.size()); michael@0: } michael@0: michael@0: TEST(Construct, UniqueFiles) { michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: Module::File *file1 = m.FindFile("foo"); michael@0: Module::File *file2 = m.FindFile(string("bar")); michael@0: Module::File *file3 = m.FindFile(string("foo")); michael@0: Module::File *file4 = m.FindFile("bar"); michael@0: EXPECT_NE(file1, file2); michael@0: EXPECT_EQ(file1, file3); michael@0: EXPECT_EQ(file2, file4); michael@0: EXPECT_EQ(file1, m.FindExistingFile("foo")); michael@0: EXPECT_TRUE(m.FindExistingFile("baz") == NULL); michael@0: } michael@0: michael@0: TEST(Construct, DuplicateFunctions) { michael@0: stringstream s; michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: // Two functions. michael@0: Module::Function *function1 = generate_duplicate_function("_without_form"); michael@0: Module::Function *function2 = generate_duplicate_function("_without_form"); michael@0: michael@0: m.AddFunction(function1); michael@0: m.AddFunction(function2); michael@0: michael@0: m.Write(s, ALL_SYMBOL_DATA); michael@0: string contents = s.str(); michael@0: EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" michael@0: "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" michael@0: " _without_form\n", michael@0: contents.c_str()); michael@0: } michael@0: michael@0: TEST(Construct, FunctionsWithSameAddress) { michael@0: stringstream s; michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: // Two functions. michael@0: Module::Function *function1 = generate_duplicate_function("_without_form"); michael@0: Module::Function *function2 = generate_duplicate_function("_and_void"); michael@0: michael@0: m.AddFunction(function1); michael@0: m.AddFunction(function2); michael@0: michael@0: m.Write(s, ALL_SYMBOL_DATA); michael@0: string contents = s.str(); michael@0: EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" michael@0: "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" michael@0: " _and_void\n" michael@0: "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" michael@0: " _without_form\n", michael@0: contents.c_str()); michael@0: } michael@0: michael@0: // Externs should be written out as PUBLIC records, sorted by michael@0: // address. michael@0: TEST(Construct, Externs) { michael@0: stringstream s; michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: // Two externs. michael@0: Module::Extern *extern1 = new(Module::Extern); michael@0: extern1->address = 0xffff; michael@0: extern1->name = "_abc"; michael@0: Module::Extern *extern2 = new(Module::Extern); michael@0: extern2->address = 0xaaaa; michael@0: extern2->name = "_xyz"; michael@0: michael@0: m.AddExtern(extern1); michael@0: m.AddExtern(extern2); michael@0: michael@0: m.Write(s, ALL_SYMBOL_DATA); michael@0: string contents = s.str(); michael@0: michael@0: EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " michael@0: MODULE_ID " " MODULE_NAME "\n" michael@0: "PUBLIC aaaa 0 _xyz\n" michael@0: "PUBLIC ffff 0 _abc\n", michael@0: contents.c_str()); michael@0: } michael@0: michael@0: // Externs with the same address should only keep the first entry michael@0: // added. michael@0: TEST(Construct, DuplicateExterns) { michael@0: stringstream s; michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: // Two externs. michael@0: Module::Extern *extern1 = new(Module::Extern); michael@0: extern1->address = 0xffff; michael@0: extern1->name = "_xyz"; michael@0: Module::Extern *extern2 = new(Module::Extern); michael@0: extern2->address = 0xffff; michael@0: extern2->name = "_abc"; michael@0: michael@0: m.AddExtern(extern1); michael@0: m.AddExtern(extern2); michael@0: michael@0: m.Write(s, ALL_SYMBOL_DATA); michael@0: string contents = s.str(); michael@0: michael@0: EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " michael@0: MODULE_ID " " MODULE_NAME "\n" michael@0: "PUBLIC ffff 0 _xyz\n", michael@0: contents.c_str()); michael@0: } michael@0: michael@0: TEST(Lookup, Function) { michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: Module::Function *function1 = new(Module::Function); michael@0: function1->name = "_abc1"; michael@0: function1->address = 0x1000; michael@0: function1->size = 0x900; michael@0: function1->parameter_size = 0x0; michael@0: michael@0: Module::Function *function2 = new(Module::Function); michael@0: function2->name = "_xyz2"; michael@0: function2->address = 0x2000; michael@0: function2->size = 0x900; michael@0: function2->parameter_size = 0x0; michael@0: michael@0: Module::Function *function3 = new(Module::Function); michael@0: function3->name = "_def3"; michael@0: function3->address = 0x3000; michael@0: function3->size = 0x900; michael@0: function3->parameter_size = 0x0; michael@0: michael@0: // Put them in a vector. michael@0: vector vec; michael@0: vec.push_back(function1); michael@0: vec.push_back(function2); michael@0: vec.push_back(function3); michael@0: michael@0: m.AddFunctions(vec.begin(), vec.end()); michael@0: michael@0: // Try looking up functions by address. michael@0: Module::Function* f = m.FindFunctionByAddress(0x1000); michael@0: EXPECT_EQ(function1, f); michael@0: f = m.FindFunctionByAddress(0x18FF); michael@0: EXPECT_EQ(function1, f); michael@0: michael@0: f = m.FindFunctionByAddress(0x1900); michael@0: EXPECT_EQ((Module::Function*)NULL, f); michael@0: f = m.FindFunctionByAddress(0x1A00); michael@0: EXPECT_EQ((Module::Function*)NULL, f); michael@0: michael@0: f = m.FindFunctionByAddress(0x2000); michael@0: EXPECT_EQ(function2, f); michael@0: f = m.FindFunctionByAddress(0x28FF); michael@0: EXPECT_EQ(function2, f); michael@0: michael@0: f = m.FindFunctionByAddress(0x3000); michael@0: EXPECT_EQ(function3, f); michael@0: f = m.FindFunctionByAddress(0x38FF); michael@0: EXPECT_EQ(function3, f); michael@0: michael@0: f = m.FindFunctionByAddress(0x3900); michael@0: EXPECT_EQ((Module::Function*)NULL, f); michael@0: f = m.FindFunctionByAddress(0x3A00); michael@0: EXPECT_EQ((Module::Function*)NULL, f); michael@0: } michael@0: michael@0: TEST(Lookup, Externs) { michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: // Two externs. michael@0: Module::Extern* extern1 = new(Module::Extern); michael@0: extern1->address = 0x1000; michael@0: extern1->name = "_abc"; michael@0: Module::Extern* extern2 = new(Module::Extern); michael@0: extern2->address = 0x2000; michael@0: extern2->name = "_xyz"; michael@0: michael@0: m.AddExtern(extern1); michael@0: m.AddExtern(extern2); michael@0: michael@0: Module::Extern* e = m.FindExternByAddress(0xFFF); michael@0: EXPECT_EQ((Module::Extern*)NULL, e); michael@0: michael@0: e = m.FindExternByAddress(0x1000); michael@0: EXPECT_EQ(extern1, e); michael@0: e = m.FindExternByAddress(0x1900); michael@0: EXPECT_EQ(extern1, e); michael@0: e = m.FindExternByAddress(0x1FFF); michael@0: EXPECT_EQ(extern1, e); michael@0: michael@0: e = m.FindExternByAddress(0x2000); michael@0: EXPECT_EQ(extern2, e); michael@0: e = m.FindExternByAddress(0x2900); michael@0: EXPECT_EQ(extern2, e); michael@0: e = m.FindExternByAddress(0xFFFFFFFF); michael@0: EXPECT_EQ(extern2, e); michael@0: } michael@0: michael@0: TEST(Lookup, StackFrameEntries) { michael@0: Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); michael@0: michael@0: // First STACK CFI entry, with no initial rules or deltas. michael@0: Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); michael@0: entry1->address = 0x2000; michael@0: entry1->size = 0x900; michael@0: m.AddStackFrameEntry(entry1); michael@0: michael@0: // Second STACK CFI entry, with initial rules but no deltas. michael@0: Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); michael@0: entry2->address = 0x3000; michael@0: entry2->size = 0x900; michael@0: entry2->initial_rules[ustr__ZDcfa()] = michael@0: Module::Expr("I think that I shall never see"); michael@0: entry2->initial_rules[ToUniqueString("stromboli")] = michael@0: Module::Expr("a poem lovely as a tree"); michael@0: entry2->initial_rules[ToUniqueString("cannoli")] = michael@0: Module::Expr("a tree whose hungry mouth is prest"); michael@0: m.AddStackFrameEntry(entry2); michael@0: michael@0: // Third STACK CFI entry, with initial rules and deltas. michael@0: Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); michael@0: entry3->address = 0x1000; michael@0: entry3->size = 0x900; michael@0: entry3->initial_rules[ustr__ZDcfa()] = Module::Expr("Whose woods are these"); michael@0: entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] = michael@0: Module::Expr("the village though"); michael@0: entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] = michael@0: Module::Expr("he will not see me stopping here"); michael@0: entry3->rule_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] = michael@0: Module::Expr("his house is in"); michael@0: entry3->rule_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] = michael@0: Module::Expr("I think I know"); michael@0: m.AddStackFrameEntry(entry3); michael@0: michael@0: Module::StackFrameEntry* s = m.FindStackFrameEntryByAddress(0x1000); michael@0: EXPECT_EQ(entry3, s); michael@0: s = m.FindStackFrameEntryByAddress(0x18FF); michael@0: EXPECT_EQ(entry3, s); michael@0: michael@0: s = m.FindStackFrameEntryByAddress(0x1900); michael@0: EXPECT_EQ((Module::StackFrameEntry*)NULL, s); michael@0: s = m.FindStackFrameEntryByAddress(0x1A00); michael@0: EXPECT_EQ((Module::StackFrameEntry*)NULL, s); michael@0: michael@0: s = m.FindStackFrameEntryByAddress(0x2000); michael@0: EXPECT_EQ(entry1, s); michael@0: s = m.FindStackFrameEntryByAddress(0x28FF); michael@0: EXPECT_EQ(entry1, s); michael@0: michael@0: s = m.FindStackFrameEntryByAddress(0x3000); michael@0: EXPECT_EQ(entry2, s); michael@0: s = m.FindStackFrameEntryByAddress(0x38FF); michael@0: EXPECT_EQ(entry2, s); michael@0: michael@0: s = m.FindStackFrameEntryByAddress(0x3900); michael@0: EXPECT_EQ((Module::StackFrameEntry*)NULL, s); michael@0: s = m.FindStackFrameEntryByAddress(0x3A00); michael@0: EXPECT_EQ((Module::StackFrameEntry*)NULL, s); michael@0: }