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 :
39 : namespace google_breakpad {
40 :
41 124 : Module::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 124 : load_address_(0) { }
48 :
49 248 : Module::~Module() {
50 23149 : for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); it++)
51 23025 : delete it->second;
52 606036 : for (FunctionSet::iterator it = functions_.begin();
53 303018 : it != functions_.end(); it++)
54 302894 : delete *it;
55 1383692 : for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin();
56 691846 : it != stack_frame_entries_.end(); it++)
57 691722 : delete *it;
58 124 : }
59 :
60 124 : void Module::SetLoadAddress(Address address) {
61 124 : load_address_ = address;
62 124 : }
63 :
64 617615 : void Module::AddFunction(Function *function) {
65 617615 : std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function);
66 617615 : if (!ret.second) {
67 : // Free the duplicate we failed to insert because we own it.
68 314721 : delete function;
69 : }
70 617615 : }
71 :
72 4723 : void Module::AddFunctions(vector<Function *>::iterator begin,
73 : vector<Function *>::iterator end) {
74 622338 : for (vector<Function *>::iterator it = begin; it != end; it++)
75 617615 : AddFunction(*it);
76 4723 : }
77 :
78 691722 : void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) {
79 691722 : stack_frame_entries_.push_back(stack_frame_entry);
80 691722 : }
81 :
82 0 : void Module::GetFunctions(vector<Function *> *vec,
83 : vector<Function *>::iterator i) {
84 0 : vec->insert(i, functions_.begin(), functions_.end());
85 0 : }
86 :
87 357415 : Module::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 357415 : FileByNameMap::iterator destiny = files_.lower_bound(&name);
99 713965 : if (destiny == files_.end()
100 356550 : || *destiny->first != name) { // Repeated string comparison, boo hoo.
101 23025 : File *file = new File;
102 23025 : file->name = name;
103 23025 : file->source_id = -1;
104 : destiny = files_.insert(destiny,
105 23025 : FileByNameMap::value_type(&file->name, file));
106 : }
107 357415 : return destiny->second;
108 : }
109 :
110 0 : Module::File *Module::FindFile(const char *name) {
111 0 : string name_string = name;
112 0 : return FindFile(name_string);
113 : }
114 :
115 0 : Module::File *Module::FindExistingFile(const string &name) {
116 0 : FileByNameMap::iterator it = files_.find(&name);
117 0 : return (it == files_.end()) ? NULL : it->second;
118 : }
119 :
120 0 : void Module::GetFiles(vector<File *> *vec) {
121 0 : vec->clear();
122 0 : for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); it++)
123 0 : vec->push_back(it->second);
124 0 : }
125 :
126 0 : void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) {
127 0 : *vec = stack_frame_entries_;
128 0 : }
129 :
130 124 : void Module::AssignSourceIds() {
131 : // First, give every source file an id of -1.
132 46298 : for (FileByNameMap::iterator file_it = files_.begin();
133 23149 : file_it != files_.end(); file_it++)
134 23025 : 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 606036 : for (FunctionSet::const_iterator func_it = functions_.begin();
139 303018 : func_it != functions_.end(); func_it++) {
140 302894 : Function *func = *func_it;
141 5850318 : for (vector<Line>::iterator line_it = func->lines.begin();
142 2925159 : line_it != func->lines.end(); line_it++)
143 2622265 : 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 124 : int next_source_id = 0;
151 46298 : for (FileByNameMap::iterator file_it = files_.begin();
152 23149 : file_it != files_.end(); file_it++)
153 23025 : if (!file_it->second->source_id)
154 10812 : file_it->second->source_id = next_source_id++;
155 124 : }
156 :
157 0 : bool Module::ReportError() {
158 : fprintf(stderr, "error writing symbol file: %s\n",
159 0 : strerror(errno));
160 0 : return false;
161 : }
162 :
163 4114800 : bool Module::WriteRuleMap(const RuleMap &rule_map, FILE *stream) {
164 20880074 : for (RuleMap::const_iterator it = rule_map.begin();
165 10440037 : it != rule_map.end(); it++) {
166 8535674 : if (it != rule_map.begin() &&
167 2210437 : 0 > putc(' ', stream))
168 0 : return false;
169 6325237 : if (0 > fprintf(stream, "%s: %s", it->first.c_str(), it->second.c_str()))
170 0 : return false;
171 : }
172 4114800 : return true;
173 : }
174 :
175 124 : bool Module::Write(FILE *stream) {
176 124 : if (0 > fprintf(stream, "MODULE %s %s %s %s\n",
177 : os_.c_str(), architecture_.c_str(), id_.c_str(),
178 124 : name_.c_str()))
179 0 : return ReportError();
180 :
181 124 : AssignSourceIds();
182 :
183 : // Write out files.
184 46298 : for (FileByNameMap::iterator file_it = files_.begin();
185 23149 : file_it != files_.end(); file_it++) {
186 23025 : File *file = file_it->second;
187 23025 : if (file->source_id >= 0) {
188 10812 : if (0 > fprintf(stream, "FILE %d %s\n",
189 10812 : file->source_id, file->name.c_str()))
190 0 : return ReportError();
191 : }
192 : }
193 :
194 : // Write out functions and their lines.
195 606036 : for (FunctionSet::const_iterator func_it = functions_.begin();
196 303018 : func_it != functions_.end(); func_it++) {
197 302894 : Function *func = *func_it;
198 302894 : 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 302894 : func->name.c_str()))
203 0 : return ReportError();
204 5850318 : for (vector<Line>::iterator line_it = func->lines.begin();
205 2925159 : line_it != func->lines.end(); line_it++)
206 2622265 : if (0 > fprintf(stream, "%llx %llx %d %d\n",
207 2622265 : (unsigned long long) (line_it->address - load_address_),
208 2622265 : (unsigned long long) line_it->size,
209 2622265 : line_it->number,
210 10489060 : line_it->file->source_id))
211 0 : return ReportError();
212 : }
213 :
214 : // Write out 'STACK CFI INIT' and 'STACK CFI' records.
215 124 : vector<StackFrameEntry *>::const_iterator frame_it;
216 1383692 : for (frame_it = stack_frame_entries_.begin();
217 691846 : frame_it != stack_frame_entries_.end(); frame_it++) {
218 691722 : StackFrameEntry *entry = *frame_it;
219 2075166 : if (0 > fprintf(stream, "STACK CFI INIT %llx %llx ",
220 : (unsigned long long) entry->address - load_address_,
221 691722 : (unsigned long long) entry->size)
222 691722 : || !WriteRuleMap(entry->initial_rules, stream)
223 691722 : || 0 > putc('\n', stream))
224 0 : return ReportError();
225 :
226 : // Write out this entry's delta rules as 'STACK CFI' records.
227 8229600 : for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin();
228 4114800 : delta_it != entry->rule_changes.end(); delta_it++) {
229 10269234 : if (0 > fprintf(stream, "STACK CFI %llx ",
230 3423078 : (unsigned long long) delta_it->first - load_address_)
231 3423078 : || !WriteRuleMap(delta_it->second, stream)
232 3423078 : || 0 > putc('\n', stream))
233 0 : return ReportError();
234 : }
235 : }
236 :
237 124 : return true;
238 : }
239 :
240 : } // namespace google_breakpad
|