1 // Copyright (c) 2011 Google Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
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
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.
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.
30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
32 // module.cc: Implement google_breakpad::Module. See module.h.
34 #include "common/module.h"
44 namespace google_breakpad {
51 Module::Module(const string &name, const string &os,
52 const string &architecture, const string &id) :
55 architecture_(architecture),
60 for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
62 for (FunctionSet::iterator it = functions_.begin();
63 it != functions_.end(); ++it) {
66 for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin();
67 it != stack_frame_entries_.end(); ++it) {
70 for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it)
74 void Module::SetLoadAddress(Address address) {
75 load_address_ = address;
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 std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function);
84 // Free the duplicate that was not inserted because this Module
90 void Module::AddFunctions(vector<Function *>::iterator begin,
91 vector<Function *>::iterator end) {
92 for (vector<Function *>::iterator it = begin; it != end; ++it)
96 void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) {
97 stack_frame_entries_.push_back(stack_frame_entry);
100 void Module::AddExtern(Extern *ext) {
101 std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext);
103 // Free the duplicate that was not inserted because this Module
109 void Module::GetFunctions(vector<Function *> *vec,
110 vector<Function *>::iterator i) {
111 vec->insert(i, functions_.begin(), functions_.end());
114 void Module::GetExterns(vector<Extern *> *vec,
115 vector<Extern *>::iterator i) {
116 vec->insert(i, externs_.begin(), externs_.end());
119 Module::File *Module::FindFile(const string &name) {
120 // A tricky bit here. The key of each map entry needs to be a
121 // pointer to the entry's File's name string. This means that we
122 // can't do the initial lookup with any operation that would create
123 // an empty entry for us if the name isn't found (like, say,
124 // operator[] or insert do), because such a created entry's key will
125 // be a pointer the string passed as our argument. Since the key of
126 // a map's value type is const, we can't fix it up once we've
127 // created our file. lower_bound does the lookup without doing an
128 // insertion, and returns a good hint iterator to pass to insert.
129 // Our "destiny" is where we belong, whether we're there or not now.
130 FileByNameMap::iterator destiny = files_.lower_bound(&name);
131 if (destiny == files_.end()
132 || *destiny->first != name) { // Repeated string comparison, boo hoo.
133 File *file = new File;
135 file->source_id = -1;
136 destiny = files_.insert(destiny,
137 FileByNameMap::value_type(&file->name, file));
139 return destiny->second;
142 Module::File *Module::FindFile(const char *name) {
143 string name_string = name;
144 return FindFile(name_string);
147 Module::File *Module::FindExistingFile(const string &name) {
148 FileByNameMap::iterator it = files_.find(&name);
149 return (it == files_.end()) ? NULL : it->second;
152 void Module::GetFiles(vector<File *> *vec) {
154 for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
155 vec->push_back(it->second);
158 void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) const {
159 *vec = stack_frame_entries_;
162 void Module::AssignSourceIds() {
163 // First, give every source file an id of -1.
164 for (FileByNameMap::iterator file_it = files_.begin();
165 file_it != files_.end(); ++file_it) {
166 file_it->second->source_id = -1;
169 // Next, mark all files actually cited by our functions' line number
170 // info, by setting each one's source id to zero.
171 for (FunctionSet::const_iterator func_it = functions_.begin();
172 func_it != functions_.end(); ++func_it) {
173 Function *func = *func_it;
174 for (vector<Line>::iterator line_it = func->lines.begin();
175 line_it != func->lines.end(); ++line_it)
176 line_it->file->source_id = 0;
179 // Finally, assign source ids to those files that have been marked.
180 // We could have just assigned source id numbers while traversing
181 // the line numbers, but doing it this way numbers the files in
182 // lexicographical order by name, which is neat.
183 int next_source_id = 0;
184 for (FileByNameMap::iterator file_it = files_.begin();
185 file_it != files_.end(); ++file_it) {
186 if (!file_it->second->source_id)
187 file_it->second->source_id = next_source_id++;
191 bool Module::ReportError() {
192 fprintf(stderr, "error writing symbol file: %s\n",
197 bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
198 for (RuleMap::const_iterator it = rule_map.begin();
199 it != rule_map.end(); ++it) {
200 if (it != rule_map.begin())
202 stream << it->first << ": " << it->second;
204 return stream.good();
207 bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
208 stream << "MODULE " << os_ << " " << architecture_ << " "
209 << id_ << " " << name_ << endl;
211 return ReportError();
213 if (symbol_data != ONLY_CFI) {
217 for (FileByNameMap::iterator file_it = files_.begin();
218 file_it != files_.end(); ++file_it) {
219 File *file = file_it->second;
220 if (file->source_id >= 0) {
221 stream << "FILE " << file->source_id << " " << file->name << endl;
223 return ReportError();
227 // Write out functions and their lines.
228 for (FunctionSet::const_iterator func_it = functions_.begin();
229 func_it != functions_.end(); ++func_it) {
230 Function *func = *func_it;
231 stream << "FUNC " << hex
232 << (func->address - load_address_) << " "
234 << func->parameter_size << " "
235 << func->name << dec << endl;
237 return ReportError();
239 for (vector<Line>::iterator line_it = func->lines.begin();
240 line_it != func->lines.end(); ++line_it) {
242 << (line_it->address - load_address_) << " "
243 << line_it->size << " "
245 << line_it->number << " "
246 << line_it->file->source_id << endl;
248 return ReportError();
252 // Write out 'PUBLIC' records.
253 for (ExternSet::const_iterator extern_it = externs_.begin();
254 extern_it != externs_.end(); ++extern_it) {
255 Extern *ext = *extern_it;
256 stream << "PUBLIC " << hex
257 << (ext->address - load_address_) << " 0 "
258 << ext->name << dec << endl;
262 if (symbol_data != NO_CFI) {
263 // Write out 'STACK CFI INIT' and 'STACK CFI' records.
264 vector<StackFrameEntry *>::const_iterator frame_it;
265 for (frame_it = stack_frame_entries_.begin();
266 frame_it != stack_frame_entries_.end(); ++frame_it) {
267 StackFrameEntry *entry = *frame_it;
268 stream << "STACK CFI INIT " << hex
269 << (entry->address - load_address_) << " "
270 << entry->size << " " << dec;
272 || !WriteRuleMap(entry->initial_rules, stream))
273 return ReportError();
277 // Write out this entry's delta rules as 'STACK CFI' records.
278 for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin();
279 delta_it != entry->rule_changes.end(); ++delta_it) {
280 stream << "STACK CFI " << hex
281 << (delta_it->first - load_address_) << " " << dec;
283 || !WriteRuleMap(delta_it->second, stream))
284 return ReportError();
294 } // namespace google_breakpad