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