|
1 // Copyright (c) 2011 Google Inc. |
|
2 // All rights reserved. |
|
3 // |
|
4 // Redistribution and use in source and binary forms, with or without |
|
5 // modification, are permitted provided that the following conditions are |
|
6 // met: |
|
7 // |
|
8 // * Redistributions of source code must retain the above copyright |
|
9 // notice, this list of conditions and the following disclaimer. |
|
10 // * Redistributions in binary form must reproduce the above |
|
11 // copyright notice, this list of conditions and the following disclaimer |
|
12 // in the documentation and/or other materials provided with the |
|
13 // distribution. |
|
14 // * Neither the name of Google Inc. nor the names of its |
|
15 // contributors may be used to endorse or promote products derived from |
|
16 // this software without specific prior written permission. |
|
17 // |
|
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
29 |
|
30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
|
31 |
|
32 // module.cc: Implement google_breakpad::Module. See module.h. |
|
33 |
|
34 #include "common/module.h" |
|
35 |
|
36 #include <assert.h> |
|
37 #include <errno.h> |
|
38 #include <stdio.h> |
|
39 #include <string.h> |
|
40 |
|
41 #include <algorithm> |
|
42 #include <iostream> |
|
43 #include <utility> |
|
44 |
|
45 namespace google_breakpad { |
|
46 |
|
47 using std::dec; |
|
48 using std::endl; |
|
49 using std::hex; |
|
50 |
|
51 |
|
52 Module::Module(const string &name, const string &os, |
|
53 const string &architecture, const string &id) : |
|
54 name_(name), |
|
55 os_(os), |
|
56 architecture_(architecture), |
|
57 id_(id), |
|
58 load_address_(0) { } |
|
59 |
|
60 Module::~Module() { |
|
61 for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) |
|
62 delete it->second; |
|
63 for (FunctionSet::iterator it = functions_.begin(); |
|
64 it != functions_.end(); ++it) { |
|
65 delete *it; |
|
66 } |
|
67 for (StackFrameEntrySet::iterator it = stack_frame_entries_.begin(); |
|
68 it != stack_frame_entries_.end(); ++it) { |
|
69 delete *it; |
|
70 } |
|
71 for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it) |
|
72 delete *it; |
|
73 } |
|
74 |
|
75 void Module::SetLoadAddress(Address address) { |
|
76 load_address_ = address; |
|
77 } |
|
78 |
|
79 void Module::AddFunction(Function *function) { |
|
80 // FUNC lines must not hold an empty name, so catch the problem early if |
|
81 // callers try to add one. |
|
82 assert(!function->name.empty()); |
|
83 std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function); |
|
84 if (!ret.second) { |
|
85 // Free the duplicate that was not inserted because this Module |
|
86 // now owns it. |
|
87 delete function; |
|
88 } |
|
89 } |
|
90 |
|
91 void Module::AddFunctions(vector<Function *>::iterator begin, |
|
92 vector<Function *>::iterator end) { |
|
93 for (vector<Function *>::iterator it = begin; it != end; ++it) |
|
94 AddFunction(*it); |
|
95 } |
|
96 |
|
97 void Module::AddStackFrameEntry(StackFrameEntry* stack_frame_entry) { |
|
98 std::pair<StackFrameEntrySet::iterator,bool> ret = |
|
99 stack_frame_entries_.insert(stack_frame_entry); |
|
100 if (!ret.second) { |
|
101 // Free the duplicate that was not inserted because this Module |
|
102 // now owns it. |
|
103 delete stack_frame_entry; |
|
104 } |
|
105 } |
|
106 |
|
107 void Module::AddExtern(Extern *ext) { |
|
108 std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext); |
|
109 if (!ret.second) { |
|
110 // Free the duplicate that was not inserted because this Module |
|
111 // now owns it. |
|
112 delete ext; |
|
113 } |
|
114 } |
|
115 |
|
116 void Module::GetFunctions(vector<Function *> *vec, |
|
117 vector<Function *>::iterator i) { |
|
118 vec->insert(i, functions_.begin(), functions_.end()); |
|
119 } |
|
120 |
|
121 template<typename T> |
|
122 bool EntryContainsAddress(T entry, Module::Address address) { |
|
123 return entry->address <= address && address < entry->address + entry->size; |
|
124 } |
|
125 |
|
126 Module::Function* Module::FindFunctionByAddress(Address address) { |
|
127 Function search; |
|
128 search.address = address; |
|
129 // Ensure that name always sorts higher than the function name, |
|
130 // so that upper_bound always returns the function just after |
|
131 // the function containing this address. |
|
132 search.name = "\xFF"; |
|
133 FunctionSet::iterator it = functions_.upper_bound(&search); |
|
134 if (it == functions_.begin()) |
|
135 return NULL; |
|
136 |
|
137 it--; |
|
138 |
|
139 if (EntryContainsAddress(*it, address)) |
|
140 return *it; |
|
141 |
|
142 return NULL; |
|
143 } |
|
144 |
|
145 void Module::GetExterns(vector<Extern *> *vec, |
|
146 vector<Extern *>::iterator i) { |
|
147 vec->insert(i, externs_.begin(), externs_.end()); |
|
148 } |
|
149 |
|
150 Module::Extern* Module::FindExternByAddress(Address address) { |
|
151 Extern search; |
|
152 search.address = address; |
|
153 ExternSet::iterator it = externs_.upper_bound(&search); |
|
154 |
|
155 if (it == externs_.begin()) |
|
156 return NULL; |
|
157 |
|
158 it--; |
|
159 if ((*it)->address > address) |
|
160 return NULL; |
|
161 |
|
162 return *it; |
|
163 } |
|
164 |
|
165 Module::File *Module::FindFile(const string &name) { |
|
166 // A tricky bit here. The key of each map entry needs to be a |
|
167 // pointer to the entry's File's name string. This means that we |
|
168 // can't do the initial lookup with any operation that would create |
|
169 // an empty entry for us if the name isn't found (like, say, |
|
170 // operator[] or insert do), because such a created entry's key will |
|
171 // be a pointer the string passed as our argument. Since the key of |
|
172 // a map's value type is const, we can't fix it up once we've |
|
173 // created our file. lower_bound does the lookup without doing an |
|
174 // insertion, and returns a good hint iterator to pass to insert. |
|
175 // Our "destiny" is where we belong, whether we're there or not now. |
|
176 FileByNameMap::iterator destiny = files_.lower_bound(&name); |
|
177 if (destiny == files_.end() |
|
178 || *destiny->first != name) { // Repeated string comparison, boo hoo. |
|
179 File *file = new File; |
|
180 file->name = name; |
|
181 file->source_id = -1; |
|
182 destiny = files_.insert(destiny, |
|
183 FileByNameMap::value_type(&file->name, file)); |
|
184 } |
|
185 return destiny->second; |
|
186 } |
|
187 |
|
188 Module::File *Module::FindFile(const char *name) { |
|
189 string name_string = name; |
|
190 return FindFile(name_string); |
|
191 } |
|
192 |
|
193 Module::File *Module::FindExistingFile(const string &name) { |
|
194 FileByNameMap::iterator it = files_.find(&name); |
|
195 return (it == files_.end()) ? NULL : it->second; |
|
196 } |
|
197 |
|
198 void Module::GetFiles(vector<File *> *vec) { |
|
199 vec->clear(); |
|
200 for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) |
|
201 vec->push_back(it->second); |
|
202 } |
|
203 |
|
204 void Module::GetStackFrameEntries(vector<StackFrameEntry *>* vec) { |
|
205 vec->clear(); |
|
206 vec->insert(vec->begin(), stack_frame_entries_.begin(), |
|
207 stack_frame_entries_.end()); |
|
208 } |
|
209 |
|
210 Module::StackFrameEntry* Module::FindStackFrameEntryByAddress(Address address) { |
|
211 StackFrameEntry search; |
|
212 search.address = address; |
|
213 StackFrameEntrySet::iterator it = stack_frame_entries_.upper_bound(&search); |
|
214 |
|
215 if (it == stack_frame_entries_.begin()) |
|
216 return NULL; |
|
217 |
|
218 it--; |
|
219 if (EntryContainsAddress(*it, address)) |
|
220 return *it; |
|
221 |
|
222 return NULL; |
|
223 } |
|
224 |
|
225 void Module::AssignSourceIds() { |
|
226 // First, give every source file an id of -1. |
|
227 for (FileByNameMap::iterator file_it = files_.begin(); |
|
228 file_it != files_.end(); ++file_it) { |
|
229 file_it->second->source_id = -1; |
|
230 } |
|
231 |
|
232 // Next, mark all files actually cited by our functions' line number |
|
233 // info, by setting each one's source id to zero. |
|
234 for (FunctionSet::const_iterator func_it = functions_.begin(); |
|
235 func_it != functions_.end(); ++func_it) { |
|
236 Function *func = *func_it; |
|
237 for (vector<Line>::iterator line_it = func->lines.begin(); |
|
238 line_it != func->lines.end(); ++line_it) |
|
239 line_it->file->source_id = 0; |
|
240 } |
|
241 |
|
242 // Finally, assign source ids to those files that have been marked. |
|
243 // We could have just assigned source id numbers while traversing |
|
244 // the line numbers, but doing it this way numbers the files in |
|
245 // lexicographical order by name, which is neat. |
|
246 int next_source_id = 0; |
|
247 for (FileByNameMap::iterator file_it = files_.begin(); |
|
248 file_it != files_.end(); ++file_it) { |
|
249 if (!file_it->second->source_id) |
|
250 file_it->second->source_id = next_source_id++; |
|
251 } |
|
252 } |
|
253 |
|
254 bool Module::ReportError() { |
|
255 fprintf(stderr, "error writing symbol file: %s\n", |
|
256 strerror(errno)); |
|
257 return false; |
|
258 } |
|
259 |
|
260 std::ostream& operator<<(std::ostream& stream, const Module::Expr& expr) { |
|
261 assert(!expr.isExprInvalid()); |
|
262 switch (expr.how_) { |
|
263 case Module::kExprSimple: |
|
264 stream << FromUniqueString(expr.ident_) << " " << expr.offset_ << " +"; |
|
265 break; |
|
266 case Module::kExprSimpleMem: |
|
267 stream << FromUniqueString(expr.ident_) << " " << expr.offset_ << " + ^"; |
|
268 break; |
|
269 case Module::kExprPostfix: |
|
270 stream << expr.postfix_; break; |
|
271 case Module::kExprInvalid: |
|
272 default: |
|
273 break; |
|
274 } |
|
275 return stream; |
|
276 } |
|
277 |
|
278 bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) { |
|
279 // Visit the register rules in alphabetical order. Because |
|
280 // rule_map has the elements in some arbitrary order, |
|
281 // get the names out into a vector, sort them, and visit in |
|
282 // sorted order. |
|
283 std::vector<const UniqueString*> rr_names; |
|
284 for (RuleMap::const_iterator it = rule_map.begin(); |
|
285 it != rule_map.end(); ++it) { |
|
286 rr_names.push_back(it->first); |
|
287 } |
|
288 |
|
289 std::sort(rr_names.begin(), rr_names.end(), LessThan_UniqueString); |
|
290 |
|
291 // Now visit the register rules in alphabetical order. |
|
292 for (std::vector<const UniqueString*>::const_iterator name = rr_names.begin(); |
|
293 name != rr_names.end(); |
|
294 ++name) { |
|
295 if (name != rr_names.begin()) |
|
296 stream << " "; |
|
297 stream << FromUniqueString(*name) << ": " << rule_map.find(*name)->second; |
|
298 } |
|
299 return stream.good(); |
|
300 } |
|
301 |
|
302 bool Module::Write(std::ostream &stream, SymbolData symbol_data) { |
|
303 stream << "MODULE " << os_ << " " << architecture_ << " " |
|
304 << id_ << " " << name_ << endl; |
|
305 if (!stream.good()) |
|
306 return ReportError(); |
|
307 |
|
308 if (symbol_data != ONLY_CFI) { |
|
309 AssignSourceIds(); |
|
310 |
|
311 // Write out files. |
|
312 for (FileByNameMap::iterator file_it = files_.begin(); |
|
313 file_it != files_.end(); ++file_it) { |
|
314 File *file = file_it->second; |
|
315 if (file->source_id >= 0) { |
|
316 stream << "FILE " << file->source_id << " " << file->name << endl; |
|
317 if (!stream.good()) |
|
318 return ReportError(); |
|
319 } |
|
320 } |
|
321 |
|
322 // Write out functions and their lines. |
|
323 for (FunctionSet::const_iterator func_it = functions_.begin(); |
|
324 func_it != functions_.end(); ++func_it) { |
|
325 Function *func = *func_it; |
|
326 stream << "FUNC " << hex |
|
327 << (func->address - load_address_) << " " |
|
328 << func->size << " " |
|
329 << func->parameter_size << " " |
|
330 << func->name << dec << endl; |
|
331 if (!stream.good()) |
|
332 return ReportError(); |
|
333 |
|
334 for (vector<Line>::iterator line_it = func->lines.begin(); |
|
335 line_it != func->lines.end(); ++line_it) { |
|
336 stream << hex |
|
337 << (line_it->address - load_address_) << " " |
|
338 << line_it->size << " " |
|
339 << dec |
|
340 << line_it->number << " " |
|
341 << line_it->file->source_id << endl; |
|
342 if (!stream.good()) |
|
343 return ReportError(); |
|
344 } |
|
345 } |
|
346 |
|
347 // Write out 'PUBLIC' records. |
|
348 for (ExternSet::const_iterator extern_it = externs_.begin(); |
|
349 extern_it != externs_.end(); ++extern_it) { |
|
350 Extern *ext = *extern_it; |
|
351 stream << "PUBLIC " << hex |
|
352 << (ext->address - load_address_) << " 0 " |
|
353 << ext->name << dec << endl; |
|
354 } |
|
355 } |
|
356 |
|
357 if (symbol_data != NO_CFI) { |
|
358 // Write out 'STACK CFI INIT' and 'STACK CFI' records. |
|
359 StackFrameEntrySet::const_iterator frame_it; |
|
360 for (frame_it = stack_frame_entries_.begin(); |
|
361 frame_it != stack_frame_entries_.end(); ++frame_it) { |
|
362 StackFrameEntry *entry = *frame_it; |
|
363 stream << "STACK CFI INIT " << hex |
|
364 << (entry->address - load_address_) << " " |
|
365 << entry->size << " " << dec; |
|
366 if (!stream.good() |
|
367 || !WriteRuleMap(entry->initial_rules, stream)) |
|
368 return ReportError(); |
|
369 |
|
370 stream << endl; |
|
371 |
|
372 // Write out this entry's delta rules as 'STACK CFI' records. |
|
373 for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin(); |
|
374 delta_it != entry->rule_changes.end(); ++delta_it) { |
|
375 stream << "STACK CFI " << hex |
|
376 << (delta_it->first - load_address_) << " " << dec; |
|
377 if (!stream.good() |
|
378 || !WriteRuleMap(delta_it->second, stream)) |
|
379 return ReportError(); |
|
380 |
|
381 stream << endl; |
|
382 } |
|
383 } |
|
384 } |
|
385 |
|
386 return true; |
|
387 } |
|
388 |
|
389 } // namespace google_breakpad |