1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/module.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,389 @@ 1.4 +// Copyright (c) 2011 Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 + 1.33 +// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> 1.34 + 1.35 +// module.cc: Implement google_breakpad::Module. See module.h. 1.36 + 1.37 +#include "common/module.h" 1.38 + 1.39 +#include <assert.h> 1.40 +#include <errno.h> 1.41 +#include <stdio.h> 1.42 +#include <string.h> 1.43 + 1.44 +#include <algorithm> 1.45 +#include <iostream> 1.46 +#include <utility> 1.47 + 1.48 +namespace google_breakpad { 1.49 + 1.50 +using std::dec; 1.51 +using std::endl; 1.52 +using std::hex; 1.53 + 1.54 + 1.55 +Module::Module(const string &name, const string &os, 1.56 + const string &architecture, const string &id) : 1.57 + name_(name), 1.58 + os_(os), 1.59 + architecture_(architecture), 1.60 + id_(id), 1.61 + load_address_(0) { } 1.62 + 1.63 +Module::~Module() { 1.64 + for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) 1.65 + delete it->second; 1.66 + for (FunctionSet::iterator it = functions_.begin(); 1.67 + it != functions_.end(); ++it) { 1.68 + delete *it; 1.69 + } 1.70 + for (StackFrameEntrySet::iterator it = stack_frame_entries_.begin(); 1.71 + it != stack_frame_entries_.end(); ++it) { 1.72 + delete *it; 1.73 + } 1.74 + for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it) 1.75 + delete *it; 1.76 +} 1.77 + 1.78 +void Module::SetLoadAddress(Address address) { 1.79 + load_address_ = address; 1.80 +} 1.81 + 1.82 +void Module::AddFunction(Function *function) { 1.83 + // FUNC lines must not hold an empty name, so catch the problem early if 1.84 + // callers try to add one. 1.85 + assert(!function->name.empty()); 1.86 + std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function); 1.87 + if (!ret.second) { 1.88 + // Free the duplicate that was not inserted because this Module 1.89 + // now owns it. 1.90 + delete function; 1.91 + } 1.92 +} 1.93 + 1.94 +void Module::AddFunctions(vector<Function *>::iterator begin, 1.95 + vector<Function *>::iterator end) { 1.96 + for (vector<Function *>::iterator it = begin; it != end; ++it) 1.97 + AddFunction(*it); 1.98 +} 1.99 + 1.100 +void Module::AddStackFrameEntry(StackFrameEntry* stack_frame_entry) { 1.101 + std::pair<StackFrameEntrySet::iterator,bool> ret = 1.102 + stack_frame_entries_.insert(stack_frame_entry); 1.103 + if (!ret.second) { 1.104 + // Free the duplicate that was not inserted because this Module 1.105 + // now owns it. 1.106 + delete stack_frame_entry; 1.107 + } 1.108 +} 1.109 + 1.110 +void Module::AddExtern(Extern *ext) { 1.111 + std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext); 1.112 + if (!ret.second) { 1.113 + // Free the duplicate that was not inserted because this Module 1.114 + // now owns it. 1.115 + delete ext; 1.116 + } 1.117 +} 1.118 + 1.119 +void Module::GetFunctions(vector<Function *> *vec, 1.120 + vector<Function *>::iterator i) { 1.121 + vec->insert(i, functions_.begin(), functions_.end()); 1.122 +} 1.123 + 1.124 +template<typename T> 1.125 +bool EntryContainsAddress(T entry, Module::Address address) { 1.126 + return entry->address <= address && address < entry->address + entry->size; 1.127 +} 1.128 + 1.129 +Module::Function* Module::FindFunctionByAddress(Address address) { 1.130 + Function search; 1.131 + search.address = address; 1.132 + // Ensure that name always sorts higher than the function name, 1.133 + // so that upper_bound always returns the function just after 1.134 + // the function containing this address. 1.135 + search.name = "\xFF"; 1.136 + FunctionSet::iterator it = functions_.upper_bound(&search); 1.137 + if (it == functions_.begin()) 1.138 + return NULL; 1.139 + 1.140 + it--; 1.141 + 1.142 + if (EntryContainsAddress(*it, address)) 1.143 + return *it; 1.144 + 1.145 + return NULL; 1.146 +} 1.147 + 1.148 +void Module::GetExterns(vector<Extern *> *vec, 1.149 + vector<Extern *>::iterator i) { 1.150 + vec->insert(i, externs_.begin(), externs_.end()); 1.151 +} 1.152 + 1.153 +Module::Extern* Module::FindExternByAddress(Address address) { 1.154 + Extern search; 1.155 + search.address = address; 1.156 + ExternSet::iterator it = externs_.upper_bound(&search); 1.157 + 1.158 + if (it == externs_.begin()) 1.159 + return NULL; 1.160 + 1.161 + it--; 1.162 + if ((*it)->address > address) 1.163 + return NULL; 1.164 + 1.165 + return *it; 1.166 +} 1.167 + 1.168 +Module::File *Module::FindFile(const string &name) { 1.169 + // A tricky bit here. The key of each map entry needs to be a 1.170 + // pointer to the entry's File's name string. This means that we 1.171 + // can't do the initial lookup with any operation that would create 1.172 + // an empty entry for us if the name isn't found (like, say, 1.173 + // operator[] or insert do), because such a created entry's key will 1.174 + // be a pointer the string passed as our argument. Since the key of 1.175 + // a map's value type is const, we can't fix it up once we've 1.176 + // created our file. lower_bound does the lookup without doing an 1.177 + // insertion, and returns a good hint iterator to pass to insert. 1.178 + // Our "destiny" is where we belong, whether we're there or not now. 1.179 + FileByNameMap::iterator destiny = files_.lower_bound(&name); 1.180 + if (destiny == files_.end() 1.181 + || *destiny->first != name) { // Repeated string comparison, boo hoo. 1.182 + File *file = new File; 1.183 + file->name = name; 1.184 + file->source_id = -1; 1.185 + destiny = files_.insert(destiny, 1.186 + FileByNameMap::value_type(&file->name, file)); 1.187 + } 1.188 + return destiny->second; 1.189 +} 1.190 + 1.191 +Module::File *Module::FindFile(const char *name) { 1.192 + string name_string = name; 1.193 + return FindFile(name_string); 1.194 +} 1.195 + 1.196 +Module::File *Module::FindExistingFile(const string &name) { 1.197 + FileByNameMap::iterator it = files_.find(&name); 1.198 + return (it == files_.end()) ? NULL : it->second; 1.199 +} 1.200 + 1.201 +void Module::GetFiles(vector<File *> *vec) { 1.202 + vec->clear(); 1.203 + for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) 1.204 + vec->push_back(it->second); 1.205 +} 1.206 + 1.207 +void Module::GetStackFrameEntries(vector<StackFrameEntry *>* vec) { 1.208 + vec->clear(); 1.209 + vec->insert(vec->begin(), stack_frame_entries_.begin(), 1.210 + stack_frame_entries_.end()); 1.211 +} 1.212 + 1.213 +Module::StackFrameEntry* Module::FindStackFrameEntryByAddress(Address address) { 1.214 + StackFrameEntry search; 1.215 + search.address = address; 1.216 + StackFrameEntrySet::iterator it = stack_frame_entries_.upper_bound(&search); 1.217 + 1.218 + if (it == stack_frame_entries_.begin()) 1.219 + return NULL; 1.220 + 1.221 + it--; 1.222 + if (EntryContainsAddress(*it, address)) 1.223 + return *it; 1.224 + 1.225 + return NULL; 1.226 +} 1.227 + 1.228 +void Module::AssignSourceIds() { 1.229 + // First, give every source file an id of -1. 1.230 + for (FileByNameMap::iterator file_it = files_.begin(); 1.231 + file_it != files_.end(); ++file_it) { 1.232 + file_it->second->source_id = -1; 1.233 + } 1.234 + 1.235 + // Next, mark all files actually cited by our functions' line number 1.236 + // info, by setting each one's source id to zero. 1.237 + for (FunctionSet::const_iterator func_it = functions_.begin(); 1.238 + func_it != functions_.end(); ++func_it) { 1.239 + Function *func = *func_it; 1.240 + for (vector<Line>::iterator line_it = func->lines.begin(); 1.241 + line_it != func->lines.end(); ++line_it) 1.242 + line_it->file->source_id = 0; 1.243 + } 1.244 + 1.245 + // Finally, assign source ids to those files that have been marked. 1.246 + // We could have just assigned source id numbers while traversing 1.247 + // the line numbers, but doing it this way numbers the files in 1.248 + // lexicographical order by name, which is neat. 1.249 + int next_source_id = 0; 1.250 + for (FileByNameMap::iterator file_it = files_.begin(); 1.251 + file_it != files_.end(); ++file_it) { 1.252 + if (!file_it->second->source_id) 1.253 + file_it->second->source_id = next_source_id++; 1.254 + } 1.255 +} 1.256 + 1.257 +bool Module::ReportError() { 1.258 + fprintf(stderr, "error writing symbol file: %s\n", 1.259 + strerror(errno)); 1.260 + return false; 1.261 +} 1.262 + 1.263 +std::ostream& operator<<(std::ostream& stream, const Module::Expr& expr) { 1.264 + assert(!expr.isExprInvalid()); 1.265 + switch (expr.how_) { 1.266 + case Module::kExprSimple: 1.267 + stream << FromUniqueString(expr.ident_) << " " << expr.offset_ << " +"; 1.268 + break; 1.269 + case Module::kExprSimpleMem: 1.270 + stream << FromUniqueString(expr.ident_) << " " << expr.offset_ << " + ^"; 1.271 + break; 1.272 + case Module::kExprPostfix: 1.273 + stream << expr.postfix_; break; 1.274 + case Module::kExprInvalid: 1.275 + default: 1.276 + break; 1.277 + } 1.278 + return stream; 1.279 +} 1.280 + 1.281 +bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) { 1.282 + // Visit the register rules in alphabetical order. Because 1.283 + // rule_map has the elements in some arbitrary order, 1.284 + // get the names out into a vector, sort them, and visit in 1.285 + // sorted order. 1.286 + std::vector<const UniqueString*> rr_names; 1.287 + for (RuleMap::const_iterator it = rule_map.begin(); 1.288 + it != rule_map.end(); ++it) { 1.289 + rr_names.push_back(it->first); 1.290 + } 1.291 + 1.292 + std::sort(rr_names.begin(), rr_names.end(), LessThan_UniqueString); 1.293 + 1.294 + // Now visit the register rules in alphabetical order. 1.295 + for (std::vector<const UniqueString*>::const_iterator name = rr_names.begin(); 1.296 + name != rr_names.end(); 1.297 + ++name) { 1.298 + if (name != rr_names.begin()) 1.299 + stream << " "; 1.300 + stream << FromUniqueString(*name) << ": " << rule_map.find(*name)->second; 1.301 + } 1.302 + return stream.good(); 1.303 +} 1.304 + 1.305 +bool Module::Write(std::ostream &stream, SymbolData symbol_data) { 1.306 + stream << "MODULE " << os_ << " " << architecture_ << " " 1.307 + << id_ << " " << name_ << endl; 1.308 + if (!stream.good()) 1.309 + return ReportError(); 1.310 + 1.311 + if (symbol_data != ONLY_CFI) { 1.312 + AssignSourceIds(); 1.313 + 1.314 + // Write out files. 1.315 + for (FileByNameMap::iterator file_it = files_.begin(); 1.316 + file_it != files_.end(); ++file_it) { 1.317 + File *file = file_it->second; 1.318 + if (file->source_id >= 0) { 1.319 + stream << "FILE " << file->source_id << " " << file->name << endl; 1.320 + if (!stream.good()) 1.321 + return ReportError(); 1.322 + } 1.323 + } 1.324 + 1.325 + // Write out functions and their lines. 1.326 + for (FunctionSet::const_iterator func_it = functions_.begin(); 1.327 + func_it != functions_.end(); ++func_it) { 1.328 + Function *func = *func_it; 1.329 + stream << "FUNC " << hex 1.330 + << (func->address - load_address_) << " " 1.331 + << func->size << " " 1.332 + << func->parameter_size << " " 1.333 + << func->name << dec << endl; 1.334 + if (!stream.good()) 1.335 + return ReportError(); 1.336 + 1.337 + for (vector<Line>::iterator line_it = func->lines.begin(); 1.338 + line_it != func->lines.end(); ++line_it) { 1.339 + stream << hex 1.340 + << (line_it->address - load_address_) << " " 1.341 + << line_it->size << " " 1.342 + << dec 1.343 + << line_it->number << " " 1.344 + << line_it->file->source_id << endl; 1.345 + if (!stream.good()) 1.346 + return ReportError(); 1.347 + } 1.348 + } 1.349 + 1.350 + // Write out 'PUBLIC' records. 1.351 + for (ExternSet::const_iterator extern_it = externs_.begin(); 1.352 + extern_it != externs_.end(); ++extern_it) { 1.353 + Extern *ext = *extern_it; 1.354 + stream << "PUBLIC " << hex 1.355 + << (ext->address - load_address_) << " 0 " 1.356 + << ext->name << dec << endl; 1.357 + } 1.358 + } 1.359 + 1.360 + if (symbol_data != NO_CFI) { 1.361 + // Write out 'STACK CFI INIT' and 'STACK CFI' records. 1.362 + StackFrameEntrySet::const_iterator frame_it; 1.363 + for (frame_it = stack_frame_entries_.begin(); 1.364 + frame_it != stack_frame_entries_.end(); ++frame_it) { 1.365 + StackFrameEntry *entry = *frame_it; 1.366 + stream << "STACK CFI INIT " << hex 1.367 + << (entry->address - load_address_) << " " 1.368 + << entry->size << " " << dec; 1.369 + if (!stream.good() 1.370 + || !WriteRuleMap(entry->initial_rules, stream)) 1.371 + return ReportError(); 1.372 + 1.373 + stream << endl; 1.374 + 1.375 + // Write out this entry's delta rules as 'STACK CFI' records. 1.376 + for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin(); 1.377 + delta_it != entry->rule_changes.end(); ++delta_it) { 1.378 + stream << "STACK CFI " << hex 1.379 + << (delta_it->first - load_address_) << " " << dec; 1.380 + if (!stream.good() 1.381 + || !WriteRuleMap(delta_it->second, stream)) 1.382 + return ReportError(); 1.383 + 1.384 + stream << endl; 1.385 + } 1.386 + } 1.387 + } 1.388 + 1.389 + return true; 1.390 +} 1.391 + 1.392 +} // namespace google_breakpad