| OLD | NEW |
| 1 // Copyright (c) 2010 Google Inc. | 1 // Copyright (c) 2010 Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 LogParseError("ParseStackInfo failed", line_number, &num_errors); | 139 LogParseError("ParseStackInfo failed", line_number, &num_errors); |
| 140 } | 140 } |
| 141 } else if (strncmp(buffer, "FUNC ", 5) == 0) { | 141 } else if (strncmp(buffer, "FUNC ", 5) == 0) { |
| 142 cur_func.reset(ParseFunction(buffer)); | 142 cur_func.reset(ParseFunction(buffer)); |
| 143 if (!cur_func.get()) { | 143 if (!cur_func.get()) { |
| 144 LogParseError("ParseFunction failed", line_number, &num_errors); | 144 LogParseError("ParseFunction failed", line_number, &num_errors); |
| 145 } else { | 145 } else { |
| 146 // StoreRange will fail if the function has an invalid address or size. | 146 // StoreRange will fail if the function has an invalid address or size. |
| 147 // We'll silently ignore this, the function and any corresponding lines | 147 // We'll silently ignore this, the function and any corresponding lines |
| 148 // will be destroyed when cur_func is released. | 148 // will be destroyed when cur_func is released. |
| 149 functions_.StoreRange(cur_func->address, cur_func->size, cur_func); | 149 functions_.StoreRange(cur_func->address, 0 /* delta */, cur_func->size, |
| 150 cur_func); |
| 150 } | 151 } |
| 151 } else if (strncmp(buffer, "PUBLIC ", 7) == 0) { | 152 } else if (strncmp(buffer, "PUBLIC ", 7) == 0) { |
| 152 // Clear cur_func: public symbols don't contain line number information. | 153 // Clear cur_func: public symbols don't contain line number information. |
| 153 cur_func.reset(); | 154 cur_func.reset(); |
| 154 | 155 |
| 155 if (!ParsePublicSymbol(buffer)) { | 156 if (!ParsePublicSymbol(buffer)) { |
| 156 LogParseError("ParsePublicSymbol failed", line_number, &num_errors); | 157 LogParseError("ParsePublicSymbol failed", line_number, &num_errors); |
| 157 } | 158 } |
| 158 } else if (strncmp(buffer, "MODULE ", 7) == 0) { | 159 } else if (strncmp(buffer, "MODULE ", 7) == 0) { |
| 159 // Ignore these. They're not of any use to BasicSourceLineResolver, | 160 // Ignore these. They're not of any use to BasicSourceLineResolver, |
| 160 // which is fed modules by a SymbolSupplier. These lines are present to | 161 // which is fed modules by a SymbolSupplier. These lines are present to |
| 161 // aid other tools in properly placing symbol files so that they can | 162 // aid other tools in properly placing symbol files so that they can |
| 162 // be accessed by a SymbolSupplier. | 163 // be accessed by a SymbolSupplier. |
| 163 // | 164 // |
| 164 // MODULE <guid> <age> <filename> | 165 // MODULE <guid> <age> <filename> |
| 165 } else if (strncmp(buffer, "INFO ", 5) == 0) { | 166 } else if (strncmp(buffer, "INFO ", 5) == 0) { |
| 166 // Ignore these as well, they're similarly just for housekeeping. | 167 // Ignore these as well, they're similarly just for housekeeping. |
| 167 // | 168 // |
| 168 // INFO CODE_ID <code id> <filename> | 169 // INFO CODE_ID <code id> <filename> |
| 169 } else { | 170 } else { |
| 170 if (!cur_func.get()) { | 171 if (!cur_func.get()) { |
| 171 LogParseError("Found source line data without a function", | 172 LogParseError("Found source line data without a function", |
| 172 line_number, &num_errors); | 173 line_number, &num_errors); |
| 173 } else { | 174 } else { |
| 174 Line *line = ParseLine(buffer); | 175 Line *line = ParseLine(buffer); |
| 175 if (!line) { | 176 if (!line) { |
| 176 LogParseError("ParseLine failed", line_number, &num_errors); | 177 LogParseError("ParseLine failed", line_number, &num_errors); |
| 177 } else { | 178 } else { |
| 178 cur_func->lines.StoreRange(line->address, line->size, | 179 cur_func->lines.StoreRange(line->address, 0 /* delta */, line->size, |
| 179 linked_ptr<Line>(line)); | 180 linked_ptr<Line>(line)); |
| 180 } | 181 } |
| 181 } | 182 } |
| 182 } | 183 } |
| 183 if (num_errors > kMaxErrorsBeforeBailing) { | 184 if (num_errors > kMaxErrorsBeforeBailing) { |
| 184 break; | 185 break; |
| 185 } | 186 } |
| 186 buffer = strtok_r(NULL, "\r\n", &save_ptr); | 187 buffer = strtok_r(NULL, "\r\n", &save_ptr); |
| 187 } | 188 } |
| 188 is_corrupt_ = num_errors > 0; | 189 is_corrupt_ = num_errors > 0; |
| 189 return true; | 190 return true; |
| 190 } | 191 } |
| 191 | 192 |
| 192 void BasicSourceLineResolver::Module::LookupAddress(StackFrame *frame) const { | 193 void BasicSourceLineResolver::Module::LookupAddress(StackFrame *frame) const { |
| 193 MemAddr address = frame->instruction - frame->module->base_address(); | 194 MemAddr address = frame->instruction - frame->module->base_address(); |
| 194 | 195 |
| 195 // First, look for a FUNC record that covers address. Use | 196 // First, look for a FUNC record that covers address. Use |
| 196 // RetrieveNearestRange instead of RetrieveRange so that, if there | 197 // RetrieveNearestRange instead of RetrieveRange so that, if there |
| 197 // is no such function, we can use the next function to bound the | 198 // is no such function, we can use the next function to bound the |
| 198 // extent of the PUBLIC symbol we find, below. This does mean we | 199 // extent of the PUBLIC symbol we find, below. This does mean we |
| 199 // need to check that address indeed falls within the function we | 200 // need to check that address indeed falls within the function we |
| 200 // find; do the range comparison in an overflow-friendly way. | 201 // find; do the range comparison in an overflow-friendly way. |
| 201 linked_ptr<Function> func; | 202 linked_ptr<Function> func; |
| 202 linked_ptr<PublicSymbol> public_symbol; | 203 linked_ptr<PublicSymbol> public_symbol; |
| 203 MemAddr function_base; | 204 MemAddr function_base; |
| 204 MemAddr function_size; | 205 MemAddr function_size; |
| 205 MemAddr public_address; | 206 MemAddr public_address; |
| 206 if (functions_.RetrieveNearestRange(address, &func, | 207 if (functions_.RetrieveNearestRange(address, &func, &function_base, |
| 207 &function_base, &function_size) && | 208 NULL /* delta */, &function_size) && |
| 208 address >= function_base && address - function_base < function_size) { | 209 address >= function_base && address - function_base < function_size) { |
| 209 frame->function_name = func->name; | 210 frame->function_name = func->name; |
| 210 frame->function_base = frame->module->base_address() + function_base; | 211 frame->function_base = frame->module->base_address() + function_base; |
| 211 | 212 |
| 212 linked_ptr<Line> line; | 213 linked_ptr<Line> line; |
| 213 MemAddr line_base; | 214 MemAddr line_base; |
| 214 if (func->lines.RetrieveRange(address, &line, &line_base, NULL)) { | 215 if (func->lines.RetrieveRange(address, &line, &line_base, NULL, NULL)) { |
| 215 FileMap::const_iterator it = files_.find(line->source_file_id); | 216 FileMap::const_iterator it = files_.find(line->source_file_id); |
| 216 if (it != files_.end()) { | 217 if (it != files_.end()) { |
| 217 frame->source_file_name = files_.find(line->source_file_id)->second; | 218 frame->source_file_name = files_.find(line->source_file_id)->second; |
| 218 } | 219 } |
| 219 frame->source_line = line->line; | 220 frame->source_line = line->line; |
| 220 frame->source_line_base = frame->module->base_address() + line_base; | 221 frame->source_line_base = frame->module->base_address() + line_base; |
| 221 } | 222 } |
| 222 } else if (public_symbols_.Retrieve(address, | 223 } else if (public_symbols_.Retrieve(address, |
| 223 &public_symbol, &public_address) && | 224 &public_symbol, &public_address) && |
| 224 (!func.get() || public_address > function_base)) { | 225 (!func.get() || public_address > function_base)) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 249 | 250 |
| 250 // Even without a relevant STACK line, many functions contain | 251 // Even without a relevant STACK line, many functions contain |
| 251 // information about how much space their parameters consume on the | 252 // information about how much space their parameters consume on the |
| 252 // stack. Use RetrieveNearestRange instead of RetrieveRange, so that | 253 // stack. Use RetrieveNearestRange instead of RetrieveRange, so that |
| 253 // we can use the function to bound the extent of the PUBLIC symbol, | 254 // we can use the function to bound the extent of the PUBLIC symbol, |
| 254 // below. However, this does mean we need to check that ADDRESS | 255 // below. However, this does mean we need to check that ADDRESS |
| 255 // falls within the retrieved function's range; do the range | 256 // falls within the retrieved function's range; do the range |
| 256 // comparison in an overflow-friendly way. | 257 // comparison in an overflow-friendly way. |
| 257 linked_ptr<Function> function; | 258 linked_ptr<Function> function; |
| 258 MemAddr function_base, function_size; | 259 MemAddr function_base, function_size; |
| 259 if (functions_.RetrieveNearestRange(address, &function, | 260 if (functions_.RetrieveNearestRange(address, &function, &function_base, |
| 260 &function_base, &function_size) && | 261 NULL /* delta */, &function_size) && |
| 261 address >= function_base && address - function_base < function_size) { | 262 address >= function_base && address - function_base < function_size) { |
| 262 result->parameter_size = function->parameter_size; | 263 result->parameter_size = function->parameter_size; |
| 263 result->valid |= WindowsFrameInfo::VALID_PARAMETER_SIZE; | 264 result->valid |= WindowsFrameInfo::VALID_PARAMETER_SIZE; |
| 264 return result.release(); | 265 return result.release(); |
| 265 } | 266 } |
| 266 | 267 |
| 267 // PUBLIC symbols might have a parameter size. Use the function we | 268 // PUBLIC symbols might have a parameter size. Use the function we |
| 268 // found above to limit the range the public symbol covers. | 269 // found above to limit the range the public symbol covers. |
| 269 linked_ptr<PublicSymbol> public_symbol; | 270 linked_ptr<PublicSymbol> public_symbol; |
| 270 MemAddr public_address; | 271 MemAddr public_address; |
| 271 if (public_symbols_.Retrieve(address, &public_symbol, &public_address) && | 272 if (public_symbols_.Retrieve(address, &public_symbol, &public_address) && |
| 272 (!function.get() || public_address > function_base)) { | 273 (!function.get() || public_address > function_base)) { |
| 273 result->parameter_size = public_symbol->parameter_size; | 274 result->parameter_size = public_symbol->parameter_size; |
| 274 } | 275 } |
| 275 | 276 |
| 276 return NULL; | 277 return NULL; |
| 277 } | 278 } |
| 278 | 279 |
| 279 CFIFrameInfo *BasicSourceLineResolver::Module::FindCFIFrameInfo( | 280 CFIFrameInfo *BasicSourceLineResolver::Module::FindCFIFrameInfo( |
| 280 const StackFrame *frame) const { | 281 const StackFrame *frame) const { |
| 281 MemAddr address = frame->instruction - frame->module->base_address(); | 282 MemAddr address = frame->instruction - frame->module->base_address(); |
| 282 MemAddr initial_base, initial_size; | 283 MemAddr initial_base, initial_size; |
| 283 string initial_rules; | 284 string initial_rules; |
| 284 | 285 |
| 285 // Find the initial rule whose range covers this address. That | 286 // Find the initial rule whose range covers this address. That |
| 286 // provides an initial set of register recovery rules. Then, walk | 287 // provides an initial set of register recovery rules. Then, walk |
| 287 // forward from the initial rule's starting address to frame's | 288 // forward from the initial rule's starting address to frame's |
| 288 // instruction address, applying delta rules. | 289 // instruction address, applying delta rules. |
| 289 if (!cfi_initial_rules_.RetrieveRange(address, &initial_rules, | 290 if (!cfi_initial_rules_.RetrieveRange(address, &initial_rules, &initial_base, |
| 290 &initial_base, &initial_size)) { | 291 NULL /* delta */, &initial_size)) { |
| 291 return NULL; | 292 return NULL; |
| 292 } | 293 } |
| 293 | 294 |
| 294 // Create a frame info structure, and populate it with the rules from | 295 // Create a frame info structure, and populate it with the rules from |
| 295 // the STACK CFI INIT record. | 296 // the STACK CFI INIT record. |
| 296 scoped_ptr<CFIFrameInfo> rules(new CFIFrameInfo()); | 297 scoped_ptr<CFIFrameInfo> rules(new CFIFrameInfo()); |
| 297 if (!ParseCFIRuleSet(initial_rules, rules.get())) | 298 if (!ParseCFIRuleSet(initial_rules, rules.get())) |
| 298 return NULL; | 299 return NULL; |
| 299 | 300 |
| 300 // Find the first delta rule that falls within the initial rule's range. | 301 // Find the first delta rule that falls within the initial rule's range. |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 442 if (!address_field) return false; | 443 if (!address_field) return false; |
| 443 | 444 |
| 444 char *size_field = strtok_r(NULL, " \r\n", &cursor); | 445 char *size_field = strtok_r(NULL, " \r\n", &cursor); |
| 445 if (!size_field) return false; | 446 if (!size_field) return false; |
| 446 | 447 |
| 447 char *initial_rules = strtok_r(NULL, "\r\n", &cursor); | 448 char *initial_rules = strtok_r(NULL, "\r\n", &cursor); |
| 448 if (!initial_rules) return false; | 449 if (!initial_rules) return false; |
| 449 | 450 |
| 450 MemAddr address = strtoul(address_field, NULL, 16); | 451 MemAddr address = strtoul(address_field, NULL, 16); |
| 451 MemAddr size = strtoul(size_field, NULL, 16); | 452 MemAddr size = strtoul(size_field, NULL, 16); |
| 452 cfi_initial_rules_.StoreRange(address, size, initial_rules); | 453 cfi_initial_rules_.StoreRange(address, 0 /* delta */, size, initial_rules); |
| 453 return true; | 454 return true; |
| 454 } | 455 } |
| 455 | 456 |
| 456 // This record has the form "STACK <address> <rules...>". | 457 // This record has the form "STACK <address> <rules...>". |
| 457 char *address_field = init_or_address; | 458 char *address_field = init_or_address; |
| 458 char *delta_rules = strtok_r(NULL, "\r\n", &cursor); | 459 char *delta_rules = strtok_r(NULL, "\r\n", &cursor); |
| 459 if (!delta_rules) return false; | 460 if (!delta_rules) return false; |
| 460 MemAddr address = strtoul(address_field, NULL, 16); | 461 MemAddr address = strtoul(address_field, NULL, 16); |
| 461 cfi_delta_rules_[address] = delta_rules; | 462 cfi_delta_rules_[address] = delta_rules; |
| 462 return true; | 463 return true; |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 if (!IsValidAfterNumber(after_number) || | 589 if (!IsValidAfterNumber(after_number) || |
| 589 *address == std::numeric_limits<unsigned long long>::max()) { | 590 *address == std::numeric_limits<unsigned long long>::max()) { |
| 590 return false; | 591 return false; |
| 591 } | 592 } |
| 592 *stack_param_size = strtol(tokens[1], &after_number, 16); | 593 *stack_param_size = strtol(tokens[1], &after_number, 16); |
| 593 if (!IsValidAfterNumber(after_number) || | 594 if (!IsValidAfterNumber(after_number) || |
| 594 *stack_param_size == std::numeric_limits<long>::max() || | 595 *stack_param_size == std::numeric_limits<long>::max() || |
| 595 *stack_param_size < 0) { | 596 *stack_param_size < 0) { |
| 596 return false; | 597 return false; |
| 597 } | 598 } |
| 598 *name = tokens[2]; | 599 *name = tokens[2]; |
| 599 | 600 |
| 600 return true; | 601 return true; |
| 601 } | 602 } |
| 602 | 603 |
| 603 // static | 604 // static |
| 604 bool SymbolParseHelper::IsValidAfterNumber(char *after_number) { | 605 bool SymbolParseHelper::IsValidAfterNumber(char *after_number) { |
| 605 if (after_number != NULL && strchr(kWhitespace, *after_number) != NULL) { | 606 if (after_number != NULL && strchr(kWhitespace, *after_number) != NULL) { |
| 606 return true; | 607 return true; |
| 607 } | 608 } |
| 608 return false; | 609 return false; |
| 609 } | 610 } |
| 610 | 611 |
| 611 } // namespace google_breakpad | 612 } // namespace google_breakpad |
| OLD | NEW |