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