|
1 # HG changeset patch |
|
2 # User Ted Mielczarek <ted@mielczarek.org> |
|
3 # Date 1352220493 18000 |
|
4 # Node ID c3b1109dd392c16a9fe4e85da693010966dbbf0b |
|
5 # Parent 03db269a2868503cca9e80f62ce676aabbf967fd |
|
6 Add APIs for querying Module data |
|
7 R=glandium at https://breakpad.appspot.com/511003/ |
|
8 |
|
9 diff --git a/src/common/module.cc b/src/common/module.cc |
|
10 --- a/src/common/module.cc |
|
11 +++ b/src/common/module.cc |
|
12 @@ -58,17 +58,17 @@ |
|
13 |
|
14 Module::~Module() { |
|
15 for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) |
|
16 delete it->second; |
|
17 for (FunctionSet::iterator it = functions_.begin(); |
|
18 it != functions_.end(); ++it) { |
|
19 delete *it; |
|
20 } |
|
21 - for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin(); |
|
22 + for (StackFrameEntrySet::iterator it = stack_frame_entries_.begin(); |
|
23 it != stack_frame_entries_.end(); ++it) { |
|
24 delete *it; |
|
25 } |
|
26 for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it) |
|
27 delete *it; |
|
28 } |
|
29 |
|
30 void Module::SetLoadAddress(Address address) { |
|
31 @@ -88,39 +88,84 @@ |
|
32 } |
|
33 |
|
34 void Module::AddFunctions(vector<Function *>::iterator begin, |
|
35 vector<Function *>::iterator end) { |
|
36 for (vector<Function *>::iterator it = begin; it != end; ++it) |
|
37 AddFunction(*it); |
|
38 } |
|
39 |
|
40 -void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) { |
|
41 - stack_frame_entries_.push_back(stack_frame_entry); |
|
42 +void Module::AddStackFrameEntry(StackFrameEntry* stack_frame_entry) { |
|
43 + std::pair<StackFrameEntrySet::iterator,bool> ret = |
|
44 + stack_frame_entries_.insert(stack_frame_entry); |
|
45 + if (!ret.second) { |
|
46 + // Free the duplicate that was not inserted because this Module |
|
47 + // now owns it. |
|
48 + delete stack_frame_entry; |
|
49 + } |
|
50 } |
|
51 |
|
52 void Module::AddExtern(Extern *ext) { |
|
53 std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext); |
|
54 if (!ret.second) { |
|
55 // Free the duplicate that was not inserted because this Module |
|
56 // now owns it. |
|
57 delete ext; |
|
58 } |
|
59 } |
|
60 |
|
61 void Module::GetFunctions(vector<Function *> *vec, |
|
62 vector<Function *>::iterator i) { |
|
63 vec->insert(i, functions_.begin(), functions_.end()); |
|
64 } |
|
65 |
|
66 +template<typename T> |
|
67 +bool EntryContainsAddress(T entry, Module::Address address) { |
|
68 + return entry->address <= address && address < entry->address + entry->size; |
|
69 +} |
|
70 + |
|
71 +Module::Function* Module::FindFunctionByAddress(Address address) { |
|
72 + Function search; |
|
73 + search.address = address; |
|
74 + // Ensure that name always sorts higher than the function name, |
|
75 + // so that upper_bound always returns the function just after |
|
76 + // the function containing this address. |
|
77 + search.name = "\xFF"; |
|
78 + FunctionSet::iterator it = functions_.upper_bound(&search); |
|
79 + if (it == functions_.begin()) |
|
80 + return NULL; |
|
81 + |
|
82 + it--; |
|
83 + |
|
84 + if (EntryContainsAddress(*it, address)) |
|
85 + return *it; |
|
86 + |
|
87 + return NULL; |
|
88 +} |
|
89 + |
|
90 void Module::GetExterns(vector<Extern *> *vec, |
|
91 vector<Extern *>::iterator i) { |
|
92 vec->insert(i, externs_.begin(), externs_.end()); |
|
93 } |
|
94 |
|
95 +Module::Extern* Module::FindExternByAddress(Address address) { |
|
96 + Extern search; |
|
97 + search.address = address; |
|
98 + ExternSet::iterator it = externs_.upper_bound(&search); |
|
99 + |
|
100 + if (it == externs_.begin()) |
|
101 + return NULL; |
|
102 + |
|
103 + it--; |
|
104 + if ((*it)->address > address) |
|
105 + return NULL; |
|
106 + |
|
107 + return *it; |
|
108 +} |
|
109 + |
|
110 Module::File *Module::FindFile(const string &name) { |
|
111 // A tricky bit here. The key of each map entry needs to be a |
|
112 // pointer to the entry's File's name string. This means that we |
|
113 // can't do the initial lookup with any operation that would create |
|
114 // an empty entry for us if the name isn't found (like, say, |
|
115 // operator[] or insert do), because such a created entry's key will |
|
116 // be a pointer the string passed as our argument. Since the key of |
|
117 // a map's value type is const, we can't fix it up once we've |
|
118 @@ -150,18 +195,35 @@ |
|
119 } |
|
120 |
|
121 void Module::GetFiles(vector<File *> *vec) { |
|
122 vec->clear(); |
|
123 for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) |
|
124 vec->push_back(it->second); |
|
125 } |
|
126 |
|
127 -void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) { |
|
128 - *vec = stack_frame_entries_; |
|
129 +void Module::GetStackFrameEntries(vector<StackFrameEntry *>* vec) { |
|
130 + vec->clear(); |
|
131 + vec->insert(vec->begin(), stack_frame_entries_.begin(), |
|
132 + stack_frame_entries_.end()); |
|
133 +} |
|
134 + |
|
135 +Module::StackFrameEntry* Module::FindStackFrameEntryByAddress(Address address) { |
|
136 + StackFrameEntry search; |
|
137 + search.address = address; |
|
138 + StackFrameEntrySet::iterator it = stack_frame_entries_.upper_bound(&search); |
|
139 + |
|
140 + if (it == stack_frame_entries_.begin()) |
|
141 + return NULL; |
|
142 + |
|
143 + it--; |
|
144 + if (EntryContainsAddress(*it, address)) |
|
145 + return *it; |
|
146 + |
|
147 + return NULL; |
|
148 } |
|
149 |
|
150 void Module::AssignSourceIds() { |
|
151 // First, give every source file an id of -1. |
|
152 for (FileByNameMap::iterator file_it = files_.begin(); |
|
153 file_it != files_.end(); ++file_it) { |
|
154 file_it->second->source_id = -1; |
|
155 } |
|
156 @@ -256,17 +318,17 @@ |
|
157 stream << "PUBLIC " << hex |
|
158 << (ext->address - load_address_) << " 0 " |
|
159 << ext->name << dec << endl; |
|
160 } |
|
161 } |
|
162 |
|
163 if (symbol_data != NO_CFI) { |
|
164 // Write out 'STACK CFI INIT' and 'STACK CFI' records. |
|
165 - vector<StackFrameEntry *>::const_iterator frame_it; |
|
166 + StackFrameEntrySet::const_iterator frame_it; |
|
167 for (frame_it = stack_frame_entries_.begin(); |
|
168 frame_it != stack_frame_entries_.end(); ++frame_it) { |
|
169 StackFrameEntry *entry = *frame_it; |
|
170 stream << "STACK CFI INIT " << hex |
|
171 << (entry->address - load_address_) << " " |
|
172 << entry->size << " " << dec; |
|
173 if (!stream.good() |
|
174 || !WriteRuleMap(entry->initial_rules, stream)) |
|
175 diff --git a/src/common/module.h b/src/common/module.h |
|
176 --- a/src/common/module.h |
|
177 +++ b/src/common/module.h |
|
178 @@ -164,16 +164,23 @@ |
|
179 |
|
180 struct ExternCompare { |
|
181 bool operator() (const Extern *lhs, |
|
182 const Extern *rhs) const { |
|
183 return lhs->address < rhs->address; |
|
184 } |
|
185 }; |
|
186 |
|
187 + struct StackFrameEntryCompare { |
|
188 + bool operator() (const StackFrameEntry* lhs, |
|
189 + const StackFrameEntry* rhs) const { |
|
190 + return lhs->address < rhs->address; |
|
191 + } |
|
192 + }; |
|
193 + |
|
194 // Create a new module with the given name, operating system, |
|
195 // architecture, and ID string. |
|
196 Module(const string &name, const string &os, const string &architecture, |
|
197 const string &id); |
|
198 ~Module(); |
|
199 |
|
200 // Set the module's load address to LOAD_ADDRESS; addresses given |
|
201 // for functions and lines will be written to the Breakpad symbol |
|
202 @@ -223,37 +230,49 @@ |
|
203 |
|
204 // Insert pointers to the functions added to this module at I in |
|
205 // VEC. The pointed-to Functions are still owned by this module. |
|
206 // (Since this is effectively a copy of the function list, this is |
|
207 // mostly useful for testing; other uses should probably get a more |
|
208 // appropriate interface.) |
|
209 void GetFunctions(vector<Function *> *vec, vector<Function *>::iterator i); |
|
210 |
|
211 + // If this module has a function at ADDRESS, return a pointer to it. |
|
212 + // Otherwise, return NULL. |
|
213 + Function* FindFunctionByAddress(Address address); |
|
214 + |
|
215 // Insert pointers to the externs added to this module at I in |
|
216 // VEC. The pointed-to Externs are still owned by this module. |
|
217 // (Since this is effectively a copy of the extern list, this is |
|
218 // mostly useful for testing; other uses should probably get a more |
|
219 // appropriate interface.) |
|
220 void GetExterns(vector<Extern *> *vec, vector<Extern *>::iterator i); |
|
221 |
|
222 + // If this module has an extern whose base address is less than ADDRESS, |
|
223 + // return a pointer to it. Otherwise, return NULL. |
|
224 + Extern* FindExternByAddress(Address address); |
|
225 + |
|
226 // Clear VEC and fill it with pointers to the Files added to this |
|
227 // module, sorted by name. The pointed-to Files are still owned by |
|
228 // this module. (Since this is effectively a copy of the file list, |
|
229 // this is mostly useful for testing; other uses should probably get |
|
230 // a more appropriate interface.) |
|
231 void GetFiles(vector<File *> *vec); |
|
232 |
|
233 // Clear VEC and fill it with pointers to the StackFrameEntry |
|
234 // objects that have been added to this module. (Since this is |
|
235 // effectively a copy of the stack frame entry list, this is mostly |
|
236 // useful for testing; other uses should probably get |
|
237 // a more appropriate interface.) |
|
238 void GetStackFrameEntries(vector<StackFrameEntry *> *vec); |
|
239 |
|
240 + // If this module has a StackFrameEntry whose address range covers |
|
241 + // ADDRESS, return it. Otherwise return NULL. |
|
242 + StackFrameEntry* FindStackFrameEntryByAddress(Address address); |
|
243 + |
|
244 // Find those files in this module that are actually referred to by |
|
245 // functions' line number data, and assign them source id numbers. |
|
246 // Set the source id numbers for all other files --- unused by the |
|
247 // source line data --- to -1. We do this before writing out the |
|
248 // symbol file, at which point we omit any unused files. |
|
249 void AssignSourceIds(); |
|
250 |
|
251 // Call AssignSourceIds, and write this module to STREAM in the |
|
252 @@ -299,25 +318,28 @@ |
|
253 typedef map<const string *, File *, CompareStringPtrs> FileByNameMap; |
|
254 |
|
255 // A set containing Function structures, sorted by address. |
|
256 typedef set<Function *, FunctionCompare> FunctionSet; |
|
257 |
|
258 // A set containing Extern structures, sorted by address. |
|
259 typedef set<Extern *, ExternCompare> ExternSet; |
|
260 |
|
261 + // A set containing StackFrameEntry structures, sorted by address. |
|
262 + typedef set<StackFrameEntry*, StackFrameEntryCompare> StackFrameEntrySet; |
|
263 + |
|
264 // The module owns all the files and functions that have been added |
|
265 // to it; destroying the module frees the Files and Functions these |
|
266 // point to. |
|
267 FileByNameMap files_; // This module's source files. |
|
268 FunctionSet functions_; // This module's functions. |
|
269 |
|
270 // The module owns all the call frame info entries that have been |
|
271 // added to it. |
|
272 - vector<StackFrameEntry *> stack_frame_entries_; |
|
273 + StackFrameEntrySet stack_frame_entries_; |
|
274 |
|
275 // The module owns all the externs that have been added to it; |
|
276 // destroying the module frees the Externs these point to. |
|
277 ExternSet externs_; |
|
278 }; |
|
279 |
|
280 } // namespace google_breakpad |
|
281 |
|
282 diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc |
|
283 --- a/src/common/module_unittest.cc |
|
284 +++ b/src/common/module_unittest.cc |
|
285 @@ -329,63 +329,63 @@ |
|
286 entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = |
|
287 "I think I know"; |
|
288 m.AddStackFrameEntry(entry3); |
|
289 |
|
290 // Check that Write writes STACK CFI records properly. |
|
291 m.Write(s, ALL_SYMBOL_DATA); |
|
292 string contents = s.str(); |
|
293 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" |
|
294 - "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n" |
|
295 - "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" |
|
296 - " .cfa: I think that I shall never see" |
|
297 - " cannoli: a tree whose hungry mouth is prest" |
|
298 - " stromboli: a poem lovely as a tree\n" |
|
299 "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" |
|
300 " .cfa: Whose woods are these\n" |
|
301 "STACK CFI 36682fad3763ffff" |
|
302 " .cfa: I think I know" |
|
303 " stromboli: his house is in\n" |
|
304 "STACK CFI 47ceb0f63c269d7f" |
|
305 " calzone: the village though" |
|
306 - " cannoli: he will not see me stopping here\n", |
|
307 + " cannoli: he will not see me stopping here\n" |
|
308 + "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" |
|
309 + " .cfa: I think that I shall never see" |
|
310 + " cannoli: a tree whose hungry mouth is prest" |
|
311 + " stromboli: a poem lovely as a tree\n" |
|
312 + "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n", |
|
313 contents.c_str()); |
|
314 |
|
315 // Check that GetStackFrameEntries works. |
|
316 vector<Module::StackFrameEntry *> entries; |
|
317 m.GetStackFrameEntries(&entries); |
|
318 ASSERT_EQ(3U, entries.size()); |
|
319 // Check first entry. |
|
320 - EXPECT_EQ(0xddb5f41285aa7757ULL, entries[0]->address); |
|
321 - EXPECT_EQ(0x1486493370dc5073ULL, entries[0]->size); |
|
322 - ASSERT_EQ(0U, entries[0]->initial_rules.size()); |
|
323 - ASSERT_EQ(0U, entries[0]->rule_changes.size()); |
|
324 + EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[0]->address); |
|
325 + EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[0]->size); |
|
326 + Module::RuleMap entry1_initial; |
|
327 + entry1_initial[".cfa"] = "Whose woods are these"; |
|
328 + EXPECT_THAT(entries[0]->initial_rules, ContainerEq(entry1_initial)); |
|
329 + Module::RuleChangeMap entry1_changes; |
|
330 + entry1_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; |
|
331 + entry1_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in"; |
|
332 + entry1_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though"; |
|
333 + entry1_changes[0x47ceb0f63c269d7fULL]["cannoli"] = |
|
334 + "he will not see me stopping here"; |
|
335 + EXPECT_THAT(entries[0]->rule_changes, ContainerEq(entry1_changes)); |
|
336 // Check second entry. |
|
337 EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); |
|
338 EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); |
|
339 ASSERT_EQ(3U, entries[1]->initial_rules.size()); |
|
340 Module::RuleMap entry2_initial; |
|
341 entry2_initial[".cfa"] = "I think that I shall never see"; |
|
342 entry2_initial["stromboli"] = "a poem lovely as a tree"; |
|
343 entry2_initial["cannoli"] = "a tree whose hungry mouth is prest"; |
|
344 EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); |
|
345 ASSERT_EQ(0U, entries[1]->rule_changes.size()); |
|
346 // Check third entry. |
|
347 - EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[2]->address); |
|
348 - EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[2]->size); |
|
349 - Module::RuleMap entry3_initial; |
|
350 - entry3_initial[".cfa"] = "Whose woods are these"; |
|
351 - EXPECT_THAT(entries[2]->initial_rules, ContainerEq(entry3_initial)); |
|
352 - Module::RuleChangeMap entry3_changes; |
|
353 - entry3_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; |
|
354 - entry3_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in"; |
|
355 - entry3_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though"; |
|
356 - entry3_changes[0x47ceb0f63c269d7fULL]["cannoli"] = |
|
357 - "he will not see me stopping here"; |
|
358 - EXPECT_THAT(entries[2]->rule_changes, ContainerEq(entry3_changes)); |
|
359 + EXPECT_EQ(0xddb5f41285aa7757ULL, entries[2]->address); |
|
360 + EXPECT_EQ(0x1486493370dc5073ULL, entries[2]->size); |
|
361 + ASSERT_EQ(0U, entries[2]->initial_rules.size()); |
|
362 + ASSERT_EQ(0U, entries[2]->rule_changes.size()); |
|
363 } |
|
364 |
|
365 TEST(Construct, UniqueFiles) { |
|
366 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
367 Module::File *file1 = m.FindFile("foo"); |
|
368 Module::File *file2 = m.FindFile(string("bar")); |
|
369 Module::File *file3 = m.FindFile(string("foo")); |
|
370 Module::File *file4 = m.FindFile("bar"); |
|
371 @@ -483,8 +483,155 @@ |
|
372 m.Write(s, ALL_SYMBOL_DATA); |
|
373 string contents = s.str(); |
|
374 |
|
375 EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " |
|
376 MODULE_ID " " MODULE_NAME "\n" |
|
377 "PUBLIC ffff 0 _xyz\n", |
|
378 contents.c_str()); |
|
379 } |
|
380 + |
|
381 +TEST(Lookup, Function) { |
|
382 + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
383 + |
|
384 + Module::Function *function1 = new(Module::Function); |
|
385 + function1->name = "_abc1"; |
|
386 + function1->address = 0x1000; |
|
387 + function1->size = 0x900; |
|
388 + function1->parameter_size = 0x0; |
|
389 + |
|
390 + Module::Function *function2 = new(Module::Function); |
|
391 + function2->name = "_xyz2"; |
|
392 + function2->address = 0x2000; |
|
393 + function2->size = 0x900; |
|
394 + function2->parameter_size = 0x0; |
|
395 + |
|
396 + Module::Function *function3 = new(Module::Function); |
|
397 + function3->name = "_def3"; |
|
398 + function3->address = 0x3000; |
|
399 + function3->size = 0x900; |
|
400 + function3->parameter_size = 0x0; |
|
401 + |
|
402 + // Put them in a vector. |
|
403 + vector<Module::Function *> vec; |
|
404 + vec.push_back(function1); |
|
405 + vec.push_back(function2); |
|
406 + vec.push_back(function3); |
|
407 + |
|
408 + m.AddFunctions(vec.begin(), vec.end()); |
|
409 + |
|
410 + // Try looking up functions by address. |
|
411 + Module::Function* f = m.FindFunctionByAddress(0x1000); |
|
412 + EXPECT_EQ(function1, f); |
|
413 + f = m.FindFunctionByAddress(0x18FF); |
|
414 + EXPECT_EQ(function1, f); |
|
415 + |
|
416 + f = m.FindFunctionByAddress(0x1900); |
|
417 + EXPECT_EQ((Module::Function*)NULL, f); |
|
418 + f = m.FindFunctionByAddress(0x1A00); |
|
419 + EXPECT_EQ((Module::Function*)NULL, f); |
|
420 + |
|
421 + f = m.FindFunctionByAddress(0x2000); |
|
422 + EXPECT_EQ(function2, f); |
|
423 + f = m.FindFunctionByAddress(0x28FF); |
|
424 + EXPECT_EQ(function2, f); |
|
425 + |
|
426 + f = m.FindFunctionByAddress(0x3000); |
|
427 + EXPECT_EQ(function3, f); |
|
428 + f = m.FindFunctionByAddress(0x38FF); |
|
429 + EXPECT_EQ(function3, f); |
|
430 + |
|
431 + f = m.FindFunctionByAddress(0x3900); |
|
432 + EXPECT_EQ((Module::Function*)NULL, f); |
|
433 + f = m.FindFunctionByAddress(0x3A00); |
|
434 + EXPECT_EQ((Module::Function*)NULL, f); |
|
435 +} |
|
436 + |
|
437 +TEST(Lookup, Externs) { |
|
438 + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
439 + |
|
440 + // Two externs. |
|
441 + Module::Extern* extern1 = new(Module::Extern); |
|
442 + extern1->address = 0x1000; |
|
443 + extern1->name = "_abc"; |
|
444 + Module::Extern* extern2 = new(Module::Extern); |
|
445 + extern2->address = 0x2000; |
|
446 + extern2->name = "_xyz"; |
|
447 + |
|
448 + m.AddExtern(extern1); |
|
449 + m.AddExtern(extern2); |
|
450 + |
|
451 + Module::Extern* e = m.FindExternByAddress(0xFFF); |
|
452 + EXPECT_EQ((Module::Extern*)NULL, e); |
|
453 + |
|
454 + e = m.FindExternByAddress(0x1000); |
|
455 + EXPECT_EQ(extern1, e); |
|
456 + e = m.FindExternByAddress(0x1900); |
|
457 + EXPECT_EQ(extern1, e); |
|
458 + e = m.FindExternByAddress(0x1FFF); |
|
459 + EXPECT_EQ(extern1, e); |
|
460 + |
|
461 + e = m.FindExternByAddress(0x2000); |
|
462 + EXPECT_EQ(extern2, e); |
|
463 + e = m.FindExternByAddress(0x2900); |
|
464 + EXPECT_EQ(extern2, e); |
|
465 + e = m.FindExternByAddress(0xFFFFFFFF); |
|
466 + EXPECT_EQ(extern2, e); |
|
467 +} |
|
468 + |
|
469 +TEST(Lookup, StackFrameEntries) { |
|
470 + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); |
|
471 + |
|
472 + // First STACK CFI entry, with no initial rules or deltas. |
|
473 + Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); |
|
474 + entry1->address = 0x2000; |
|
475 + entry1->size = 0x900; |
|
476 + m.AddStackFrameEntry(entry1); |
|
477 + |
|
478 + // Second STACK CFI entry, with initial rules but no deltas. |
|
479 + Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); |
|
480 + entry2->address = 0x3000; |
|
481 + entry2->size = 0x900; |
|
482 + entry2->initial_rules[".cfa"] = "I think that I shall never see"; |
|
483 + entry2->initial_rules["stromboli"] = "a poem lovely as a tree"; |
|
484 + entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest"; |
|
485 + m.AddStackFrameEntry(entry2); |
|
486 + |
|
487 + // Third STACK CFI entry, with initial rules and deltas. |
|
488 + Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); |
|
489 + entry3->address = 0x1000; |
|
490 + entry3->size = 0x900; |
|
491 + entry3->initial_rules[".cfa"] = "Whose woods are these"; |
|
492 + entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = |
|
493 + "the village though"; |
|
494 + entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = |
|
495 + "he will not see me stopping here"; |
|
496 + entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = |
|
497 + "his house is in"; |
|
498 + entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = |
|
499 + "I think I know"; |
|
500 + m.AddStackFrameEntry(entry3); |
|
501 + |
|
502 + Module::StackFrameEntry* s = m.FindStackFrameEntryByAddress(0x1000); |
|
503 + EXPECT_EQ(entry3, s); |
|
504 + s = m.FindStackFrameEntryByAddress(0x18FF); |
|
505 + EXPECT_EQ(entry3, s); |
|
506 + |
|
507 + s = m.FindStackFrameEntryByAddress(0x1900); |
|
508 + EXPECT_EQ((Module::StackFrameEntry*)NULL, s); |
|
509 + s = m.FindStackFrameEntryByAddress(0x1A00); |
|
510 + EXPECT_EQ((Module::StackFrameEntry*)NULL, s); |
|
511 + |
|
512 + s = m.FindStackFrameEntryByAddress(0x2000); |
|
513 + EXPECT_EQ(entry1, s); |
|
514 + s = m.FindStackFrameEntryByAddress(0x28FF); |
|
515 + EXPECT_EQ(entry1, s); |
|
516 + |
|
517 + s = m.FindStackFrameEntryByAddress(0x3000); |
|
518 + EXPECT_EQ(entry2, s); |
|
519 + s = m.FindStackFrameEntryByAddress(0x38FF); |
|
520 + EXPECT_EQ(entry2, s); |
|
521 + |
|
522 + s = m.FindStackFrameEntryByAddress(0x3900); |
|
523 + EXPECT_EQ((Module::StackFrameEntry*)NULL, s); |
|
524 + s = m.FindStackFrameEntryByAddress(0x3A00); |
|
525 + EXPECT_EQ((Module::StackFrameEntry*)NULL, s); |
|
526 +} |