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