fast_source_line_resolver.cc
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 (lambxsy@google.com) 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 62 FastSourceLineResolver::FastSourceLineResolver() 63 : SourceLineResolverBase(new FastModuleFactory) { } 64 65 bool FastSourceLineResolver::ShouldDeleteMemoryBufferAfterLoadModule() { 66 return false; 67 } 68 69 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 123 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 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*. 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 277 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 330 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