244fc98845d59b3ea53726627ad148c20f6f8896
[platform/framework/web/crosswalk.git] / src / breakpad / src / common / module.cc
1 // Copyright (c) 2011 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 <assert.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <string.h>
40
41 #include <iostream>
42 #include <utility>
43
44 namespace google_breakpad {
45
46 using std::dec;
47 using std::endl;
48 using std::hex;
49
50
51 Module::Module(const string &name, const string &os,
52                const string &architecture, const string &id) :
53     name_(name),
54     os_(os),
55     architecture_(architecture),
56     id_(id),
57     load_address_(0) { }
58
59 Module::~Module() {
60   for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
61     delete it->second;
62   for (FunctionSet::iterator it = functions_.begin();
63        it != functions_.end(); ++it) {
64     delete *it;
65   }
66   for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin();
67        it != stack_frame_entries_.end(); ++it) {
68     delete *it;
69   }
70   for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it)
71     delete *it;
72 }
73
74 void Module::SetLoadAddress(Address address) {
75   load_address_ = address;
76 }
77
78 void Module::AddFunction(Function *function) {
79   // FUNC lines must not hold an empty name, so catch the problem early if
80   // callers try to add one.
81   assert(!function->name.empty());
82   std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function);
83   if (!ret.second) {
84     // Free the duplicate that was not inserted because this Module
85     // now owns it.
86     delete function;
87   }
88 }
89
90 void Module::AddFunctions(vector<Function *>::iterator begin,
91                           vector<Function *>::iterator end) {
92   for (vector<Function *>::iterator it = begin; it != end; ++it)
93     AddFunction(*it);
94 }
95
96 void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) {
97   stack_frame_entries_.push_back(stack_frame_entry);
98 }
99
100 void Module::AddExtern(Extern *ext) {
101   std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext);
102   if (!ret.second) {
103     // Free the duplicate that was not inserted because this Module
104     // now owns it.
105     delete ext;
106   }
107 }
108
109 void Module::GetFunctions(vector<Function *> *vec,
110                           vector<Function *>::iterator i) {
111   vec->insert(i, functions_.begin(), functions_.end());
112 }
113
114 void Module::GetExterns(vector<Extern *> *vec,
115                         vector<Extern *>::iterator i) {
116   vec->insert(i, externs_.begin(), externs_.end());
117 }
118
119 Module::File *Module::FindFile(const string &name) {
120   // A tricky bit here.  The key of each map entry needs to be a
121   // pointer to the entry's File's name string.  This means that we
122   // can't do the initial lookup with any operation that would create
123   // an empty entry for us if the name isn't found (like, say,
124   // operator[] or insert do), because such a created entry's key will
125   // be a pointer the string passed as our argument.  Since the key of
126   // a map's value type is const, we can't fix it up once we've
127   // created our file.  lower_bound does the lookup without doing an
128   // insertion, and returns a good hint iterator to pass to insert.
129   // Our "destiny" is where we belong, whether we're there or not now.
130   FileByNameMap::iterator destiny = files_.lower_bound(&name);
131   if (destiny == files_.end()
132       || *destiny->first != name) {  // Repeated string comparison, boo hoo.
133     File *file = new File;
134     file->name = name;
135     file->source_id = -1;
136     destiny = files_.insert(destiny,
137                             FileByNameMap::value_type(&file->name, file));
138   }
139   return destiny->second;
140 }
141
142 Module::File *Module::FindFile(const char *name) {
143   string name_string = name;
144   return FindFile(name_string);
145 }
146
147 Module::File *Module::FindExistingFile(const string &name) {
148   FileByNameMap::iterator it = files_.find(&name);
149   return (it == files_.end()) ? NULL : it->second;
150 }
151
152 void Module::GetFiles(vector<File *> *vec) {
153   vec->clear();
154   for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
155     vec->push_back(it->second);
156 }
157
158 void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) const {
159   *vec = stack_frame_entries_;
160 }
161
162 void Module::AssignSourceIds() {
163   // First, give every source file an id of -1.
164   for (FileByNameMap::iterator file_it = files_.begin();
165        file_it != files_.end(); ++file_it) {
166     file_it->second->source_id = -1;
167   }
168
169   // Next, mark all files actually cited by our functions' line number
170   // info, by setting each one's source id to zero.
171   for (FunctionSet::const_iterator func_it = functions_.begin();
172        func_it != functions_.end(); ++func_it) {
173     Function *func = *func_it;
174     for (vector<Line>::iterator line_it = func->lines.begin();
175          line_it != func->lines.end(); ++line_it)
176       line_it->file->source_id = 0;
177   }
178
179   // Finally, assign source ids to those files that have been marked.
180   // We could have just assigned source id numbers while traversing
181   // the line numbers, but doing it this way numbers the files in
182   // lexicographical order by name, which is neat.
183   int next_source_id = 0;
184   for (FileByNameMap::iterator file_it = files_.begin();
185        file_it != files_.end(); ++file_it) {
186     if (!file_it->second->source_id)
187       file_it->second->source_id = next_source_id++;
188   }
189 }
190
191 bool Module::ReportError() {
192   fprintf(stderr, "error writing symbol file: %s\n",
193           strerror(errno));
194   return false;
195 }
196
197 bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
198   for (RuleMap::const_iterator it = rule_map.begin();
199        it != rule_map.end(); ++it) {
200     if (it != rule_map.begin())
201       stream << ' ';
202     stream << it->first << ": " << it->second;
203   }
204   return stream.good();
205 }
206
207 bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
208   stream << "MODULE " << os_ << " " << architecture_ << " "
209          << id_ << " " << name_ << endl;
210   if (!stream.good())
211     return ReportError();
212
213   if (symbol_data != ONLY_CFI) {
214     AssignSourceIds();
215
216     // Write out files.
217     for (FileByNameMap::iterator file_it = files_.begin();
218          file_it != files_.end(); ++file_it) {
219       File *file = file_it->second;
220       if (file->source_id >= 0) {
221         stream << "FILE " << file->source_id << " " <<  file->name << endl;
222         if (!stream.good())
223           return ReportError();
224       }
225     }
226
227     // Write out functions and their lines.
228     for (FunctionSet::const_iterator func_it = functions_.begin();
229          func_it != functions_.end(); ++func_it) {
230       Function *func = *func_it;
231       stream << "FUNC " << hex
232              << (func->address - load_address_) << " "
233              << func->size << " "
234              << func->parameter_size << " "
235              << func->name << dec << endl;
236       if (!stream.good())
237         return ReportError();
238
239       for (vector<Line>::iterator line_it = func->lines.begin();
240            line_it != func->lines.end(); ++line_it) {
241         stream << hex
242                << (line_it->address - load_address_) << " "
243                << line_it->size << " "
244                << dec
245                << line_it->number << " "
246                << line_it->file->source_id << endl;
247         if (!stream.good())
248           return ReportError();
249       }
250     }
251
252     // Write out 'PUBLIC' records.
253     for (ExternSet::const_iterator extern_it = externs_.begin();
254          extern_it != externs_.end(); ++extern_it) {
255       Extern *ext = *extern_it;
256       stream << "PUBLIC " << hex
257              << (ext->address - load_address_) << " 0 "
258              << ext->name << dec << endl;
259     }
260   }
261
262   if (symbol_data != NO_CFI) {
263     // Write out 'STACK CFI INIT' and 'STACK CFI' records.
264     vector<StackFrameEntry *>::const_iterator frame_it;
265     for (frame_it = stack_frame_entries_.begin();
266          frame_it != stack_frame_entries_.end(); ++frame_it) {
267       StackFrameEntry *entry = *frame_it;
268       stream << "STACK CFI INIT " << hex
269              << (entry->address - load_address_) << " "
270              << entry->size << " " << dec;
271       if (!stream.good()
272           || !WriteRuleMap(entry->initial_rules, stream))
273         return ReportError();
274
275       stream << endl;
276
277       // Write out this entry's delta rules as 'STACK CFI' records.
278       for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin();
279            delta_it != entry->rule_changes.end(); ++delta_it) {
280         stream << "STACK CFI " << hex
281                << (delta_it->first - load_address_) << " " << dec;
282         if (!stream.good()
283             || !WriteRuleMap(delta_it->second, stream))
284           return ReportError();
285
286         stream << endl;
287       }
288     }
289   }
290
291   return true;
292 }
293
294 }  // namespace google_breakpad