Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | // Copyright (c) 2010 Google Inc. |
michael@0 | 2 | // All rights reserved. |
michael@0 | 3 | // |
michael@0 | 4 | // Redistribution and use in source and binary forms, with or without |
michael@0 | 5 | // modification, are permitted provided that the following conditions are |
michael@0 | 6 | // met: |
michael@0 | 7 | // |
michael@0 | 8 | // * Redistributions of source code must retain the above copyright |
michael@0 | 9 | // notice, this list of conditions and the following disclaimer. |
michael@0 | 10 | // * Redistributions in binary form must reproduce the above |
michael@0 | 11 | // copyright notice, this list of conditions and the following disclaimer |
michael@0 | 12 | // in the documentation and/or other materials provided with the |
michael@0 | 13 | // distribution. |
michael@0 | 14 | // * Neither the name of Google Inc. nor the names of its |
michael@0 | 15 | // contributors may be used to endorse or promote products derived from |
michael@0 | 16 | // this software without specific prior written permission. |
michael@0 | 17 | // |
michael@0 | 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
michael@0 | 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
michael@0 | 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@0 | 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@0 | 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 29 | |
michael@0 | 30 | // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
michael@0 | 31 | |
michael@0 | 32 | // module_unittest.cc: Unit tests for google_breakpad::Module. |
michael@0 | 33 | |
michael@0 | 34 | #include <errno.h> |
michael@0 | 35 | #include <stdio.h> |
michael@0 | 36 | #include <stdlib.h> |
michael@0 | 37 | #include <string.h> |
michael@0 | 38 | |
michael@0 | 39 | #include <algorithm> |
michael@0 | 40 | #include <sstream> |
michael@0 | 41 | #include <string> |
michael@0 | 42 | |
michael@0 | 43 | #include "breakpad_googletest_includes.h" |
michael@0 | 44 | #include "common/module.h" |
michael@0 | 45 | #include "common/using_std_string.h" |
michael@0 | 46 | |
michael@0 | 47 | using google_breakpad::Module; |
michael@0 | 48 | using google_breakpad::ToUniqueString; |
michael@0 | 49 | using google_breakpad::ustr__ZDcfa; |
michael@0 | 50 | using std::stringstream; |
michael@0 | 51 | using std::vector; |
michael@0 | 52 | using testing::ContainerEq; |
michael@0 | 53 | |
michael@0 | 54 | static Module::Function *generate_duplicate_function(const string &name) { |
michael@0 | 55 | const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cLL; |
michael@0 | 56 | const Module::Address DUP_SIZE = 0x200b26e605f99071LL; |
michael@0 | 57 | const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL; |
michael@0 | 58 | |
michael@0 | 59 | Module::Function *function = new(Module::Function); |
michael@0 | 60 | function->name = name; |
michael@0 | 61 | function->address = DUP_ADDRESS; |
michael@0 | 62 | function->size = DUP_SIZE; |
michael@0 | 63 | function->parameter_size = DUP_PARAMETER_SIZE; |
michael@0 | 64 | return function; |
michael@0 | 65 | } |
michael@0 | 66 | |
michael@0 | 67 | #define MODULE_NAME "name with spaces" |
michael@0 | 68 | #define MODULE_OS "os-name" |
michael@0 | 69 | #define MODULE_ARCH "architecture" |
michael@0 | 70 | #define MODULE_ID "id-string" |
michael@0 | 71 | |
michael@0 | 72 | TEST(Write, Header) { |
michael@0 | 73 | stringstream s; |
michael@0 | 74 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 75 | m.Write(s, ALL_SYMBOL_DATA); |
michael@0 | 76 | string contents = s.str(); |
michael@0 | 77 | EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n", |
michael@0 | 78 | contents.c_str()); |
michael@0 | 79 | } |
michael@0 | 80 | |
michael@0 | 81 | TEST(Write, OneLineFunc) { |
michael@0 | 82 | stringstream s; |
michael@0 | 83 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 84 | |
michael@0 | 85 | Module::File *file = m.FindFile("file_name.cc"); |
michael@0 | 86 | Module::Function *function = new(Module::Function); |
michael@0 | 87 | function->name = "function_name"; |
michael@0 | 88 | function->address = 0xe165bf8023b9d9abLL; |
michael@0 | 89 | function->size = 0x1e4bb0eb1cbf5b09LL; |
michael@0 | 90 | function->parameter_size = 0x772beee89114358aLL; |
michael@0 | 91 | Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL, |
michael@0 | 92 | file, 67519080 }; |
michael@0 | 93 | function->lines.push_back(line); |
michael@0 | 94 | m.AddFunction(function); |
michael@0 | 95 | |
michael@0 | 96 | m.Write(s, ALL_SYMBOL_DATA); |
michael@0 | 97 | string contents = s.str(); |
michael@0 | 98 | EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
michael@0 | 99 | "FILE 0 file_name.cc\n" |
michael@0 | 100 | "FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a" |
michael@0 | 101 | " function_name\n" |
michael@0 | 102 | "e165bf8023b9d9ab 1e4bb0eb1cbf5b09 67519080 0\n", |
michael@0 | 103 | contents.c_str()); |
michael@0 | 104 | } |
michael@0 | 105 | |
michael@0 | 106 | TEST(Write, RelativeLoadAddress) { |
michael@0 | 107 | stringstream s; |
michael@0 | 108 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 109 | |
michael@0 | 110 | // Some source files. We will expect to see them in lexicographic order. |
michael@0 | 111 | Module::File *file1 = m.FindFile("filename-b.cc"); |
michael@0 | 112 | Module::File *file2 = m.FindFile("filename-a.cc"); |
michael@0 | 113 | |
michael@0 | 114 | // A function. |
michael@0 | 115 | Module::Function *function = new(Module::Function); |
michael@0 | 116 | function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)"; |
michael@0 | 117 | function->address = 0xbec774ea5dd935f3LL; |
michael@0 | 118 | function->size = 0x2922088f98d3f6fcLL; |
michael@0 | 119 | function->parameter_size = 0xe5e9aa008bd5f0d0LL; |
michael@0 | 120 | |
michael@0 | 121 | // Some source lines. The module should not sort these. |
michael@0 | 122 | Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, |
michael@0 | 123 | file1, 41676901 }; |
michael@0 | 124 | Module::Line line2 = { 0xdaf35bc123885c04LL, 0xcf621b8d324d0ebLL, |
michael@0 | 125 | file2, 67519080 }; |
michael@0 | 126 | function->lines.push_back(line2); |
michael@0 | 127 | function->lines.push_back(line1); |
michael@0 | 128 | |
michael@0 | 129 | m.AddFunction(function); |
michael@0 | 130 | |
michael@0 | 131 | // Some stack information. |
michael@0 | 132 | Module::StackFrameEntry *entry = new Module::StackFrameEntry(); |
michael@0 | 133 | entry->address = 0x30f9e5c83323973dULL; |
michael@0 | 134 | entry->size = 0x49fc9ca7c7c13dc2ULL; |
michael@0 | 135 | entry->initial_rules[ustr__ZDcfa()] = Module::Expr("he was a handsome man"); |
michael@0 | 136 | entry->initial_rules[ToUniqueString("and")] = |
michael@0 | 137 | Module::Expr("what i want to know is"); |
michael@0 | 138 | entry->initial_rules[ToUniqueString("stallion")] = |
michael@0 | 139 | Module::Expr(ToUniqueString("and break"), 8, false); |
michael@0 | 140 | entry->initial_rules[ToUniqueString("onetwothreefourfive")] = |
michael@0 | 141 | Module::Expr(ToUniqueString("pigeonsjustlikethat"), 42, true); |
michael@0 | 142 | entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("how")] = |
michael@0 | 143 | Module::Expr("do you like your blueeyed boy"); |
michael@0 | 144 | entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("Mister")] = |
michael@0 | 145 | Module::Expr("Death"); |
michael@0 | 146 | m.AddStackFrameEntry(entry); |
michael@0 | 147 | |
michael@0 | 148 | // Set the load address. Doing this after adding all the data to |
michael@0 | 149 | // the module must work fine. |
michael@0 | 150 | m.SetLoadAddress(0x2ab698b0b6407073LL); |
michael@0 | 151 | |
michael@0 | 152 | m.Write(s, ALL_SYMBOL_DATA); |
michael@0 | 153 | string contents = s.str(); |
michael@0 | 154 | EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
michael@0 | 155 | "FILE 0 filename-a.cc\n" |
michael@0 | 156 | "FILE 1 filename-b.cc\n" |
michael@0 | 157 | "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" |
michael@0 | 158 | " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" |
michael@0 | 159 | "b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n" |
michael@0 | 160 | "9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n" |
michael@0 | 161 | "STACK CFI INIT 6434d177ce326ca 49fc9ca7c7c13dc2" |
michael@0 | 162 | " .cfa: he was a handsome man" |
michael@0 | 163 | " and: what i want to know is" |
michael@0 | 164 | " onetwothreefourfive: pigeonsjustlikethat 42 + ^" |
michael@0 | 165 | " stallion: and break 8 +\n" |
michael@0 | 166 | "STACK CFI 6434d177ce326cb" |
michael@0 | 167 | " Mister: Death" |
michael@0 | 168 | " how: do you like your blueeyed boy\n", |
michael@0 | 169 | contents.c_str()); |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | TEST(Write, OmitUnusedFiles) { |
michael@0 | 173 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 174 | |
michael@0 | 175 | // Create some source files. |
michael@0 | 176 | Module::File *file1 = m.FindFile("filename1"); |
michael@0 | 177 | m.FindFile("filename2"); // not used by any line |
michael@0 | 178 | Module::File *file3 = m.FindFile("filename3"); |
michael@0 | 179 | |
michael@0 | 180 | // Create a function. |
michael@0 | 181 | Module::Function *function = new(Module::Function); |
michael@0 | 182 | function->name = "function_name"; |
michael@0 | 183 | function->address = 0x9b926d464f0b9384LL; |
michael@0 | 184 | function->size = 0x4f524a4ba795e6a6LL; |
michael@0 | 185 | function->parameter_size = 0xbbe8133a6641c9b7LL; |
michael@0 | 186 | |
michael@0 | 187 | // Source files that refer to some files, but not others. |
michael@0 | 188 | Module::Line line1 = { 0x595fa44ebacc1086LL, 0x1e1e0191b066c5b3LL, |
michael@0 | 189 | file1, 137850127 }; |
michael@0 | 190 | Module::Line line2 = { 0x401ce8c8a12d25e3LL, 0x895751c41b8d2ce2LL, |
michael@0 | 191 | file3, 28113549 }; |
michael@0 | 192 | function->lines.push_back(line1); |
michael@0 | 193 | function->lines.push_back(line2); |
michael@0 | 194 | m.AddFunction(function); |
michael@0 | 195 | |
michael@0 | 196 | m.AssignSourceIds(); |
michael@0 | 197 | |
michael@0 | 198 | vector<Module::File *> vec; |
michael@0 | 199 | m.GetFiles(&vec); |
michael@0 | 200 | EXPECT_EQ((size_t) 3, vec.size()); |
michael@0 | 201 | EXPECT_STREQ("filename1", vec[0]->name.c_str()); |
michael@0 | 202 | EXPECT_NE(-1, vec[0]->source_id); |
michael@0 | 203 | // Expect filename2 not to be used. |
michael@0 | 204 | EXPECT_STREQ("filename2", vec[1]->name.c_str()); |
michael@0 | 205 | EXPECT_EQ(-1, vec[1]->source_id); |
michael@0 | 206 | EXPECT_STREQ("filename3", vec[2]->name.c_str()); |
michael@0 | 207 | EXPECT_NE(-1, vec[2]->source_id); |
michael@0 | 208 | |
michael@0 | 209 | stringstream s; |
michael@0 | 210 | m.Write(s, ALL_SYMBOL_DATA); |
michael@0 | 211 | string contents = s.str(); |
michael@0 | 212 | EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
michael@0 | 213 | "FILE 0 filename1\n" |
michael@0 | 214 | "FILE 1 filename3\n" |
michael@0 | 215 | "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7" |
michael@0 | 216 | " function_name\n" |
michael@0 | 217 | "595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n" |
michael@0 | 218 | "401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n", |
michael@0 | 219 | contents.c_str()); |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | TEST(Write, NoCFI) { |
michael@0 | 223 | stringstream s; |
michael@0 | 224 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 225 | |
michael@0 | 226 | // Some source files. We will expect to see them in lexicographic order. |
michael@0 | 227 | Module::File *file1 = m.FindFile("filename.cc"); |
michael@0 | 228 | |
michael@0 | 229 | // A function. |
michael@0 | 230 | Module::Function *function = new(Module::Function); |
michael@0 | 231 | function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)"; |
michael@0 | 232 | function->address = 0xbec774ea5dd935f3LL; |
michael@0 | 233 | function->size = 0x2922088f98d3f6fcLL; |
michael@0 | 234 | function->parameter_size = 0xe5e9aa008bd5f0d0LL; |
michael@0 | 235 | |
michael@0 | 236 | // Some source lines. The module should not sort these. |
michael@0 | 237 | Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, |
michael@0 | 238 | file1, 41676901 }; |
michael@0 | 239 | function->lines.push_back(line1); |
michael@0 | 240 | |
michael@0 | 241 | m.AddFunction(function); |
michael@0 | 242 | |
michael@0 | 243 | // Some stack information. |
michael@0 | 244 | Module::StackFrameEntry *entry = new Module::StackFrameEntry(); |
michael@0 | 245 | entry->address = 0x30f9e5c83323973dULL; |
michael@0 | 246 | entry->size = 0x49fc9ca7c7c13dc2ULL; |
michael@0 | 247 | entry->initial_rules[ustr__ZDcfa()] = Module::Expr("he was a handsome man"); |
michael@0 | 248 | entry->initial_rules[ToUniqueString("and")] = |
michael@0 | 249 | Module::Expr("what i want to know is"); |
michael@0 | 250 | entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("how")] = |
michael@0 | 251 | Module::Expr("do you like your blueeyed boy"); |
michael@0 | 252 | entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("Mister")] = |
michael@0 | 253 | Module::Expr("Death"); |
michael@0 | 254 | m.AddStackFrameEntry(entry); |
michael@0 | 255 | |
michael@0 | 256 | // Set the load address. Doing this after adding all the data to |
michael@0 | 257 | // the module must work fine. |
michael@0 | 258 | m.SetLoadAddress(0x2ab698b0b6407073LL); |
michael@0 | 259 | |
michael@0 | 260 | m.Write(s, NO_CFI); |
michael@0 | 261 | string contents = s.str(); |
michael@0 | 262 | EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
michael@0 | 263 | "FILE 0 filename.cc\n" |
michael@0 | 264 | "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" |
michael@0 | 265 | " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" |
michael@0 | 266 | "9410dc39a798c580 1c2be6d6c5af2611 41676901 0\n", |
michael@0 | 267 | contents.c_str()); |
michael@0 | 268 | } |
michael@0 | 269 | |
michael@0 | 270 | TEST(Construct, AddFunctions) { |
michael@0 | 271 | stringstream s; |
michael@0 | 272 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 273 | |
michael@0 | 274 | // Two functions. |
michael@0 | 275 | Module::Function *function1 = new(Module::Function); |
michael@0 | 276 | function1->name = "_without_form"; |
michael@0 | 277 | function1->address = 0xd35024aa7ca7da5cLL; |
michael@0 | 278 | function1->size = 0x200b26e605f99071LL; |
michael@0 | 279 | function1->parameter_size = 0xf14ac4fed48c4a99LL; |
michael@0 | 280 | |
michael@0 | 281 | Module::Function *function2 = new(Module::Function); |
michael@0 | 282 | function2->name = "_and_void"; |
michael@0 | 283 | function2->address = 0x2987743d0b35b13fLL; |
michael@0 | 284 | function2->size = 0xb369db048deb3010LL; |
michael@0 | 285 | function2->parameter_size = 0x938e556cb5a79988LL; |
michael@0 | 286 | |
michael@0 | 287 | // Put them in a vector. |
michael@0 | 288 | vector<Module::Function *> vec; |
michael@0 | 289 | vec.push_back(function1); |
michael@0 | 290 | vec.push_back(function2); |
michael@0 | 291 | |
michael@0 | 292 | m.AddFunctions(vec.begin(), vec.end()); |
michael@0 | 293 | |
michael@0 | 294 | m.Write(s, ALL_SYMBOL_DATA); |
michael@0 | 295 | string contents = s.str(); |
michael@0 | 296 | EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
michael@0 | 297 | "FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988" |
michael@0 | 298 | " _and_void\n" |
michael@0 | 299 | "FUNC d35024aa7ca7da5c 200b26e605f99071 f14ac4fed48c4a99" |
michael@0 | 300 | " _without_form\n", |
michael@0 | 301 | contents.c_str()); |
michael@0 | 302 | |
michael@0 | 303 | // Check that m.GetFunctions returns the functions we expect. |
michael@0 | 304 | vec.clear(); |
michael@0 | 305 | m.GetFunctions(&vec, vec.end()); |
michael@0 | 306 | EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function1)); |
michael@0 | 307 | EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function2)); |
michael@0 | 308 | EXPECT_EQ((size_t) 2, vec.size()); |
michael@0 | 309 | } |
michael@0 | 310 | |
michael@0 | 311 | TEST(Construct, AddFrames) { |
michael@0 | 312 | stringstream s; |
michael@0 | 313 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 314 | |
michael@0 | 315 | // First STACK CFI entry, with no initial rules or deltas. |
michael@0 | 316 | Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); |
michael@0 | 317 | entry1->address = 0xddb5f41285aa7757ULL; |
michael@0 | 318 | entry1->size = 0x1486493370dc5073ULL; |
michael@0 | 319 | m.AddStackFrameEntry(entry1); |
michael@0 | 320 | |
michael@0 | 321 | // Second STACK CFI entry, with initial rules but no deltas. |
michael@0 | 322 | Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); |
michael@0 | 323 | entry2->address = 0x8064f3af5e067e38ULL; |
michael@0 | 324 | entry2->size = 0x0de2a5ee55509407ULL; |
michael@0 | 325 | entry2->initial_rules[ustr__ZDcfa()] = |
michael@0 | 326 | Module::Expr("I think that I shall never see"); |
michael@0 | 327 | entry2->initial_rules[ToUniqueString("stromboli")] = |
michael@0 | 328 | Module::Expr("a poem lovely as a tree"); |
michael@0 | 329 | entry2->initial_rules[ToUniqueString("cannoli")] = |
michael@0 | 330 | Module::Expr("a tree whose hungry mouth is prest"); |
michael@0 | 331 | m.AddStackFrameEntry(entry2); |
michael@0 | 332 | |
michael@0 | 333 | // Third STACK CFI entry, with initial rules and deltas. |
michael@0 | 334 | Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); |
michael@0 | 335 | entry3->address = 0x5e8d0db0a7075c6cULL; |
michael@0 | 336 | entry3->size = 0x1c7edb12a7aea229ULL; |
michael@0 | 337 | entry3->initial_rules[ustr__ZDcfa()] = Module::Expr("Whose woods are these"); |
michael@0 | 338 | entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] = |
michael@0 | 339 | Module::Expr("the village though"); |
michael@0 | 340 | entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] = |
michael@0 | 341 | Module::Expr("he will not see me stopping here"); |
michael@0 | 342 | entry3->rule_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] = |
michael@0 | 343 | Module::Expr("his house is in"); |
michael@0 | 344 | entry3->rule_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] = |
michael@0 | 345 | Module::Expr("I think I know"); |
michael@0 | 346 | m.AddStackFrameEntry(entry3); |
michael@0 | 347 | |
michael@0 | 348 | // Check that Write writes STACK CFI records properly. |
michael@0 | 349 | m.Write(s, ALL_SYMBOL_DATA); |
michael@0 | 350 | string contents = s.str(); |
michael@0 | 351 | EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
michael@0 | 352 | "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" |
michael@0 | 353 | " .cfa: Whose woods are these\n" |
michael@0 | 354 | "STACK CFI 36682fad3763ffff" |
michael@0 | 355 | " .cfa: I think I know" |
michael@0 | 356 | " stromboli: his house is in\n" |
michael@0 | 357 | "STACK CFI 47ceb0f63c269d7f" |
michael@0 | 358 | " calzone: the village though" |
michael@0 | 359 | " cannoli: he will not see me stopping here\n" |
michael@0 | 360 | "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" |
michael@0 | 361 | " .cfa: I think that I shall never see" |
michael@0 | 362 | " cannoli: a tree whose hungry mouth is prest" |
michael@0 | 363 | " stromboli: a poem lovely as a tree\n" |
michael@0 | 364 | "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n", |
michael@0 | 365 | contents.c_str()); |
michael@0 | 366 | |
michael@0 | 367 | // Check that GetStackFrameEntries works. |
michael@0 | 368 | vector<Module::StackFrameEntry *> entries; |
michael@0 | 369 | m.GetStackFrameEntries(&entries); |
michael@0 | 370 | ASSERT_EQ(3U, entries.size()); |
michael@0 | 371 | // Check first entry. |
michael@0 | 372 | EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[0]->address); |
michael@0 | 373 | EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[0]->size); |
michael@0 | 374 | Module::RuleMap entry1_initial; |
michael@0 | 375 | entry1_initial[ustr__ZDcfa()] = Module::Expr("Whose woods are these"); |
michael@0 | 376 | EXPECT_THAT(entries[0]->initial_rules, ContainerEq(entry1_initial)); |
michael@0 | 377 | Module::RuleChangeMap entry1_changes; |
michael@0 | 378 | entry1_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] = |
michael@0 | 379 | Module::Expr("I think I know"); |
michael@0 | 380 | entry1_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] = |
michael@0 | 381 | Module::Expr("his house is in"); |
michael@0 | 382 | entry1_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] = |
michael@0 | 383 | Module::Expr("the village though"); |
michael@0 | 384 | entry1_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] = |
michael@0 | 385 | Module::Expr("he will not see me stopping here"); |
michael@0 | 386 | EXPECT_THAT(entries[0]->rule_changes, ContainerEq(entry1_changes)); |
michael@0 | 387 | // Check second entry. |
michael@0 | 388 | EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); |
michael@0 | 389 | EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); |
michael@0 | 390 | ASSERT_EQ(3U, entries[1]->initial_rules.size()); |
michael@0 | 391 | Module::RuleMap entry2_initial; |
michael@0 | 392 | entry2_initial[ustr__ZDcfa()] = |
michael@0 | 393 | Module::Expr("I think that I shall never see"); |
michael@0 | 394 | entry2_initial[ToUniqueString("stromboli")] = |
michael@0 | 395 | Module::Expr("a poem lovely as a tree"); |
michael@0 | 396 | entry2_initial[ToUniqueString("cannoli")] = |
michael@0 | 397 | Module::Expr("a tree whose hungry mouth is prest"); |
michael@0 | 398 | EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); |
michael@0 | 399 | ASSERT_EQ(0U, entries[1]->rule_changes.size()); |
michael@0 | 400 | // Check third entry. |
michael@0 | 401 | EXPECT_EQ(0xddb5f41285aa7757ULL, entries[2]->address); |
michael@0 | 402 | EXPECT_EQ(0x1486493370dc5073ULL, entries[2]->size); |
michael@0 | 403 | ASSERT_EQ(0U, entries[2]->initial_rules.size()); |
michael@0 | 404 | ASSERT_EQ(0U, entries[2]->rule_changes.size()); |
michael@0 | 405 | } |
michael@0 | 406 | |
michael@0 | 407 | TEST(Construct, UniqueFiles) { |
michael@0 | 408 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 409 | Module::File *file1 = m.FindFile("foo"); |
michael@0 | 410 | Module::File *file2 = m.FindFile(string("bar")); |
michael@0 | 411 | Module::File *file3 = m.FindFile(string("foo")); |
michael@0 | 412 | Module::File *file4 = m.FindFile("bar"); |
michael@0 | 413 | EXPECT_NE(file1, file2); |
michael@0 | 414 | EXPECT_EQ(file1, file3); |
michael@0 | 415 | EXPECT_EQ(file2, file4); |
michael@0 | 416 | EXPECT_EQ(file1, m.FindExistingFile("foo")); |
michael@0 | 417 | EXPECT_TRUE(m.FindExistingFile("baz") == NULL); |
michael@0 | 418 | } |
michael@0 | 419 | |
michael@0 | 420 | TEST(Construct, DuplicateFunctions) { |
michael@0 | 421 | stringstream s; |
michael@0 | 422 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 423 | |
michael@0 | 424 | // Two functions. |
michael@0 | 425 | Module::Function *function1 = generate_duplicate_function("_without_form"); |
michael@0 | 426 | Module::Function *function2 = generate_duplicate_function("_without_form"); |
michael@0 | 427 | |
michael@0 | 428 | m.AddFunction(function1); |
michael@0 | 429 | m.AddFunction(function2); |
michael@0 | 430 | |
michael@0 | 431 | m.Write(s, ALL_SYMBOL_DATA); |
michael@0 | 432 | string contents = s.str(); |
michael@0 | 433 | EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
michael@0 | 434 | "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" |
michael@0 | 435 | " _without_form\n", |
michael@0 | 436 | contents.c_str()); |
michael@0 | 437 | } |
michael@0 | 438 | |
michael@0 | 439 | TEST(Construct, FunctionsWithSameAddress) { |
michael@0 | 440 | stringstream s; |
michael@0 | 441 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 442 | |
michael@0 | 443 | // Two functions. |
michael@0 | 444 | Module::Function *function1 = generate_duplicate_function("_without_form"); |
michael@0 | 445 | Module::Function *function2 = generate_duplicate_function("_and_void"); |
michael@0 | 446 | |
michael@0 | 447 | m.AddFunction(function1); |
michael@0 | 448 | m.AddFunction(function2); |
michael@0 | 449 | |
michael@0 | 450 | m.Write(s, ALL_SYMBOL_DATA); |
michael@0 | 451 | string contents = s.str(); |
michael@0 | 452 | EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
michael@0 | 453 | "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" |
michael@0 | 454 | " _and_void\n" |
michael@0 | 455 | "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" |
michael@0 | 456 | " _without_form\n", |
michael@0 | 457 | contents.c_str()); |
michael@0 | 458 | } |
michael@0 | 459 | |
michael@0 | 460 | // Externs should be written out as PUBLIC records, sorted by |
michael@0 | 461 | // address. |
michael@0 | 462 | TEST(Construct, Externs) { |
michael@0 | 463 | stringstream s; |
michael@0 | 464 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 465 | |
michael@0 | 466 | // Two externs. |
michael@0 | 467 | Module::Extern *extern1 = new(Module::Extern); |
michael@0 | 468 | extern1->address = 0xffff; |
michael@0 | 469 | extern1->name = "_abc"; |
michael@0 | 470 | Module::Extern *extern2 = new(Module::Extern); |
michael@0 | 471 | extern2->address = 0xaaaa; |
michael@0 | 472 | extern2->name = "_xyz"; |
michael@0 | 473 | |
michael@0 | 474 | m.AddExtern(extern1); |
michael@0 | 475 | m.AddExtern(extern2); |
michael@0 | 476 | |
michael@0 | 477 | m.Write(s, ALL_SYMBOL_DATA); |
michael@0 | 478 | string contents = s.str(); |
michael@0 | 479 | |
michael@0 | 480 | EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " |
michael@0 | 481 | MODULE_ID " " MODULE_NAME "\n" |
michael@0 | 482 | "PUBLIC aaaa 0 _xyz\n" |
michael@0 | 483 | "PUBLIC ffff 0 _abc\n", |
michael@0 | 484 | contents.c_str()); |
michael@0 | 485 | } |
michael@0 | 486 | |
michael@0 | 487 | // Externs with the same address should only keep the first entry |
michael@0 | 488 | // added. |
michael@0 | 489 | TEST(Construct, DuplicateExterns) { |
michael@0 | 490 | stringstream s; |
michael@0 | 491 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 492 | |
michael@0 | 493 | // Two externs. |
michael@0 | 494 | Module::Extern *extern1 = new(Module::Extern); |
michael@0 | 495 | extern1->address = 0xffff; |
michael@0 | 496 | extern1->name = "_xyz"; |
michael@0 | 497 | Module::Extern *extern2 = new(Module::Extern); |
michael@0 | 498 | extern2->address = 0xffff; |
michael@0 | 499 | extern2->name = "_abc"; |
michael@0 | 500 | |
michael@0 | 501 | m.AddExtern(extern1); |
michael@0 | 502 | m.AddExtern(extern2); |
michael@0 | 503 | |
michael@0 | 504 | m.Write(s, ALL_SYMBOL_DATA); |
michael@0 | 505 | string contents = s.str(); |
michael@0 | 506 | |
michael@0 | 507 | EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " |
michael@0 | 508 | MODULE_ID " " MODULE_NAME "\n" |
michael@0 | 509 | "PUBLIC ffff 0 _xyz\n", |
michael@0 | 510 | contents.c_str()); |
michael@0 | 511 | } |
michael@0 | 512 | |
michael@0 | 513 | TEST(Lookup, Function) { |
michael@0 | 514 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 515 | |
michael@0 | 516 | Module::Function *function1 = new(Module::Function); |
michael@0 | 517 | function1->name = "_abc1"; |
michael@0 | 518 | function1->address = 0x1000; |
michael@0 | 519 | function1->size = 0x900; |
michael@0 | 520 | function1->parameter_size = 0x0; |
michael@0 | 521 | |
michael@0 | 522 | Module::Function *function2 = new(Module::Function); |
michael@0 | 523 | function2->name = "_xyz2"; |
michael@0 | 524 | function2->address = 0x2000; |
michael@0 | 525 | function2->size = 0x900; |
michael@0 | 526 | function2->parameter_size = 0x0; |
michael@0 | 527 | |
michael@0 | 528 | Module::Function *function3 = new(Module::Function); |
michael@0 | 529 | function3->name = "_def3"; |
michael@0 | 530 | function3->address = 0x3000; |
michael@0 | 531 | function3->size = 0x900; |
michael@0 | 532 | function3->parameter_size = 0x0; |
michael@0 | 533 | |
michael@0 | 534 | // Put them in a vector. |
michael@0 | 535 | vector<Module::Function *> vec; |
michael@0 | 536 | vec.push_back(function1); |
michael@0 | 537 | vec.push_back(function2); |
michael@0 | 538 | vec.push_back(function3); |
michael@0 | 539 | |
michael@0 | 540 | m.AddFunctions(vec.begin(), vec.end()); |
michael@0 | 541 | |
michael@0 | 542 | // Try looking up functions by address. |
michael@0 | 543 | Module::Function* f = m.FindFunctionByAddress(0x1000); |
michael@0 | 544 | EXPECT_EQ(function1, f); |
michael@0 | 545 | f = m.FindFunctionByAddress(0x18FF); |
michael@0 | 546 | EXPECT_EQ(function1, f); |
michael@0 | 547 | |
michael@0 | 548 | f = m.FindFunctionByAddress(0x1900); |
michael@0 | 549 | EXPECT_EQ((Module::Function*)NULL, f); |
michael@0 | 550 | f = m.FindFunctionByAddress(0x1A00); |
michael@0 | 551 | EXPECT_EQ((Module::Function*)NULL, f); |
michael@0 | 552 | |
michael@0 | 553 | f = m.FindFunctionByAddress(0x2000); |
michael@0 | 554 | EXPECT_EQ(function2, f); |
michael@0 | 555 | f = m.FindFunctionByAddress(0x28FF); |
michael@0 | 556 | EXPECT_EQ(function2, f); |
michael@0 | 557 | |
michael@0 | 558 | f = m.FindFunctionByAddress(0x3000); |
michael@0 | 559 | EXPECT_EQ(function3, f); |
michael@0 | 560 | f = m.FindFunctionByAddress(0x38FF); |
michael@0 | 561 | EXPECT_EQ(function3, f); |
michael@0 | 562 | |
michael@0 | 563 | f = m.FindFunctionByAddress(0x3900); |
michael@0 | 564 | EXPECT_EQ((Module::Function*)NULL, f); |
michael@0 | 565 | f = m.FindFunctionByAddress(0x3A00); |
michael@0 | 566 | EXPECT_EQ((Module::Function*)NULL, f); |
michael@0 | 567 | } |
michael@0 | 568 | |
michael@0 | 569 | TEST(Lookup, Externs) { |
michael@0 | 570 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 571 | |
michael@0 | 572 | // Two externs. |
michael@0 | 573 | Module::Extern* extern1 = new(Module::Extern); |
michael@0 | 574 | extern1->address = 0x1000; |
michael@0 | 575 | extern1->name = "_abc"; |
michael@0 | 576 | Module::Extern* extern2 = new(Module::Extern); |
michael@0 | 577 | extern2->address = 0x2000; |
michael@0 | 578 | extern2->name = "_xyz"; |
michael@0 | 579 | |
michael@0 | 580 | m.AddExtern(extern1); |
michael@0 | 581 | m.AddExtern(extern2); |
michael@0 | 582 | |
michael@0 | 583 | Module::Extern* e = m.FindExternByAddress(0xFFF); |
michael@0 | 584 | EXPECT_EQ((Module::Extern*)NULL, e); |
michael@0 | 585 | |
michael@0 | 586 | e = m.FindExternByAddress(0x1000); |
michael@0 | 587 | EXPECT_EQ(extern1, e); |
michael@0 | 588 | e = m.FindExternByAddress(0x1900); |
michael@0 | 589 | EXPECT_EQ(extern1, e); |
michael@0 | 590 | e = m.FindExternByAddress(0x1FFF); |
michael@0 | 591 | EXPECT_EQ(extern1, e); |
michael@0 | 592 | |
michael@0 | 593 | e = m.FindExternByAddress(0x2000); |
michael@0 | 594 | EXPECT_EQ(extern2, e); |
michael@0 | 595 | e = m.FindExternByAddress(0x2900); |
michael@0 | 596 | EXPECT_EQ(extern2, e); |
michael@0 | 597 | e = m.FindExternByAddress(0xFFFFFFFF); |
michael@0 | 598 | EXPECT_EQ(extern2, e); |
michael@0 | 599 | } |
michael@0 | 600 | |
michael@0 | 601 | TEST(Lookup, StackFrameEntries) { |
michael@0 | 602 | Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
michael@0 | 603 | |
michael@0 | 604 | // First STACK CFI entry, with no initial rules or deltas. |
michael@0 | 605 | Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); |
michael@0 | 606 | entry1->address = 0x2000; |
michael@0 | 607 | entry1->size = 0x900; |
michael@0 | 608 | m.AddStackFrameEntry(entry1); |
michael@0 | 609 | |
michael@0 | 610 | // Second STACK CFI entry, with initial rules but no deltas. |
michael@0 | 611 | Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); |
michael@0 | 612 | entry2->address = 0x3000; |
michael@0 | 613 | entry2->size = 0x900; |
michael@0 | 614 | entry2->initial_rules[ustr__ZDcfa()] = |
michael@0 | 615 | Module::Expr("I think that I shall never see"); |
michael@0 | 616 | entry2->initial_rules[ToUniqueString("stromboli")] = |
michael@0 | 617 | Module::Expr("a poem lovely as a tree"); |
michael@0 | 618 | entry2->initial_rules[ToUniqueString("cannoli")] = |
michael@0 | 619 | Module::Expr("a tree whose hungry mouth is prest"); |
michael@0 | 620 | m.AddStackFrameEntry(entry2); |
michael@0 | 621 | |
michael@0 | 622 | // Third STACK CFI entry, with initial rules and deltas. |
michael@0 | 623 | Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); |
michael@0 | 624 | entry3->address = 0x1000; |
michael@0 | 625 | entry3->size = 0x900; |
michael@0 | 626 | entry3->initial_rules[ustr__ZDcfa()] = Module::Expr("Whose woods are these"); |
michael@0 | 627 | entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] = |
michael@0 | 628 | Module::Expr("the village though"); |
michael@0 | 629 | entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] = |
michael@0 | 630 | Module::Expr("he will not see me stopping here"); |
michael@0 | 631 | entry3->rule_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] = |
michael@0 | 632 | Module::Expr("his house is in"); |
michael@0 | 633 | entry3->rule_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] = |
michael@0 | 634 | Module::Expr("I think I know"); |
michael@0 | 635 | m.AddStackFrameEntry(entry3); |
michael@0 | 636 | |
michael@0 | 637 | Module::StackFrameEntry* s = m.FindStackFrameEntryByAddress(0x1000); |
michael@0 | 638 | EXPECT_EQ(entry3, s); |
michael@0 | 639 | s = m.FindStackFrameEntryByAddress(0x18FF); |
michael@0 | 640 | EXPECT_EQ(entry3, s); |
michael@0 | 641 | |
michael@0 | 642 | s = m.FindStackFrameEntryByAddress(0x1900); |
michael@0 | 643 | EXPECT_EQ((Module::StackFrameEntry*)NULL, s); |
michael@0 | 644 | s = m.FindStackFrameEntryByAddress(0x1A00); |
michael@0 | 645 | EXPECT_EQ((Module::StackFrameEntry*)NULL, s); |
michael@0 | 646 | |
michael@0 | 647 | s = m.FindStackFrameEntryByAddress(0x2000); |
michael@0 | 648 | EXPECT_EQ(entry1, s); |
michael@0 | 649 | s = m.FindStackFrameEntryByAddress(0x28FF); |
michael@0 | 650 | EXPECT_EQ(entry1, s); |
michael@0 | 651 | |
michael@0 | 652 | s = m.FindStackFrameEntryByAddress(0x3000); |
michael@0 | 653 | EXPECT_EQ(entry2, s); |
michael@0 | 654 | s = m.FindStackFrameEntryByAddress(0x38FF); |
michael@0 | 655 | EXPECT_EQ(entry2, s); |
michael@0 | 656 | |
michael@0 | 657 | s = m.FindStackFrameEntryByAddress(0x3900); |
michael@0 | 658 | EXPECT_EQ((Module::StackFrameEntry*)NULL, s); |
michael@0 | 659 | s = m.FindStackFrameEntryByAddress(0x3A00); |
michael@0 | 660 | EXPECT_EQ((Module::StackFrameEntry*)NULL, s); |
michael@0 | 661 | } |