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 (at) mozilla.com> <jimb (at) 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 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 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 74 void Module::SetLoadAddress(Address address) { 75 load_address_ = address; 76 } 77 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 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 122 void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) { 123 stack_frame_entries_.push_back(stack_frame_entry); 124 } 125 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 135 void Module::GetFunctions(vector<Function *> *vec, 136 vector<Function *>::iterator i) { 137 vec->insert(i, functions_.begin(), functions_.end()); 138 } 139 140 void Module::GetExterns(vector<Extern *> *vec, 141 vector<Extern *>::iterator i) { 142 vec->insert(i, externs_.begin(), externs_.end()); 143 } 144 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 167 Module::File *Module::FindFile(const char *name) { 168 string name_string = name; 169 return FindFile(name_string); 170 } 171 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 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 183 void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) const { 184 *vec = stack_frame_entries_; 185 } 186 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 216 bool Module::ReportError() { 217 fprintf(stderr, "error writing symbol file: %s\n", 218 strerror(errno)); 219 return false; 220 } 221 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 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