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 : // dump_stabs.cc --- implement the StabsToModule class.
33 :
34 : #include <assert.h>
35 : #include <cxxabi.h>
36 : #include <stdarg.h>
37 :
38 : #include <algorithm>
39 :
40 : #include "common/stabs_to_module.h"
41 :
42 : namespace google_breakpad {
43 :
44 : using std::string;
45 :
46 : // Demangle using abi call.
47 : // Older GCC may not support it.
48 0 : static string Demangle(const string &mangled) {
49 0 : int status = 0;
50 0 : char *demangled = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status);
51 0 : if (status == 0 && demangled != NULL) {
52 0 : string str(demangled);
53 0 : free(demangled);
54 0 : return str;
55 : }
56 0 : return string(mangled);
57 : }
58 :
59 0 : StabsToModule::~StabsToModule() {
60 : // Free any functions we've accumulated but not added to the module.
61 0 : for (vector<Module::Function *>::const_iterator func_it = functions_.begin();
62 0 : func_it != functions_.end(); func_it++)
63 0 : delete *func_it;
64 : // Free any function that we're currently within.
65 0 : delete current_function_;
66 0 : }
67 :
68 0 : bool StabsToModule::StartCompilationUnit(const char *name, uint64_t address,
69 : const char *build_directory) {
70 0 : assert(!in_compilation_unit_);
71 0 : in_compilation_unit_ = true;
72 0 : current_source_file_name_ = name;
73 0 : current_source_file_ = module_->FindFile(name);
74 0 : comp_unit_base_address_ = address;
75 0 : boundaries_.push_back(static_cast<Module::Address>(address));
76 0 : return true;
77 : }
78 :
79 0 : bool StabsToModule::EndCompilationUnit(uint64_t address) {
80 0 : assert(in_compilation_unit_);
81 0 : in_compilation_unit_ = false;
82 0 : comp_unit_base_address_ = 0;
83 0 : current_source_file_ = NULL;
84 0 : current_source_file_name_ = NULL;
85 0 : if (address)
86 0 : boundaries_.push_back(static_cast<Module::Address>(address));
87 0 : return true;
88 : }
89 :
90 0 : bool StabsToModule::StartFunction(const string &name,
91 : uint64_t address) {
92 0 : assert(!current_function_);
93 0 : Module::Function *f = new Module::Function;
94 0 : f->name = Demangle(name);
95 0 : f->address = address;
96 0 : f->size = 0; // We compute this in StabsToModule::Finalize().
97 0 : f->parameter_size = 0; // We don't provide this information.
98 0 : current_function_ = f;
99 0 : boundaries_.push_back(static_cast<Module::Address>(address));
100 0 : return true;
101 : }
102 :
103 0 : bool StabsToModule::EndFunction(uint64_t address) {
104 0 : assert(current_function_);
105 : // Functions in this compilation unit should have address bigger
106 : // than the compilation unit's starting address. There may be a lot
107 : // of duplicated entries for functions in the STABS data. We will
108 : // count on the Module to remove the duplicates.
109 0 : if (current_function_->address >= comp_unit_base_address_)
110 0 : functions_.push_back(current_function_);
111 : else
112 0 : delete current_function_;
113 0 : current_function_ = NULL;
114 0 : if (address)
115 0 : boundaries_.push_back(static_cast<Module::Address>(address));
116 0 : return true;
117 : }
118 :
119 0 : bool StabsToModule::Line(uint64_t address, const char *name, int number) {
120 0 : assert(current_function_);
121 0 : assert(current_source_file_);
122 0 : if (name != current_source_file_name_) {
123 0 : current_source_file_ = module_->FindFile(name);
124 0 : current_source_file_name_ = name;
125 : }
126 : Module::Line line;
127 0 : line.address = address;
128 0 : line.size = 0; // We compute this in StabsToModule::Finalize().
129 0 : line.file = current_source_file_;
130 0 : line.number = number;
131 0 : current_function_->lines.push_back(line);
132 0 : return true;
133 : }
134 :
135 0 : void StabsToModule::Warning(const char *format, ...) {
136 : va_list args;
137 0 : va_start(args, format);
138 0 : vfprintf(stderr, format, args);
139 0 : va_end(args);
140 0 : }
141 :
142 0 : void StabsToModule::Finalize() {
143 : // Sort our boundary list, so we can search it quickly.
144 0 : sort(boundaries_.begin(), boundaries_.end());
145 : // Sort all functions by address, just for neatness.
146 0 : sort(functions_.begin(), functions_.end(),
147 0 : Module::Function::CompareByAddress);
148 :
149 0 : for (vector<Module::Function *>::const_iterator func_it = functions_.begin();
150 0 : func_it != functions_.end();
151 : func_it++) {
152 0 : Module::Function *f = *func_it;
153 : // Compute the function f's size.
154 : vector<Module::Address>::const_iterator boundary
155 0 : = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address);
156 0 : if (boundary != boundaries_.end())
157 0 : f->size = *boundary - f->address;
158 : else
159 : // If this is the last function in the module, and the STABS
160 : // reader was unable to give us its ending address, then assign
161 : // it a bogus, very large value. This will happen at most once
162 : // per module: since we've added all functions' addresses to the
163 : // boundary table, only one can be the last.
164 0 : f->size = kFallbackSize;
165 :
166 : // Compute sizes for each of the function f's lines --- if it has any.
167 0 : if (!f->lines.empty()) {
168 0 : stable_sort(f->lines.begin(), f->lines.end(),
169 0 : Module::Line::CompareByAddress);
170 0 : vector<Module::Line>::iterator last_line = f->lines.end() - 1;
171 0 : for (vector<Module::Line>::iterator line_it = f->lines.begin();
172 : line_it != last_line; line_it++)
173 0 : line_it[0].size = line_it[1].address - line_it[0].address;
174 : // Compute the size of the last line from f's end address.
175 0 : last_line->size = (f->address + f->size) - last_line->address;
176 : }
177 : }
178 : // Now that everything has a size, add our functions to the module, and
179 : // dispose of our private list.
180 0 : module_->AddFunctions(functions_.begin(), functions_.end());
181 0 : functions_.clear();
182 0 : }
183 :
184 : } // namespace google_breakpad
|