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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 #include <map> | 42 #include <map> |
43 #include <utility> | 43 #include <utility> |
44 #include <vector> | 44 #include <vector> |
45 | 45 |
46 #include "google_breakpad/processor/basic_source_line_resolver.h" | 46 #include "google_breakpad/processor/basic_source_line_resolver.h" |
47 #include "processor/basic_source_line_resolver_types.h" | 47 #include "processor/basic_source_line_resolver_types.h" |
48 #include "processor/module_factory.h" | 48 #include "processor/module_factory.h" |
49 | 49 |
50 #include "processor/tokenize.h" | 50 #include "processor/tokenize.h" |
51 | 51 |
| 52 #include "processor/postfix_evaluator-inl.h" |
| 53 #include <sstream> |
| 54 |
52 using std::map; | 55 using std::map; |
53 using std::vector; | 56 using std::vector; |
54 using std::make_pair; | 57 using std::make_pair; |
55 | 58 |
56 namespace google_breakpad { | 59 namespace google_breakpad { |
57 | 60 |
58 #ifdef _WIN32 | 61 #ifdef _WIN32 |
59 #define strtok_r strtok_s | 62 #define strtok_r strtok_s |
60 #define strtoull _strtoui64 | 63 #define strtoull _strtoui64 |
61 #endif | 64 #endif |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 | 133 |
131 if (strncmp(buffer, "FILE ", 5) == 0) { | 134 if (strncmp(buffer, "FILE ", 5) == 0) { |
132 if (!ParseFile(buffer)) { | 135 if (!ParseFile(buffer)) { |
133 LogParseError("ParseFile on buffer failed", line_number, &num_errors); | 136 LogParseError("ParseFile on buffer failed", line_number, &num_errors); |
134 } | 137 } |
135 } else if (strncmp(buffer, "STACK ", 6) == 0) { | 138 } else if (strncmp(buffer, "STACK ", 6) == 0) { |
136 if (!ParseStackInfo(buffer)) { | 139 if (!ParseStackInfo(buffer)) { |
137 LogParseError("ParseStackInfo failed", line_number, &num_errors); | 140 LogParseError("ParseStackInfo failed", line_number, &num_errors); |
138 } | 141 } |
139 } else if (strncmp(buffer, "FUNC ", 5) == 0) { | 142 } else if (strncmp(buffer, "FUNC ", 5) == 0) { |
140 cur_func.reset(ParseFunction(buffer)); | 143 if (strncmp(buffer + 5, "VARIABLE ", 9) == 0) { |
141 if (!cur_func.get()) { | 144 if (!cur_func.get()) { |
142 LogParseError("ParseFunction failed", line_number, &num_errors); | 145 LogParseError("Found local variable data without a function", |
| 146 line_number, &num_errors); |
| 147 } else { |
| 148 if (!ParseFunctionVariable(buffer, cur_func.get())) { |
| 149 LogParseError("ParseFunctionVariable failed", |
| 150 line_number, &num_errors); |
| 151 } |
| 152 } |
143 } else { | 153 } else { |
144 // StoreRange will fail if the function has an invalid address or size. | 154 cur_func.reset(ParseFunction(buffer)); |
145 // We'll silently ignore this, the function and any corresponding lines | 155 if (!cur_func.get()) { |
146 // will be destroyed when cur_func is released. | 156 LogParseError("ParseFunction failed", line_number, &num_errors); |
147 functions_.StoreRange(cur_func->address, cur_func->size, cur_func); | 157 } else { |
| 158 // StoreRange will fail if the function has an invalid address or |
| 159 // size. We'll silently ignore this, the function and any |
| 160 // corresponding lines will be destroyed when cur_func is released. |
| 161 functions_.StoreRange(cur_func->address, cur_func->size, cur_func); |
| 162 } |
148 } | 163 } |
149 } else if (strncmp(buffer, "PUBLIC ", 7) == 0) { | 164 } else if (strncmp(buffer, "PUBLIC ", 7) == 0) { |
150 // Clear cur_func: public symbols don't contain line number information. | 165 // Clear cur_func: public symbols don't contain line number information. |
151 cur_func.reset(); | 166 cur_func.reset(); |
152 | 167 |
153 if (!ParsePublicSymbol(buffer)) { | 168 if (!ParsePublicSymbol(buffer)) { |
154 LogParseError("ParsePublicSymbol failed", line_number, &num_errors); | 169 LogParseError("ParsePublicSymbol failed", line_number, &num_errors); |
155 } | 170 } |
156 } else if (strncmp(buffer, "MODULE ", 7) == 0) { | 171 } else if (strncmp(buffer, "MODULE ", 7) == 0) { |
157 // Ignore these. They're not of any use to BasicSourceLineResolver, | 172 // Ignore these. They're not of any use to BasicSourceLineResolver, |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 uint64_t size; | 339 uint64_t size; |
325 long stack_param_size; | 340 long stack_param_size; |
326 char *name; | 341 char *name; |
327 if (SymbolParseHelper::ParseFunction(function_line, &address, &size, | 342 if (SymbolParseHelper::ParseFunction(function_line, &address, &size, |
328 &stack_param_size, &name)) { | 343 &stack_param_size, &name)) { |
329 return new Function(name, address, size, stack_param_size); | 344 return new Function(name, address, size, stack_param_size); |
330 } | 345 } |
331 return NULL; | 346 return NULL; |
332 } | 347 } |
333 | 348 |
| 349 bool BasicSourceLineResolver::Module::ParseFunctionVariable( |
| 350 char* variable_line, |
| 351 Function* cur_func) { |
| 352 uint64_t address; |
| 353 uint64_t size; |
| 354 char* type; |
| 355 char* name; |
| 356 bool is_register_location_description; |
| 357 char* location; |
| 358 if (SymbolParseHelper::ParseFunctionVariable( |
| 359 variable_line, &address, &size, &type, &name, |
| 360 &is_register_location_description, &location)) { |
| 361 Function::Variable variable; |
| 362 variable.address = address; |
| 363 variable.size = size; |
| 364 variable.type = type; |
| 365 variable.name = name; |
| 366 variable.location = location; |
| 367 cur_func->variables.push_back(variable); |
| 368 return true; |
| 369 } |
| 370 return false; |
| 371 } |
| 372 |
334 BasicSourceLineResolver::Line* BasicSourceLineResolver::Module::ParseLine( | 373 BasicSourceLineResolver::Line* BasicSourceLineResolver::Module::ParseLine( |
335 char *line_line) { | 374 char *line_line) { |
336 uint64_t address; | 375 uint64_t address; |
337 uint64_t size; | 376 uint64_t size; |
338 long line_number; | 377 long line_number; |
339 long source_file; | 378 long source_file; |
340 | 379 |
341 if (SymbolParseHelper::ParseLine(line_line, &address, &size, &line_number, | 380 if (SymbolParseHelper::ParseLine(line_line, &address, &size, &line_number, |
342 &source_file)) { | 381 &source_file)) { |
343 return new Line(address, size, source_file, line_number); | 382 return new Line(address, size, source_file, line_number); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 | 492 |
454 // This record has the form "STACK <address> <rules...>". | 493 // This record has the form "STACK <address> <rules...>". |
455 char *address_field = init_or_address; | 494 char *address_field = init_or_address; |
456 char *delta_rules = strtok_r(NULL, "\r\n", &cursor); | 495 char *delta_rules = strtok_r(NULL, "\r\n", &cursor); |
457 if (!delta_rules) return false; | 496 if (!delta_rules) return false; |
458 MemAddr address = strtoul(address_field, NULL, 16); | 497 MemAddr address = strtoul(address_field, NULL, 16); |
459 cfi_delta_rules_[address] = delta_rules; | 498 cfi_delta_rules_[address] = delta_rules; |
460 return true; | 499 return true; |
461 } | 500 } |
462 | 501 |
| 502 void BasicSourceLineResolver::FindVariables( |
| 503 const CodeModules& code_modules, |
| 504 StackFrame* frame, |
| 505 const MemoryRegion& memory, |
| 506 const CFIFrameInfo::RegisterValueMap<uint32_t>& registers) { |
| 507 ModuleMap::const_iterator it = modules_->find(frame->module->code_file()); |
| 508 if (it == modules_->end()) |
| 509 return; |
| 510 Module* m = static_cast<Module*>(it->second); |
| 511 |
| 512 MemAddr address = frame->instruction - frame->module->base_address(); |
| 513 linked_ptr<Function> func; |
| 514 MemAddr function_base; |
| 515 MemAddr function_size; |
| 516 if (!m->functions_.RetrieveNearestRange(address, &func, |
| 517 &function_base, &function_size) || |
| 518 !(address >= function_base && address - function_base < function_size)) |
| 519 return; |
| 520 |
| 521 for (size_t i = 0; i < func->variables.size(); ++i) { |
| 522 const Function::Variable& v = func->variables[i]; |
| 523 if (address >= v.address && address - v.address < v.size) { |
| 524 CFIFrameInfo::RegisterValueMap<uint32_t> working = registers; |
| 525 PostfixEvaluator<uint32_t> evaluator(&working, &memory); |
| 526 uint32_t value_address; |
| 527 if (evaluator.EvaluateForValue(v.location, &value_address)) { |
| 528 std::string value, note; |
| 529 if (v.type.size() > 2 && |
| 530 v.type[v.type.size() - 1] == ']' && v.type.substr(0, 3) == "u8[") { |
| 531 size_t j = 0; |
| 532 int count = 0; |
| 533 for (; j < v.type.size(); ++j) { |
| 534 const char c = v.type[v.type.size() - 1 - j]; |
| 535 if (c == '[') |
| 536 break; |
| 537 int n = c - '0'; |
| 538 for (size_t k = 0; k < j; ++k) |
| 539 n *= 10; |
| 540 count += n; |
| 541 } |
| 542 for (int k = 0; k < count; ++k) { |
| 543 uint8_t x; |
| 544 if (memory.GetMemoryAtAddress(value_address + k, &x)) |
| 545 value.push_back(x); |
| 546 } |
| 547 } else if (v.type == "u8" || v.type == "s8") { |
| 548 uint8_t x; |
| 549 if (!memory.GetMemoryAtAddress(value_address, &x)) |
| 550 continue; |
| 551 ostringstream s; |
| 552 s << std::hex << "0x" << static_cast<int>(x); |
| 553 value = s.str(); |
| 554 } else if (v.type == "u16" || v.type == "s16") { |
| 555 uint16_t x; |
| 556 if (!memory.GetMemoryAtAddress(value_address, &x)) |
| 557 continue; |
| 558 ostringstream s; |
| 559 s << std::hex << "0x" << x; |
| 560 value = s.str(); |
| 561 } else if (v.type == "u32" || v.type == "s32") { |
| 562 uint32_t x; |
| 563 if (!memory.GetMemoryAtAddress(value_address, &x)) |
| 564 continue; |
| 565 ostringstream s; |
| 566 s << std::hex << "0x" << x; |
| 567 value = s.str(); |
| 568 } else if (v.type == "u64" || v.type == "s64") { |
| 569 uint64_t x; |
| 570 if (!memory.GetMemoryAtAddress(value_address, &x)) |
| 571 continue; |
| 572 ostringstream s; |
| 573 s << std::hex << "0x" << x; |
| 574 value = s.str(); |
| 575 } else { // Display as a pointer. |
| 576 uint32_t x; |
| 577 if (!memory.GetMemoryAtAddress(value_address, &x)) |
| 578 continue; |
| 579 ostringstream s; |
| 580 s << std::hex << "0x" << x; |
| 581 value = s.str(); |
| 582 |
| 583 const CodeModule* code_module = |
| 584 code_modules.GetModuleForAddress(x); |
| 585 if (code_module) { |
| 586 ModuleMap::const_iterator it2 = |
| 587 modules_->find(code_module->code_file()); |
| 588 if (it2 != modules_->end()) { |
| 589 Module* m2 = static_cast<Module*>(it2->second); |
| 590 MemAddr address = x - code_module->base_address(); |
| 591 linked_ptr<Function> func; |
| 592 MemAddr function_base = 0; |
| 593 MemAddr function_size = 0; |
| 594 if (m2->functions_.RetrieveNearestRange( |
| 595 address, &func, &function_base, &function_size) && |
| 596 address >= function_base && |
| 597 address - function_base < function_size) { |
| 598 ostringstream s; |
| 599 s << "<" << func->name << ">"; |
| 600 note = s.str(); |
| 601 } |
| 602 } |
| 603 } |
| 604 } |
| 605 StackFrame::Variable variable; |
| 606 variable.name = v.name; |
| 607 variable.value = value; |
| 608 variable.note = note; |
| 609 frame->variables.push_back(variable); |
| 610 } |
| 611 } |
| 612 } |
| 613 } |
| 614 |
463 // static | 615 // static |
464 bool SymbolParseHelper::ParseFile(char *file_line, long *index, | 616 bool SymbolParseHelper::ParseFile(char *file_line, long *index, |
465 char **filename) { | 617 char **filename) { |
466 // FILE <id> <filename> | 618 // FILE <id> <filename> |
467 assert(strncmp(file_line, "FILE ", 5) == 0); | 619 assert(strncmp(file_line, "FILE ", 5) == 0); |
468 file_line += 5; // skip prefix | 620 file_line += 5; // skip prefix |
469 | 621 |
470 vector<char*> tokens; | 622 vector<char*> tokens; |
471 if (!Tokenize(file_line, kWhitespace, 2, &tokens)) { | 623 if (!Tokenize(file_line, kWhitespace, 2, &tokens)) { |
472 return false; | 624 return false; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 *stack_param_size == std::numeric_limits<long>::max() || | 668 *stack_param_size == std::numeric_limits<long>::max() || |
517 *stack_param_size < 0) { | 669 *stack_param_size < 0) { |
518 return false; | 670 return false; |
519 } | 671 } |
520 *name = tokens[3]; | 672 *name = tokens[3]; |
521 | 673 |
522 return true; | 674 return true; |
523 } | 675 } |
524 | 676 |
525 // static | 677 // static |
| 678 bool SymbolParseHelper::ParseFunctionVariable( |
| 679 char *variable_line, |
| 680 uint64_t *address, |
| 681 uint64_t *size, |
| 682 char **type, |
| 683 char **name, |
| 684 bool *is_register_location_description, |
| 685 char **location) { |
| 686 // FUNC VARIABLE <address> <size> <type> <name> <is_register> <location> |
| 687 assert(strncmp(variable_line, "FUNC VARIABLE ", 14) == 0); |
| 688 variable_line += 14; // skip prefix |
| 689 |
| 690 vector<char*> tokens; |
| 691 if (!Tokenize(variable_line, kWhitespace, 6, &tokens)) |
| 692 return false; |
| 693 |
| 694 char *after_number; |
| 695 *address = strtoull(tokens[0], &after_number, 16); |
| 696 if (!IsValidAfterNumber(after_number) || |
| 697 *address == std::numeric_limits<unsigned long long>::max()) { |
| 698 return false; |
| 699 } |
| 700 *size = strtoull(tokens[1], &after_number, 16); |
| 701 if (!IsValidAfterNumber(after_number) || |
| 702 *size == std::numeric_limits<unsigned long long>::max()) { |
| 703 return false; |
| 704 } |
| 705 *type = tokens[2]; |
| 706 *name = tokens[3]; |
| 707 uint64_t is_register = strtoull(tokens[4], &after_number, 10); |
| 708 if (!IsValidAfterNumber(after_number) || is_register > 1) { |
| 709 return false; |
| 710 } |
| 711 *is_register_location_description = is_register; |
| 712 *location = tokens[5]; |
| 713 return true; |
| 714 } |
| 715 |
| 716 // static |
526 bool SymbolParseHelper::ParseLine(char *line_line, uint64_t *address, | 717 bool SymbolParseHelper::ParseLine(char *line_line, uint64_t *address, |
527 uint64_t *size, long *line_number, | 718 uint64_t *size, long *line_number, |
528 long *source_file) { | 719 long *source_file) { |
529 // <address> <size> <line number> <source file id> | 720 // <address> <size> <line number> <source file id> |
530 vector<char*> tokens; | 721 vector<char*> tokens; |
531 if (!Tokenize(line_line, kWhitespace, 4, &tokens)) { | 722 if (!Tokenize(line_line, kWhitespace, 4, &tokens)) { |
532 return false; | 723 return false; |
533 } | 724 } |
534 | 725 |
535 char *after_number; | 726 char *after_number; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
600 | 791 |
601 // static | 792 // static |
602 bool SymbolParseHelper::IsValidAfterNumber(char *after_number) { | 793 bool SymbolParseHelper::IsValidAfterNumber(char *after_number) { |
603 if (after_number != NULL && strchr(kWhitespace, *after_number) != NULL) { | 794 if (after_number != NULL && strchr(kWhitespace, *after_number) != NULL) { |
604 return true; | 795 return true; |
605 } | 796 } |
606 return false; | 797 return false; |
607 } | 798 } |
608 | 799 |
609 } // namespace google_breakpad | 800 } // namespace google_breakpad |
OLD | NEW |