toolkit/crashreporter/google-breakpad/src/common/module.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2011 Google Inc.
michael@0 2 // All rights reserved.
michael@0 3 //
michael@0 4 // Redistribution and use in source and binary forms, with or without
michael@0 5 // modification, are permitted provided that the following conditions are
michael@0 6 // met:
michael@0 7 //
michael@0 8 // * Redistributions of source code must retain the above copyright
michael@0 9 // notice, this list of conditions and the following disclaimer.
michael@0 10 // * Redistributions in binary form must reproduce the above
michael@0 11 // copyright notice, this list of conditions and the following disclaimer
michael@0 12 // in the documentation and/or other materials provided with the
michael@0 13 // distribution.
michael@0 14 // * Neither the name of Google Inc. nor the names of its
michael@0 15 // contributors may be used to endorse or promote products derived from
michael@0 16 // this software without specific prior written permission.
michael@0 17 //
michael@0 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 29
michael@0 30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
michael@0 31
michael@0 32 // module.cc: Implement google_breakpad::Module. See module.h.
michael@0 33
michael@0 34 #include "common/module.h"
michael@0 35
michael@0 36 #include <assert.h>
michael@0 37 #include <errno.h>
michael@0 38 #include <stdio.h>
michael@0 39 #include <string.h>
michael@0 40
michael@0 41 #include <algorithm>
michael@0 42 #include <iostream>
michael@0 43 #include <utility>
michael@0 44
michael@0 45 namespace google_breakpad {
michael@0 46
michael@0 47 using std::dec;
michael@0 48 using std::endl;
michael@0 49 using std::hex;
michael@0 50
michael@0 51
michael@0 52 Module::Module(const string &name, const string &os,
michael@0 53 const string &architecture, const string &id) :
michael@0 54 name_(name),
michael@0 55 os_(os),
michael@0 56 architecture_(architecture),
michael@0 57 id_(id),
michael@0 58 load_address_(0) { }
michael@0 59
michael@0 60 Module::~Module() {
michael@0 61 for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
michael@0 62 delete it->second;
michael@0 63 for (FunctionSet::iterator it = functions_.begin();
michael@0 64 it != functions_.end(); ++it) {
michael@0 65 delete *it;
michael@0 66 }
michael@0 67 for (StackFrameEntrySet::iterator it = stack_frame_entries_.begin();
michael@0 68 it != stack_frame_entries_.end(); ++it) {
michael@0 69 delete *it;
michael@0 70 }
michael@0 71 for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it)
michael@0 72 delete *it;
michael@0 73 }
michael@0 74
michael@0 75 void Module::SetLoadAddress(Address address) {
michael@0 76 load_address_ = address;
michael@0 77 }
michael@0 78
michael@0 79 void Module::AddFunction(Function *function) {
michael@0 80 // FUNC lines must not hold an empty name, so catch the problem early if
michael@0 81 // callers try to add one.
michael@0 82 assert(!function->name.empty());
michael@0 83 std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function);
michael@0 84 if (!ret.second) {
michael@0 85 // Free the duplicate that was not inserted because this Module
michael@0 86 // now owns it.
michael@0 87 delete function;
michael@0 88 }
michael@0 89 }
michael@0 90
michael@0 91 void Module::AddFunctions(vector<Function *>::iterator begin,
michael@0 92 vector<Function *>::iterator end) {
michael@0 93 for (vector<Function *>::iterator it = begin; it != end; ++it)
michael@0 94 AddFunction(*it);
michael@0 95 }
michael@0 96
michael@0 97 void Module::AddStackFrameEntry(StackFrameEntry* stack_frame_entry) {
michael@0 98 std::pair<StackFrameEntrySet::iterator,bool> ret =
michael@0 99 stack_frame_entries_.insert(stack_frame_entry);
michael@0 100 if (!ret.second) {
michael@0 101 // Free the duplicate that was not inserted because this Module
michael@0 102 // now owns it.
michael@0 103 delete stack_frame_entry;
michael@0 104 }
michael@0 105 }
michael@0 106
michael@0 107 void Module::AddExtern(Extern *ext) {
michael@0 108 std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext);
michael@0 109 if (!ret.second) {
michael@0 110 // Free the duplicate that was not inserted because this Module
michael@0 111 // now owns it.
michael@0 112 delete ext;
michael@0 113 }
michael@0 114 }
michael@0 115
michael@0 116 void Module::GetFunctions(vector<Function *> *vec,
michael@0 117 vector<Function *>::iterator i) {
michael@0 118 vec->insert(i, functions_.begin(), functions_.end());
michael@0 119 }
michael@0 120
michael@0 121 template<typename T>
michael@0 122 bool EntryContainsAddress(T entry, Module::Address address) {
michael@0 123 return entry->address <= address && address < entry->address + entry->size;
michael@0 124 }
michael@0 125
michael@0 126 Module::Function* Module::FindFunctionByAddress(Address address) {
michael@0 127 Function search;
michael@0 128 search.address = address;
michael@0 129 // Ensure that name always sorts higher than the function name,
michael@0 130 // so that upper_bound always returns the function just after
michael@0 131 // the function containing this address.
michael@0 132 search.name = "\xFF";
michael@0 133 FunctionSet::iterator it = functions_.upper_bound(&search);
michael@0 134 if (it == functions_.begin())
michael@0 135 return NULL;
michael@0 136
michael@0 137 it--;
michael@0 138
michael@0 139 if (EntryContainsAddress(*it, address))
michael@0 140 return *it;
michael@0 141
michael@0 142 return NULL;
michael@0 143 }
michael@0 144
michael@0 145 void Module::GetExterns(vector<Extern *> *vec,
michael@0 146 vector<Extern *>::iterator i) {
michael@0 147 vec->insert(i, externs_.begin(), externs_.end());
michael@0 148 }
michael@0 149
michael@0 150 Module::Extern* Module::FindExternByAddress(Address address) {
michael@0 151 Extern search;
michael@0 152 search.address = address;
michael@0 153 ExternSet::iterator it = externs_.upper_bound(&search);
michael@0 154
michael@0 155 if (it == externs_.begin())
michael@0 156 return NULL;
michael@0 157
michael@0 158 it--;
michael@0 159 if ((*it)->address > address)
michael@0 160 return NULL;
michael@0 161
michael@0 162 return *it;
michael@0 163 }
michael@0 164
michael@0 165 Module::File *Module::FindFile(const string &name) {
michael@0 166 // A tricky bit here. The key of each map entry needs to be a
michael@0 167 // pointer to the entry's File's name string. This means that we
michael@0 168 // can't do the initial lookup with any operation that would create
michael@0 169 // an empty entry for us if the name isn't found (like, say,
michael@0 170 // operator[] or insert do), because such a created entry's key will
michael@0 171 // be a pointer the string passed as our argument. Since the key of
michael@0 172 // a map's value type is const, we can't fix it up once we've
michael@0 173 // created our file. lower_bound does the lookup without doing an
michael@0 174 // insertion, and returns a good hint iterator to pass to insert.
michael@0 175 // Our "destiny" is where we belong, whether we're there or not now.
michael@0 176 FileByNameMap::iterator destiny = files_.lower_bound(&name);
michael@0 177 if (destiny == files_.end()
michael@0 178 || *destiny->first != name) { // Repeated string comparison, boo hoo.
michael@0 179 File *file = new File;
michael@0 180 file->name = name;
michael@0 181 file->source_id = -1;
michael@0 182 destiny = files_.insert(destiny,
michael@0 183 FileByNameMap::value_type(&file->name, file));
michael@0 184 }
michael@0 185 return destiny->second;
michael@0 186 }
michael@0 187
michael@0 188 Module::File *Module::FindFile(const char *name) {
michael@0 189 string name_string = name;
michael@0 190 return FindFile(name_string);
michael@0 191 }
michael@0 192
michael@0 193 Module::File *Module::FindExistingFile(const string &name) {
michael@0 194 FileByNameMap::iterator it = files_.find(&name);
michael@0 195 return (it == files_.end()) ? NULL : it->second;
michael@0 196 }
michael@0 197
michael@0 198 void Module::GetFiles(vector<File *> *vec) {
michael@0 199 vec->clear();
michael@0 200 for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
michael@0 201 vec->push_back(it->second);
michael@0 202 }
michael@0 203
michael@0 204 void Module::GetStackFrameEntries(vector<StackFrameEntry *>* vec) {
michael@0 205 vec->clear();
michael@0 206 vec->insert(vec->begin(), stack_frame_entries_.begin(),
michael@0 207 stack_frame_entries_.end());
michael@0 208 }
michael@0 209
michael@0 210 Module::StackFrameEntry* Module::FindStackFrameEntryByAddress(Address address) {
michael@0 211 StackFrameEntry search;
michael@0 212 search.address = address;
michael@0 213 StackFrameEntrySet::iterator it = stack_frame_entries_.upper_bound(&search);
michael@0 214
michael@0 215 if (it == stack_frame_entries_.begin())
michael@0 216 return NULL;
michael@0 217
michael@0 218 it--;
michael@0 219 if (EntryContainsAddress(*it, address))
michael@0 220 return *it;
michael@0 221
michael@0 222 return NULL;
michael@0 223 }
michael@0 224
michael@0 225 void Module::AssignSourceIds() {
michael@0 226 // First, give every source file an id of -1.
michael@0 227 for (FileByNameMap::iterator file_it = files_.begin();
michael@0 228 file_it != files_.end(); ++file_it) {
michael@0 229 file_it->second->source_id = -1;
michael@0 230 }
michael@0 231
michael@0 232 // Next, mark all files actually cited by our functions' line number
michael@0 233 // info, by setting each one's source id to zero.
michael@0 234 for (FunctionSet::const_iterator func_it = functions_.begin();
michael@0 235 func_it != functions_.end(); ++func_it) {
michael@0 236 Function *func = *func_it;
michael@0 237 for (vector<Line>::iterator line_it = func->lines.begin();
michael@0 238 line_it != func->lines.end(); ++line_it)
michael@0 239 line_it->file->source_id = 0;
michael@0 240 }
michael@0 241
michael@0 242 // Finally, assign source ids to those files that have been marked.
michael@0 243 // We could have just assigned source id numbers while traversing
michael@0 244 // the line numbers, but doing it this way numbers the files in
michael@0 245 // lexicographical order by name, which is neat.
michael@0 246 int next_source_id = 0;
michael@0 247 for (FileByNameMap::iterator file_it = files_.begin();
michael@0 248 file_it != files_.end(); ++file_it) {
michael@0 249 if (!file_it->second->source_id)
michael@0 250 file_it->second->source_id = next_source_id++;
michael@0 251 }
michael@0 252 }
michael@0 253
michael@0 254 bool Module::ReportError() {
michael@0 255 fprintf(stderr, "error writing symbol file: %s\n",
michael@0 256 strerror(errno));
michael@0 257 return false;
michael@0 258 }
michael@0 259
michael@0 260 std::ostream& operator<<(std::ostream& stream, const Module::Expr& expr) {
michael@0 261 assert(!expr.isExprInvalid());
michael@0 262 switch (expr.how_) {
michael@0 263 case Module::kExprSimple:
michael@0 264 stream << FromUniqueString(expr.ident_) << " " << expr.offset_ << " +";
michael@0 265 break;
michael@0 266 case Module::kExprSimpleMem:
michael@0 267 stream << FromUniqueString(expr.ident_) << " " << expr.offset_ << " + ^";
michael@0 268 break;
michael@0 269 case Module::kExprPostfix:
michael@0 270 stream << expr.postfix_; break;
michael@0 271 case Module::kExprInvalid:
michael@0 272 default:
michael@0 273 break;
michael@0 274 }
michael@0 275 return stream;
michael@0 276 }
michael@0 277
michael@0 278 bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
michael@0 279 // Visit the register rules in alphabetical order. Because
michael@0 280 // rule_map has the elements in some arbitrary order,
michael@0 281 // get the names out into a vector, sort them, and visit in
michael@0 282 // sorted order.
michael@0 283 std::vector<const UniqueString*> rr_names;
michael@0 284 for (RuleMap::const_iterator it = rule_map.begin();
michael@0 285 it != rule_map.end(); ++it) {
michael@0 286 rr_names.push_back(it->first);
michael@0 287 }
michael@0 288
michael@0 289 std::sort(rr_names.begin(), rr_names.end(), LessThan_UniqueString);
michael@0 290
michael@0 291 // Now visit the register rules in alphabetical order.
michael@0 292 for (std::vector<const UniqueString*>::const_iterator name = rr_names.begin();
michael@0 293 name != rr_names.end();
michael@0 294 ++name) {
michael@0 295 if (name != rr_names.begin())
michael@0 296 stream << " ";
michael@0 297 stream << FromUniqueString(*name) << ": " << rule_map.find(*name)->second;
michael@0 298 }
michael@0 299 return stream.good();
michael@0 300 }
michael@0 301
michael@0 302 bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
michael@0 303 stream << "MODULE " << os_ << " " << architecture_ << " "
michael@0 304 << id_ << " " << name_ << endl;
michael@0 305 if (!stream.good())
michael@0 306 return ReportError();
michael@0 307
michael@0 308 if (symbol_data != ONLY_CFI) {
michael@0 309 AssignSourceIds();
michael@0 310
michael@0 311 // Write out files.
michael@0 312 for (FileByNameMap::iterator file_it = files_.begin();
michael@0 313 file_it != files_.end(); ++file_it) {
michael@0 314 File *file = file_it->second;
michael@0 315 if (file->source_id >= 0) {
michael@0 316 stream << "FILE " << file->source_id << " " << file->name << endl;
michael@0 317 if (!stream.good())
michael@0 318 return ReportError();
michael@0 319 }
michael@0 320 }
michael@0 321
michael@0 322 // Write out functions and their lines.
michael@0 323 for (FunctionSet::const_iterator func_it = functions_.begin();
michael@0 324 func_it != functions_.end(); ++func_it) {
michael@0 325 Function *func = *func_it;
michael@0 326 stream << "FUNC " << hex
michael@0 327 << (func->address - load_address_) << " "
michael@0 328 << func->size << " "
michael@0 329 << func->parameter_size << " "
michael@0 330 << func->name << dec << endl;
michael@0 331 if (!stream.good())
michael@0 332 return ReportError();
michael@0 333
michael@0 334 for (vector<Line>::iterator line_it = func->lines.begin();
michael@0 335 line_it != func->lines.end(); ++line_it) {
michael@0 336 stream << hex
michael@0 337 << (line_it->address - load_address_) << " "
michael@0 338 << line_it->size << " "
michael@0 339 << dec
michael@0 340 << line_it->number << " "
michael@0 341 << line_it->file->source_id << endl;
michael@0 342 if (!stream.good())
michael@0 343 return ReportError();
michael@0 344 }
michael@0 345 }
michael@0 346
michael@0 347 // Write out 'PUBLIC' records.
michael@0 348 for (ExternSet::const_iterator extern_it = externs_.begin();
michael@0 349 extern_it != externs_.end(); ++extern_it) {
michael@0 350 Extern *ext = *extern_it;
michael@0 351 stream << "PUBLIC " << hex
michael@0 352 << (ext->address - load_address_) << " 0 "
michael@0 353 << ext->name << dec << endl;
michael@0 354 }
michael@0 355 }
michael@0 356
michael@0 357 if (symbol_data != NO_CFI) {
michael@0 358 // Write out 'STACK CFI INIT' and 'STACK CFI' records.
michael@0 359 StackFrameEntrySet::const_iterator frame_it;
michael@0 360 for (frame_it = stack_frame_entries_.begin();
michael@0 361 frame_it != stack_frame_entries_.end(); ++frame_it) {
michael@0 362 StackFrameEntry *entry = *frame_it;
michael@0 363 stream << "STACK CFI INIT " << hex
michael@0 364 << (entry->address - load_address_) << " "
michael@0 365 << entry->size << " " << dec;
michael@0 366 if (!stream.good()
michael@0 367 || !WriteRuleMap(entry->initial_rules, stream))
michael@0 368 return ReportError();
michael@0 369
michael@0 370 stream << endl;
michael@0 371
michael@0 372 // Write out this entry's delta rules as 'STACK CFI' records.
michael@0 373 for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin();
michael@0 374 delta_it != entry->rule_changes.end(); ++delta_it) {
michael@0 375 stream << "STACK CFI " << hex
michael@0 376 << (delta_it->first - load_address_) << " " << dec;
michael@0 377 if (!stream.good()
michael@0 378 || !WriteRuleMap(delta_it->second, stream))
michael@0 379 return ReportError();
michael@0 380
michael@0 381 stream << endl;
michael@0 382 }
michael@0 383 }
michael@0 384 }
michael@0 385
michael@0 386 return true;
michael@0 387 }
michael@0 388
michael@0 389 } // namespace google_breakpad

mercurial