OLD | NEW |
1 // Copyright (c) 2006, Google Inc. | 1 // Copyright (c) 2006, 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 10 matching lines...) Expand all Loading... |
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | 29 |
30 #include <atlbase.h> | 30 #include <atlbase.h> |
31 #include <DbgHelp.h> | |
32 #include <dia2.h> | 31 #include <dia2.h> |
| 32 #include <ImageHlp.h> |
33 #include <stdio.h> | 33 #include <stdio.h> |
34 | 34 |
35 #include "common/windows/string_utils-inl.h" | 35 #include "common/windows/string_utils-inl.h" |
36 | 36 |
37 #include "common/windows/pdb_source_line_writer.h" | 37 #include "common/windows/pdb_source_line_writer.h" |
38 #include "common/windows/guid_string.h" | 38 #include "common/windows/guid_string.h" |
39 | 39 |
40 // This constant may be missing from DbgHelp.h. See the documentation for | 40 // This constant may be missing from DbgHelp.h. See the documentation for |
41 // IDiaSymbol::get_undecoratedNameEx. | 41 // IDiaSymbol::get_undecoratedNameEx. |
42 #ifndef UNDNAME_NO_ECSU | 42 #ifndef UNDNAME_NO_ECSU |
43 #define UNDNAME_NO_ECSU 0x8000 // Suppresses enum/class/struct/union. | 43 #define UNDNAME_NO_ECSU 0x8000 // Suppresses enum/class/struct/union. |
44 #endif // UNDNAME_NO_ECSU | 44 #endif // UNDNAME_NO_ECSU |
45 | 45 |
46 namespace google_breakpad { | 46 namespace google_breakpad { |
47 | 47 |
| 48 using std::vector; |
| 49 |
| 50 // A helper class to scope a PLOADED_IMAGE. |
| 51 class AutoImage { |
| 52 public: |
| 53 explicit AutoImage(PLOADED_IMAGE img) : img_(img) {} |
| 54 ~AutoImage() { |
| 55 if (img_) |
| 56 ImageUnload(img_); |
| 57 } |
| 58 |
| 59 operator PLOADED_IMAGE() { return img_; } |
| 60 PLOADED_IMAGE operator->() { return img_; } |
| 61 |
| 62 private: |
| 63 PLOADED_IMAGE img_; |
| 64 }; |
| 65 |
48 PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) { | 66 PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) { |
49 } | 67 } |
50 | 68 |
51 PDBSourceLineWriter::~PDBSourceLineWriter() { | 69 PDBSourceLineWriter::~PDBSourceLineWriter() { |
52 } | 70 } |
53 | 71 |
54 bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) { | 72 bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) { |
55 Close(); | 73 Close(); |
56 | 74 |
57 if (FAILED(CoInitialize(NULL))) { | 75 if (FAILED(CoInitialize(NULL))) { |
(...skipping 13 matching lines...) Expand all Loading... |
71 if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { | 89 if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { |
72 fprintf(stderr, "loadDataFromPdb failed\n"); | 90 fprintf(stderr, "loadDataFromPdb failed\n"); |
73 return false; | 91 return false; |
74 } | 92 } |
75 break; | 93 break; |
76 case EXE_FILE: | 94 case EXE_FILE: |
77 if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { | 95 if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { |
78 fprintf(stderr, "loadDataForExe failed\n"); | 96 fprintf(stderr, "loadDataForExe failed\n"); |
79 return false; | 97 return false; |
80 } | 98 } |
| 99 code_file_ = file; |
81 break; | 100 break; |
82 case ANY_FILE: | 101 case ANY_FILE: |
83 if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { | 102 if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { |
84 if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { | 103 if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { |
85 fprintf(stderr, "loadDataForPdb and loadDataFromExe failed\n"); | 104 fprintf(stderr, "loadDataForPdb and loadDataFromExe failed\n"); |
86 return false; | 105 return false; |
87 } | 106 } |
| 107 code_file_ = file; |
88 } | 108 } |
89 break; | 109 break; |
90 default: | 110 default: |
91 fprintf(stderr, "Unknown file format\n"); | 111 fprintf(stderr, "Unknown file format\n"); |
92 return false; | 112 return false; |
93 } | 113 } |
94 | 114 |
95 if (FAILED(data_source->openSession(&session_))) { | 115 if (FAILED(data_source->openSession(&session_))) { |
96 fprintf(stderr, "openSession failed\n"); | 116 fprintf(stderr, "openSession failed\n"); |
97 } | 117 } |
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 // Hard-code "windows" for the OS because that's the only thing that makes | 511 // Hard-code "windows" for the OS because that's the only thing that makes |
492 // sense for PDB files. (This might not be strictly correct for Windows CE | 512 // sense for PDB files. (This might not be strictly correct for Windows CE |
493 // support, but we don't care about that at the moment.) | 513 // support, but we don't care about that at the moment.) |
494 fprintf(output_, "MODULE windows %ws %ws %ws\n", | 514 fprintf(output_, "MODULE windows %ws %ws %ws\n", |
495 info.cpu.c_str(), info.debug_identifier.c_str(), | 515 info.cpu.c_str(), info.debug_identifier.c_str(), |
496 info.debug_file.c_str()); | 516 info.debug_file.c_str()); |
497 | 517 |
498 return true; | 518 return true; |
499 } | 519 } |
500 | 520 |
| 521 bool PDBSourceLineWriter::PrintPEInfo() { |
| 522 PEModuleInfo info; |
| 523 if (!GetPEInfo(&info)) { |
| 524 return false; |
| 525 } |
| 526 |
| 527 fprintf(output_, "INFO CODE_ID %ws %ws\n", |
| 528 info.code_identifier.c_str(), |
| 529 info.code_file.c_str()); |
| 530 return true; |
| 531 } |
| 532 |
501 // wcstol_positive_strict is sort of like wcstol, but much stricter. string | 533 // wcstol_positive_strict is sort of like wcstol, but much stricter. string |
502 // should be a buffer pointing to a null-terminated string containing only | 534 // should be a buffer pointing to a null-terminated string containing only |
503 // decimal digits. If the entire string can be converted to an integer | 535 // decimal digits. If the entire string can be converted to an integer |
504 // without overflowing, and there are no non-digit characters before the | 536 // without overflowing, and there are no non-digit characters before the |
505 // result is set to the value and this function returns true. Otherwise, | 537 // result is set to the value and this function returns true. Otherwise, |
506 // this function returns false. This is an alternative to the strtol, atoi, | 538 // this function returns false. This is an alternative to the strtol, atoi, |
507 // and scanf families, which are not as strict about input and in some cases | 539 // and scanf families, which are not as strict about input and in some cases |
508 // don't provide a good way for the caller to determine if a conversion was | 540 // don't provide a good way for the caller to determine if a conversion was |
509 // successful. | 541 // successful. |
510 static bool wcstol_positive_strict(wchar_t *string, int *result) { | 542 static bool wcstol_positive_strict(wchar_t *string, int *result) { |
(...skipping 17 matching lines...) Expand all Loading... |
528 } | 560 } |
529 // Forbid leading zeroes unless the string is just "0". | 561 // Forbid leading zeroes unless the string is just "0". |
530 if (value == 0 && *(c+1) != '\0') { | 562 if (value == 0 && *(c+1) != '\0') { |
531 return false; | 563 return false; |
532 } | 564 } |
533 } | 565 } |
534 *result = value; | 566 *result = value; |
535 return true; | 567 return true; |
536 } | 568 } |
537 | 569 |
| 570 bool PDBSourceLineWriter::FindPEFile() { |
| 571 CComPtr<IDiaSymbol> global; |
| 572 if (FAILED(session_->get_globalScope(&global))) { |
| 573 fprintf(stderr, "get_globalScope failed\n"); |
| 574 return false; |
| 575 } |
| 576 |
| 577 CComBSTR symbols_file; |
| 578 if (SUCCEEDED(global->get_symbolsFileName(&symbols_file))) { |
| 579 wstring file(symbols_file); |
| 580 |
| 581 // Look for an EXE or DLL file. |
| 582 const wchar_t *extensions[] = { L"exe", L"dll" }; |
| 583 for (int i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) { |
| 584 size_t dot_pos = file.find_last_of(L"."); |
| 585 if (dot_pos != wstring::npos) { |
| 586 file.replace(dot_pos + 1, wstring::npos, extensions[i]); |
| 587 // Check if this file exists. |
| 588 if (GetFileAttributesW(file.c_str()) != INVALID_FILE_ATTRIBUTES) { |
| 589 code_file_ = file; |
| 590 return true; |
| 591 } |
| 592 } |
| 593 } |
| 594 } |
| 595 |
| 596 return false; |
| 597 } |
| 598 |
538 // static | 599 // static |
539 bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function, | 600 bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function, |
540 BSTR *name, | 601 BSTR *name, |
541 int *stack_param_size) { | 602 int *stack_param_size) { |
542 *stack_param_size = -1; | 603 *stack_param_size = -1; |
543 const DWORD undecorate_options = UNDNAME_NO_MS_KEYWORDS | | 604 const DWORD undecorate_options = UNDNAME_NO_MS_KEYWORDS | |
544 UNDNAME_NO_FUNCTION_RETURNS | | 605 UNDNAME_NO_FUNCTION_RETURNS | |
545 UNDNAME_NO_ALLOCATION_MODEL | | 606 UNDNAME_NO_ALLOCATION_MODEL | |
546 UNDNAME_NO_ALLOCATION_LANGUAGE | | 607 UNDNAME_NO_ALLOCATION_LANGUAGE | |
547 UNDNAME_NO_THISTYPE | | 608 UNDNAME_NO_THISTYPE | |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
730 | 791 |
731 param_size = highest_end - lowest_base; | 792 param_size = highest_end - lowest_base; |
732 } | 793 } |
733 | 794 |
734 return param_size; | 795 return param_size; |
735 } | 796 } |
736 | 797 |
737 bool PDBSourceLineWriter::WriteMap(FILE *map_file) { | 798 bool PDBSourceLineWriter::WriteMap(FILE *map_file) { |
738 output_ = map_file; | 799 output_ = map_file; |
739 | 800 |
740 bool ret = PrintPDBInfo() && | 801 bool ret = PrintPDBInfo(); |
741 PrintSourceFiles() && | 802 // TODO(ted): This is currently disabled to allow Breakpad users to update |
742 PrintFunctions() && | 803 // processing infrastructure. |
743 PrintFrameData(); | 804 // This is not a critical piece of the symbol file. |
| 805 // PrintPEInfo(); |
| 806 ret = ret && |
| 807 PrintSourceFiles() && |
| 808 PrintFunctions() && |
| 809 PrintFrameData(); |
744 | 810 |
745 output_ = NULL; | 811 output_ = NULL; |
746 return ret; | 812 return ret; |
747 } | 813 } |
748 | 814 |
749 void PDBSourceLineWriter::Close() { | 815 void PDBSourceLineWriter::Close() { |
750 session_.Release(); | 816 session_.Release(); |
751 } | 817 } |
752 | 818 |
753 bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) { | 819 bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) { |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
839 CComBSTR debug_file_string; | 905 CComBSTR debug_file_string; |
840 if (FAILED(global->get_symbolsFileName(&debug_file_string))) { | 906 if (FAILED(global->get_symbolsFileName(&debug_file_string))) { |
841 return false; | 907 return false; |
842 } | 908 } |
843 info->debug_file = | 909 info->debug_file = |
844 WindowsStringUtils::GetBaseName(wstring(debug_file_string)); | 910 WindowsStringUtils::GetBaseName(wstring(debug_file_string)); |
845 | 911 |
846 return true; | 912 return true; |
847 } | 913 } |
848 | 914 |
| 915 bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) { |
| 916 if (!info) { |
| 917 return false; |
| 918 } |
| 919 |
| 920 if (code_file_.empty() && !FindPEFile()) { |
| 921 fprintf(stderr, "Couldn't locate EXE or DLL file.\n"); |
| 922 return false; |
| 923 } |
| 924 |
| 925 // Convert wchar to native charset because ImageLoad only takes |
| 926 // a PSTR as input. |
| 927 string code_file; |
| 928 if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) { |
| 929 return false; |
| 930 } |
| 931 |
| 932 AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL)); |
| 933 if (!img) { |
| 934 fprintf(stderr, "Failed to open PE file: %s\n", code_file.c_str()); |
| 935 return false; |
| 936 } |
| 937 |
| 938 info->code_file = WindowsStringUtils::GetBaseName(code_file_); |
| 939 |
| 940 // The date and time that the file was created by the linker. |
| 941 DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp; |
| 942 // The size of the file in bytes, including all headers. |
| 943 DWORD SizeOfImage = 0; |
| 944 PIMAGE_OPTIONAL_HEADER64 opt = |
| 945 &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader; |
| 946 if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { |
| 947 // 64-bit PE file. |
| 948 SizeOfImage = opt->SizeOfImage; |
| 949 } |
| 950 else { |
| 951 // 32-bit PE file. |
| 952 SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage; |
| 953 } |
| 954 wchar_t code_identifier[32]; |
| 955 swprintf(code_identifier, |
| 956 sizeof(code_identifier) / sizeof(code_identifier[0]), |
| 957 L"%08X%X", TimeDateStamp, SizeOfImage); |
| 958 info->code_identifier = code_identifier; |
| 959 |
| 960 return true; |
| 961 } |
| 962 |
849 bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) { | 963 bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) { |
850 if (!uses_guid) | 964 if (!uses_guid) |
851 return false; | 965 return false; |
852 | 966 |
853 CComPtr<IDiaSymbol> global; | 967 CComPtr<IDiaSymbol> global; |
854 if (FAILED(session_->get_globalScope(&global))) | 968 if (FAILED(session_->get_globalScope(&global))) |
855 return false; | 969 return false; |
856 | 970 |
857 GUID guid; | 971 GUID guid; |
858 if (FAILED(global->get_guid(&guid))) | 972 if (FAILED(global->get_guid(&guid))) |
(...skipping 16 matching lines...) Expand all Loading... |
875 // an old-style CodeView record if a real 128-bit GUID has its first 32 | 989 // an old-style CodeView record if a real 128-bit GUID has its first 32 |
876 // bits set the same as the module's signature (timestamp) and the rest of | 990 // bits set the same as the module's signature (timestamp) and the rest of |
877 // the GUID is set to 0. This is highly unlikely. | 991 // the GUID is set to 0. This is highly unlikely. |
878 | 992 |
879 GUID signature_guid = {signature}; // 0-initializes other members | 993 GUID signature_guid = {signature}; // 0-initializes other members |
880 *uses_guid = !IsEqualGUID(guid, signature_guid); | 994 *uses_guid = !IsEqualGUID(guid, signature_guid); |
881 return true; | 995 return true; |
882 } | 996 } |
883 | 997 |
884 } // namespace google_breakpad | 998 } // namespace google_breakpad |
OLD | NEW |