1 // Copyright 2010 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 // * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 // fast_source_line_resolver.cc: FastSourceLineResolver is a concrete class that
30 // implements SourceLineResolverInterface. Both FastSourceLineResolver and
31 // BasicSourceLineResolver inherit from SourceLineResolverBase class to reduce
32 // code redundancy.
33 //
34 // See fast_source_line_resolver.h and fast_source_line_resolver_types.h
35 // for more documentation.
36 //
37 // Author: Siyang Xie ([email protected])
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h> // Must come first
41 #endif
42
43 #include "google_breakpad/processor/fast_source_line_resolver.h"
44 #include "processor/fast_source_line_resolver_types.h"
45
46 #include <cassert>
47 #include <map>
48 #include <string>
49 #include <utility>
50
51 #include "common/scoped_ptr.h"
52 #include "common/using_std_string.h"
53 #include "processor/logging.h"
54 #include "processor/module_factory.h"
55 #include "processor/simple_serializer-inl.h"
56
57 using std::deque;
58 using std::unique_ptr;
59
60 namespace google_breakpad {
61
FastSourceLineResolver()62 FastSourceLineResolver::FastSourceLineResolver()
63 : SourceLineResolverBase(new FastModuleFactory) { }
64
ShouldDeleteMemoryBufferAfterLoadModule()65 bool FastSourceLineResolver::ShouldDeleteMemoryBufferAfterLoadModule() {
66 return false;
67 }
68
LookupAddress(StackFrame * frame,std::deque<std::unique_ptr<StackFrame>> * inlined_frames) const69 void FastSourceLineResolver::Module::LookupAddress(
70 StackFrame* frame,
71 std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const {
72 MemAddr address = frame->instruction - frame->module->base_address();
73
74 // First, look for a FUNC record that covers address. Use
75 // RetrieveNearestRange instead of RetrieveRange so that, if there
76 // is no such function, we can use the next function to bound the
77 // extent of the PUBLIC symbol we find, below. This does mean we
78 // need to check that address indeed falls within the function we
79 // find; do the range comparison in an overflow-friendly way.
80 scoped_ptr<Function> func(new Function);
81 const Function* func_ptr = 0;
82 scoped_ptr<PublicSymbol> public_symbol(new PublicSymbol);
83 const PublicSymbol* public_symbol_ptr = 0;
84 MemAddr function_base;
85 MemAddr function_size;
86 MemAddr public_address;
87
88 if (functions_.RetrieveNearestRange(address, func_ptr,
89 &function_base, &function_size) &&
90 address >= function_base && address - function_base < function_size) {
91 func->CopyFrom(func_ptr);
92 frame->function_name = func->name;
93 frame->function_base = frame->module->base_address() + function_base;
94 frame->is_multiple = func->is_multiple;
95
96 scoped_ptr<Line> line(new Line);
97 const Line* line_ptr = 0;
98 MemAddr line_base;
99 if (func->lines.RetrieveRange(address, line_ptr, &line_base, NULL)) {
100 line->CopyFrom(line_ptr);
101 FileMap::iterator it = files_.find(line->source_file_id);
102 if (it != files_.end()) {
103 frame->source_file_name =
104 files_.find(line->source_file_id).GetValuePtr();
105 }
106 frame->source_line = line->line;
107 frame->source_line_base = frame->module->base_address() + line_base;
108 }
109 // Check if this is inlined function call.
110 if (inlined_frames) {
111 ConstructInlineFrames(frame, address, func->inlines, inlined_frames);
112 }
113 } else if (public_symbols_.Retrieve(address,
114 public_symbol_ptr, &public_address) &&
115 (!func_ptr || public_address > function_base)) {
116 public_symbol->CopyFrom(public_symbol_ptr);
117 frame->function_name = public_symbol->name;
118 frame->function_base = frame->module->base_address() + public_address;
119 frame->is_multiple = public_symbol->is_multiple;
120 }
121 }
122
ConstructInlineFrames(StackFrame * frame,MemAddr address,const StaticContainedRangeMap<MemAddr,char> & inline_map,std::deque<std::unique_ptr<StackFrame>> * inlined_frames) const123 void FastSourceLineResolver::Module::ConstructInlineFrames(
124 StackFrame* frame,
125 MemAddr address,
126 const StaticContainedRangeMap<MemAddr, char>& inline_map,
127 std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const {
128 std::vector<const char*> inline_ptrs;
129 if (!inline_map.RetrieveRanges(address, inline_ptrs)) {
130 return;
131 }
132
133 for (const char* inline_ptr : inline_ptrs) {
134 scoped_ptr<Inline> in(new Inline);
135 in->CopyFrom(inline_ptr);
136 unique_ptr<StackFrame> new_frame =
137 unique_ptr<StackFrame>(new StackFrame(*frame));
138 auto origin_iter = inline_origins_.find(in->origin_id);
139 if (origin_iter != inline_origins_.end()) {
140 scoped_ptr<InlineOrigin> origin(new InlineOrigin);
141 origin->CopyFrom(origin_iter.GetValuePtr());
142 new_frame->function_name = origin->name;
143 } else {
144 new_frame->function_name = "<name omitted>";
145 }
146
147 // Store call site file and line in current frame, which will be updated
148 // later.
149 new_frame->source_line = in->call_site_line;
150 if (in->has_call_site_file_id) {
151 auto file_iter = files_.find(in->call_site_file_id);
152 if (file_iter != files_.end()) {
153 new_frame->source_file_name = file_iter.GetValuePtr();
154 }
155 }
156
157 // Use the starting adress of the inlined range as inlined function base.
158 new_frame->function_base = new_frame->module->base_address();
159 for (const auto& range : in->inline_ranges) {
160 if (address >= range.first && address < range.first + range.second) {
161 new_frame->function_base += range.first;
162 break;
163 }
164 }
165 new_frame->trust = StackFrame::FRAME_TRUST_INLINE;
166
167 // The inlines vector has an order from innermost entry to outermost entry.
168 // By push_back, we will have inlined_frames with the same order.
169 inlined_frames->push_back(std::move(new_frame));
170 }
171
172 // Update the source file and source line for each inlined frame.
173 if (!inlined_frames->empty()) {
174 string parent_frame_source_file_name = frame->source_file_name;
175 int parent_frame_source_line = frame->source_line;
176 frame->source_file_name = inlined_frames->back()->source_file_name;
177 frame->source_line = inlined_frames->back()->source_line;
178 for (unique_ptr<StackFrame>& inlined_frame : *inlined_frames) {
179 std::swap(inlined_frame->source_file_name, parent_frame_source_file_name);
180 std::swap(inlined_frame->source_line, parent_frame_source_line);
181 }
182 }
183 }
184
185 // WFI: WindowsFrameInfo.
186 // Returns a WFI object reading from a raw memory chunk of data
CopyWFI(const char * raw)187 WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char* raw) {
188 const WindowsFrameInfo::StackInfoTypes type =
189 static_cast<const WindowsFrameInfo::StackInfoTypes>(
190 *reinterpret_cast<const int32_t*>(raw));
191
192 // The first 8 bytes of int data are unused.
193 // They correspond to "StackInfoTypes type_;" and "int valid;"
194 // data member of WFI.
195 const uint32_t* para_uint32 = reinterpret_cast<const uint32_t*>(
196 raw + 2 * sizeof(int32_t));
197
198 uint32_t prolog_size = para_uint32[0];;
199 uint32_t epilog_size = para_uint32[1];
200 uint32_t parameter_size = para_uint32[2];
201 uint32_t saved_register_size = para_uint32[3];
202 uint32_t local_size = para_uint32[4];
203 uint32_t max_stack_size = para_uint32[5];
204 const char* boolean = reinterpret_cast<const char*>(para_uint32 + 6);
205 bool allocates_base_pointer = (*boolean != 0);
206 string program_string = boolean + 1;
207
208 return WindowsFrameInfo(type,
209 prolog_size,
210 epilog_size,
211 parameter_size,
212 saved_register_size,
213 local_size,
214 max_stack_size,
215 allocates_base_pointer,
216 program_string);
217 }
218
219 // Loads a map from the given buffer in char* type.
220 // Does NOT take ownership of mem_buffer.
221 // In addition, treat mem_buffer as const char*.
LoadMapFromMemory(char * memory_buffer,size_t memory_buffer_size)222 bool FastSourceLineResolver::Module::LoadMapFromMemory(
223 char* memory_buffer,
224 size_t memory_buffer_size) {
225 if (!memory_buffer) return false;
226
227 // Read the "is_corrupt" flag.
228 const char* mem_buffer = memory_buffer;
229 mem_buffer = SimpleSerializer<bool>::Read(mem_buffer, &is_corrupt_);
230
231 const uint32_t* map_sizes = reinterpret_cast<const uint32_t*>(mem_buffer);
232
233 unsigned int header_size = kNumberMaps_ * sizeof(unsigned int);
234
235 // offsets[]: an array of offset addresses (with respect to mem_buffer),
236 // for each "Static***Map" component of Module.
237 // "Static***Map": static version of std::map or map wrapper, i.e., StaticMap,
238 // StaticAddressMap, StaticContainedRangeMap, and StaticRangeMap.
239 unsigned int offsets[kNumberMaps_];
240 offsets[0] = header_size;
241 for (int i = 1; i < kNumberMaps_; ++i) {
242 offsets[i] = offsets[i - 1] + map_sizes[i - 1];
243 }
244 unsigned int expected_size = sizeof(bool) + offsets[kNumberMaps_ - 1] +
245 map_sizes[kNumberMaps_ - 1] + 1;
246 if (expected_size != memory_buffer_size &&
247 // Allow for having an extra null terminator.
248 expected_size != memory_buffer_size - 1) {
249 // This could either be a random corruption or the serialization format was
250 // changed without updating the version in kSerializedBreakpadFileExtension.
251 BPLOG(ERROR) << "Memory buffer is either corrupt or an unsupported version"
252 << ", expected size: " << expected_size
253 << ", actual size: " << memory_buffer_size;
254 return false;
255 }
256 BPLOG(INFO) << "Memory buffer size looks good, size: " << memory_buffer_size;
257
258 // Use pointers to construct Static*Map data members in Module:
259 int map_id = 0;
260 files_ = StaticMap<int, char>(mem_buffer + offsets[map_id++]);
261 functions_ =
262 StaticRangeMap<MemAddr, Function>(mem_buffer + offsets[map_id++]);
263 public_symbols_ =
264 StaticAddressMap<MemAddr, PublicSymbol>(mem_buffer + offsets[map_id++]);
265 for (int i = 0; i < WindowsFrameInfo::STACK_INFO_LAST; ++i) {
266 windows_frame_info_[i] =
267 StaticContainedRangeMap<MemAddr, char>(mem_buffer + offsets[map_id++]);
268 }
269
270 cfi_initial_rules_ =
271 StaticRangeMap<MemAddr, char>(mem_buffer + offsets[map_id++]);
272 cfi_delta_rules_ = StaticMap<MemAddr, char>(mem_buffer + offsets[map_id++]);
273 inline_origins_ = StaticMap<int, char>(mem_buffer + offsets[map_id++]);
274 return true;
275 }
276
FindWindowsFrameInfo(const StackFrame * frame) const277 WindowsFrameInfo* FastSourceLineResolver::Module::FindWindowsFrameInfo(
278 const StackFrame* frame) const {
279 MemAddr address = frame->instruction - frame->module->base_address();
280 scoped_ptr<WindowsFrameInfo> result(new WindowsFrameInfo());
281
282 // We only know about WindowsFrameInfo::STACK_INFO_FRAME_DATA and
283 // WindowsFrameInfo::STACK_INFO_FPO. Prefer them in this order.
284 // WindowsFrameInfo::STACK_INFO_FRAME_DATA is the newer type that
285 // includes its own program string.
286 // WindowsFrameInfo::STACK_INFO_FPO is the older type
287 // corresponding to the FPO_DATA struct. See stackwalker_x86.cc.
288 const char* frame_info_ptr;
289 if ((windows_frame_info_[WindowsFrameInfo::STACK_INFO_FRAME_DATA]
290 .RetrieveRange(address, frame_info_ptr))
291 || (windows_frame_info_[WindowsFrameInfo::STACK_INFO_FPO]
292 .RetrieveRange(address, frame_info_ptr))) {
293 result->CopyFrom(CopyWFI(frame_info_ptr));
294 return result.release();
295 }
296
297 // Even without a relevant STACK line, many functions contain
298 // information about how much space their parameters consume on the
299 // stack. Use RetrieveNearestRange instead of RetrieveRange, so that
300 // we can use the function to bound the extent of the PUBLIC symbol,
301 // below. However, this does mean we need to check that ADDRESS
302 // falls within the retrieved function's range; do the range
303 // comparison in an overflow-friendly way.
304 scoped_ptr<Function> function(new Function);
305 const Function* function_ptr = 0;
306 MemAddr function_base, function_size;
307 if (functions_.RetrieveNearestRange(address, function_ptr,
308 &function_base, &function_size) &&
309 address >= function_base && address - function_base < function_size) {
310 function->CopyFrom(function_ptr);
311 result->parameter_size = function->parameter_size;
312 result->valid |= WindowsFrameInfo::VALID_PARAMETER_SIZE;
313 return result.release();
314 }
315
316 // PUBLIC symbols might have a parameter size. Use the function we
317 // found above to limit the range the public symbol covers.
318 scoped_ptr<PublicSymbol> public_symbol(new PublicSymbol);
319 const PublicSymbol* public_symbol_ptr = 0;
320 MemAddr public_address;
321 if (public_symbols_.Retrieve(address, public_symbol_ptr, &public_address) &&
322 (!function_ptr || public_address > function_base)) {
323 public_symbol->CopyFrom(public_symbol_ptr);
324 result->parameter_size = public_symbol->parameter_size;
325 }
326
327 return NULL;
328 }
329
FindCFIFrameInfo(const StackFrame * frame) const330 CFIFrameInfo* FastSourceLineResolver::Module::FindCFIFrameInfo(
331 const StackFrame* frame) const {
332 MemAddr address = frame->instruction - frame->module->base_address();
333 MemAddr initial_base, initial_size;
334 const char* initial_rules = NULL;
335
336 // Find the initial rule whose range covers this address. That
337 // provides an initial set of register recovery rules. Then, walk
338 // forward from the initial rule's starting address to frame's
339 // instruction address, applying delta rules.
340 if (!cfi_initial_rules_.RetrieveRange(address, initial_rules,
341 &initial_base, &initial_size)) {
342 return NULL;
343 }
344
345 // Create a frame info structure, and populate it with the rules from
346 // the STACK CFI INIT record.
347 scoped_ptr<CFIFrameInfo> rules(new CFIFrameInfo());
348 if (!ParseCFIRuleSet(initial_rules, rules.get()))
349 return NULL;
350
351 // Find the first delta rule that falls within the initial rule's range.
352 StaticMap<MemAddr, char>::iterator delta =
353 cfi_delta_rules_.lower_bound(initial_base);
354
355 // Apply delta rules up to and including the frame's address.
356 while (delta != cfi_delta_rules_.end() && delta.GetKey() <= address) {
357 ParseCFIRuleSet(delta.GetValuePtr(), rules.get());
358 delta++;
359 }
360
361 return rules.release();
362 }
363
364 } // namespace google_breakpad
365