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 <iostream>
42 #include <utility>
43
44 namespace google_breakpad {
45
46 using std::dec;
47 using std::endl;
48 using std::hex;
49
50
Module(const string & name,const string & os,const string & architecture,const string & id)51 Module::Module(const string &name, const string &os,
52 const string &architecture, const string &id) :
53 name_(name),
54 os_(os),
55 architecture_(architecture),
56 id_(id),
57 load_address_(0) { }
58
~Module()59 Module::~Module() {
60 for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
61 delete it->second;
62 for (FunctionSet::iterator it = functions_.begin();
63 it != functions_.end(); ++it) {
64 delete *it;
65 }
66 for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin();
67 it != stack_frame_entries_.end(); ++it) {
68 delete *it;
69 }
70 for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it)
71 delete *it;
72 }
73
SetLoadAddress(Address address)74 void Module::SetLoadAddress(Address address) {
75 load_address_ = address;
76 }
77
AddFunction(Function * function)78 void Module::AddFunction(Function *function) {
79 // FUNC lines must not hold an empty name, so catch the problem early if
80 // callers try to add one.
81 assert(!function->name.empty());
82
83 // FUNCs are better than PUBLICs as they come with sizes, so remove an extern
84 // with the same address if present.
85 Extern ext(function->address);
86 ExternSet::iterator it_ext = externs_.find(&ext);
87 if (it_ext == externs_.end() &&
88 architecture_ == "arm" &&
89 (function->address & 0x1) == 0) {
90 // ARM THUMB functions have bit 0 set. ARM64 does not have THUMB.
91 Extern arm_thumb_ext(function->address | 0x1);
92 it_ext = externs_.find(&arm_thumb_ext);
93 }
94 if (it_ext != externs_.end()) {
95 delete *it_ext;
96 externs_.erase(it_ext);
97 }
98 #if _DEBUG
99 {
100 // There should be no other PUBLIC symbols that overlap with the function.
101 Extern debug_ext(function->address);
102 ExternSet::iterator it_debug = externs_.lower_bound(&ext);
103 assert(it_debug == externs_.end() ||
104 (*it_debug)->address >= function->address + function->size);
105 }
106 #endif
107
108 std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function);
109 if (!ret.second && (*ret.first != function)) {
110 // Free the duplicate that was not inserted because this Module
111 // now owns it.
112 delete function;
113 }
114 }
115
AddFunctions(vector<Function * >::iterator begin,vector<Function * >::iterator end)116 void Module::AddFunctions(vector<Function *>::iterator begin,
117 vector<Function *>::iterator end) {
118 for (vector<Function *>::iterator it = begin; it != end; ++it)
119 AddFunction(*it);
120 }
121
AddStackFrameEntry(StackFrameEntry * stack_frame_entry)122 void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) {
123 stack_frame_entries_.push_back(stack_frame_entry);
124 }
125
AddExtern(Extern * ext)126 void Module::AddExtern(Extern *ext) {
127 std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext);
128 if (!ret.second) {
129 // Free the duplicate that was not inserted because this Module
130 // now owns it.
131 delete ext;
132 }
133 }
134
GetFunctions(vector<Function * > * vec,vector<Function * >::iterator i)135 void Module::GetFunctions(vector<Function *> *vec,
136 vector<Function *>::iterator i) {
137 vec->insert(i, functions_.begin(), functions_.end());
138 }
139
GetExterns(vector<Extern * > * vec,vector<Extern * >::iterator i)140 void Module::GetExterns(vector<Extern *> *vec,
141 vector<Extern *>::iterator i) {
142 vec->insert(i, externs_.begin(), externs_.end());
143 }
144
FindFile(const string & name)145 Module::File *Module::FindFile(const string &name) {
146 // A tricky bit here. The key of each map entry needs to be a
147 // pointer to the entry's File's name string. This means that we
148 // can't do the initial lookup with any operation that would create
149 // an empty entry for us if the name isn't found (like, say,
150 // operator[] or insert do), because such a created entry's key will
151 // be a pointer the string passed as our argument. Since the key of
152 // a map's value type is const, we can't fix it up once we've
153 // created our file. lower_bound does the lookup without doing an
154 // insertion, and returns a good hint iterator to pass to insert.
155 // Our "destiny" is where we belong, whether we're there or not now.
156 FileByNameMap::iterator destiny = files_.lower_bound(&name);
157 if (destiny == files_.end()
158 || *destiny->first != name) { // Repeated string comparison, boo hoo.
159 File *file = new File(name);
160 file->source_id = -1;
161 destiny = files_.insert(destiny,
162 FileByNameMap::value_type(&file->name, file));
163 }
164 return destiny->second;
165 }
166
FindFile(const char * name)167 Module::File *Module::FindFile(const char *name) {
168 string name_string = name;
169 return FindFile(name_string);
170 }
171
FindExistingFile(const string & name)172 Module::File *Module::FindExistingFile(const string &name) {
173 FileByNameMap::iterator it = files_.find(&name);
174 return (it == files_.end()) ? NULL : it->second;
175 }
176
GetFiles(vector<File * > * vec)177 void Module::GetFiles(vector<File *> *vec) {
178 vec->clear();
179 for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
180 vec->push_back(it->second);
181 }
182
GetStackFrameEntries(vector<StackFrameEntry * > * vec) const183 void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) const {
184 *vec = stack_frame_entries_;
185 }
186
AssignSourceIds()187 void Module::AssignSourceIds() {
188 // First, give every source file an id of -1.
189 for (FileByNameMap::iterator file_it = files_.begin();
190 file_it != files_.end(); ++file_it) {
191 file_it->second->source_id = -1;
192 }
193
194 // Next, mark all files actually cited by our functions' line number
195 // info, by setting each one's source id to zero.
196 for (FunctionSet::const_iterator func_it = functions_.begin();
197 func_it != functions_.end(); ++func_it) {
198 Function *func = *func_it;
199 for (vector<Line>::iterator line_it = func->lines.begin();
200 line_it != func->lines.end(); ++line_it)
201 line_it->file->source_id = 0;
202 }
203
204 // Finally, assign source ids to those files that have been marked.
205 // We could have just assigned source id numbers while traversing
206 // the line numbers, but doing it this way numbers the files in
207 // lexicographical order by name, which is neat.
208 int next_source_id = 0;
209 for (FileByNameMap::iterator file_it = files_.begin();
210 file_it != files_.end(); ++file_it) {
211 if (!file_it->second->source_id)
212 file_it->second->source_id = next_source_id++;
213 }
214 }
215
ReportError()216 bool Module::ReportError() {
217 fprintf(stderr, "error writing symbol file: %s\n",
218 strerror(errno));
219 return false;
220 }
221
WriteRuleMap(const RuleMap & rule_map,std::ostream & stream)222 bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
223 for (RuleMap::const_iterator it = rule_map.begin();
224 it != rule_map.end(); ++it) {
225 if (it != rule_map.begin())
226 stream << ' ';
227 stream << it->first << ": " << it->second;
228 }
229 return stream.good();
230 }
231
Write(std::ostream & stream,SymbolData symbol_data)232 bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
233 stream << "MODULE " << os_ << " " << architecture_ << " "
234 << id_ << " " << name_ << endl;
235 if (!stream.good())
236 return ReportError();
237
238 if (symbol_data != ONLY_CFI) {
239 AssignSourceIds();
240
241 // Write out files.
242 for (FileByNameMap::iterator file_it = files_.begin();
243 file_it != files_.end(); ++file_it) {
244 File *file = file_it->second;
245 if (file->source_id >= 0) {
246 stream << "FILE " << file->source_id << " " << file->name << endl;
247 if (!stream.good())
248 return ReportError();
249 }
250 }
251
252 // Write out functions and their lines.
253 for (FunctionSet::const_iterator func_it = functions_.begin();
254 func_it != functions_.end(); ++func_it) {
255 Function *func = *func_it;
256 stream << "FUNC " << hex
257 << (func->address - load_address_) << " "
258 << func->size << " "
259 << func->parameter_size << " "
260 << func->name << dec << endl;
261 if (!stream.good())
262 return ReportError();
263
264 for (vector<Line>::iterator line_it = func->lines.begin();
265 line_it != func->lines.end(); ++line_it) {
266 stream << hex
267 << (line_it->address - load_address_) << " "
268 << line_it->size << " "
269 << dec
270 << line_it->number << " "
271 << line_it->file->source_id << endl;
272 if (!stream.good())
273 return ReportError();
274 }
275 }
276
277 // Write out 'PUBLIC' records.
278 for (ExternSet::const_iterator extern_it = externs_.begin();
279 extern_it != externs_.end(); ++extern_it) {
280 Extern *ext = *extern_it;
281 stream << "PUBLIC " << hex
282 << (ext->address - load_address_) << " 0 "
283 << ext->name << dec << endl;
284 }
285 }
286
287 if (symbol_data != NO_CFI) {
288 // Write out 'STACK CFI INIT' and 'STACK CFI' records.
289 vector<StackFrameEntry *>::const_iterator frame_it;
290 for (frame_it = stack_frame_entries_.begin();
291 frame_it != stack_frame_entries_.end(); ++frame_it) {
292 StackFrameEntry *entry = *frame_it;
293 stream << "STACK CFI INIT " << hex
294 << (entry->address - load_address_) << " "
295 << entry->size << " " << dec;
296 if (!stream.good()
297 || !WriteRuleMap(entry->initial_rules, stream))
298 return ReportError();
299
300 stream << endl;
301
302 // Write out this entry's delta rules as 'STACK CFI' records.
303 for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin();
304 delta_it != entry->rule_changes.end(); ++delta_it) {
305 stream << "STACK CFI " << hex
306 << (delta_it->first - load_address_) << " " << dec;
307 if (!stream.good()
308 || !WriteRuleMap(delta_it->second, stream))
309 return ReportError();
310
311 stream << endl;
312 }
313 }
314 }
315
316 return true;
317 }
318
319 } // namespace google_breakpad
320