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 19 matching lines...) Expand all Loading... |
30 #include "common/windows/pdb_source_line_writer.h" | 30 #include "common/windows/pdb_source_line_writer.h" |
31 | 31 |
32 #include <windows.h> | 32 #include <windows.h> |
33 #include <winnt.h> | 33 #include <winnt.h> |
34 #include <atlbase.h> | 34 #include <atlbase.h> |
35 #include <dia2.h> | 35 #include <dia2.h> |
36 #include <diacreate.h> | 36 #include <diacreate.h> |
37 #include <ImageHlp.h> | 37 #include <ImageHlp.h> |
38 #include <stdio.h> | 38 #include <stdio.h> |
39 | 39 |
| 40 #include <cassert> |
40 #include <limits> | 41 #include <limits> |
41 #include <set> | 42 #include <set> |
42 | 43 |
43 #include "common/windows/dia_util.h" | 44 #include "common/windows/dia_util.h" |
44 #include "common/windows/guid_string.h" | 45 #include "common/windows/guid_string.h" |
45 #include "common/windows/string_utils-inl.h" | 46 #include "common/windows/string_utils-inl.h" |
46 | 47 |
47 // This constant may be missing from DbgHelp.h. See the documentation for | 48 // This constant may be missing from DbgHelp.h. See the documentation for |
48 // IDiaSymbol::get_undecoratedNameEx. | 49 // IDiaSymbol::get_undecoratedNameEx. |
49 #ifndef UNDNAME_NO_ECSU | 50 #ifndef UNDNAME_NO_ECSU |
(...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 last_code_size = code_size; | 680 last_code_size = code_size; |
680 last_prolog_size = prolog_size; | 681 last_prolog_size = prolog_size; |
681 } | 682 } |
682 | 683 |
683 frame_data.Release(); | 684 frame_data.Release(); |
684 } | 685 } |
685 | 686 |
686 return true; | 687 return true; |
687 } | 688 } |
688 | 689 |
689 bool PDBSourceLineWriter::PrintFrameDataUsingEXE() { | 690 // Prints CFI from xdata/pdata |
690 if (code_file_.empty() && !FindPEFile()) { | 691 // |
691 fprintf(stderr, "Couldn't locate EXE or DLL file.\n"); | 692 // Performing the translation of RVA to a real pointer is very different for a |
692 return false; | 693 // XDATA/PDATA streams read from a PDB, and XDATA/PDATA found in the loaded |
693 } | 694 // image of an executable, so we specialize this function for each case with |
| 695 // RvaToVaTraits |
| 696 // |
| 697 template <typename RvaToVaTraits> |
| 698 static bool PrintCFIFromXData(FILE *output, PVOID pdata, size_t pdata_size, |
| 699 const typename RvaToVaTraits &t) { |
| 700 PIMAGE_RUNTIME_FUNCTION_ENTRY funcs = |
| 701 static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(pdata); |
694 | 702 |
695 // Convert wchar to native charset because ImageLoad only takes | 703 for (size_t i = 0; i < pdata_size / sizeof(*funcs) ; i++) { |
696 // a PSTR as input. | |
697 string code_file; | |
698 if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) { | |
699 return false; | |
700 } | |
701 | |
702 AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL)); | |
703 if (!img) { | |
704 fprintf(stderr, "Failed to load %s\n", code_file.c_str()); | |
705 return false; | |
706 } | |
707 PIMAGE_OPTIONAL_HEADER64 optional_header = | |
708 &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader; | |
709 if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { | |
710 fprintf(stderr, "Not a PE32+ image\n"); | |
711 return false; | |
712 } | |
713 | |
714 // Read Exception Directory | |
715 DWORD exception_rva = optional_header-> | |
716 DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress; | |
717 DWORD exception_size = optional_header-> | |
718 DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size; | |
719 PIMAGE_RUNTIME_FUNCTION_ENTRY funcs = | |
720 static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>( | |
721 ImageRvaToVa(img->FileHeader, | |
722 img->MappedAddress, | |
723 exception_rva, | |
724 &img->LastRvaSection)); | |
725 for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) { | |
726 DWORD unwind_rva = funcs[i].UnwindInfoAddress; | 704 DWORD unwind_rva = funcs[i].UnwindInfoAddress; |
727 // handle chaining | 705 // handle chaining |
728 while (unwind_rva & 0x1) { | 706 while (unwind_rva & 0x1) { |
729 unwind_rva ^= 0x1; | 707 unwind_rva ^= 0x1; |
730 PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func = | 708 PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func = |
731 static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>( | 709 static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>( |
732 ImageRvaToVa(img->FileHeader, | 710 t.PDataRvaToVa(unwind_rva)); |
733 img->MappedAddress, | |
734 unwind_rva, | |
735 &img->LastRvaSection)); | |
736 unwind_rva = chained_func->UnwindInfoAddress; | 711 unwind_rva = chained_func->UnwindInfoAddress; |
737 } | 712 } |
738 | 713 |
739 UnwindInfo *unwind_info = static_cast<UnwindInfo *>( | 714 UnwindInfo *unwind_info = static_cast<UnwindInfo *>( |
740 ImageRvaToVa(img->FileHeader, | 715 t.XDataRvaToVa(unwind_rva)); |
741 img->MappedAddress, | |
742 unwind_rva, | |
743 &img->LastRvaSection)); | |
744 | 716 |
745 DWORD stack_size = 8; // minimal stack size is 8 for RIP | 717 DWORD stack_size = 8; // minimal stack size is 8 for RIP |
746 DWORD rip_offset = 8; | 718 DWORD rip_offset = 8; |
747 do { | 719 do { |
748 for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) { | 720 for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) { |
749 UnwindCode *unwind_code = &unwind_info->unwind_code[c]; | 721 UnwindCode *unwind_code = &unwind_info->unwind_code[c]; |
750 switch (unwind_code->unwind_operation_code) { | 722 switch (unwind_code->unwind_operation_code) { |
751 case UWOP_PUSH_NONVOL: { | 723 case UWOP_PUSH_NONVOL: { |
752 stack_size += 8; | 724 stack_size += 8; |
753 break; | 725 break; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
788 stack_size += 88; | 760 stack_size += 88; |
789 } else { | 761 } else { |
790 stack_size += 80; | 762 stack_size += 80; |
791 } | 763 } |
792 rip_offset += 80; | 764 rip_offset += 80; |
793 break; | 765 break; |
794 } | 766 } |
795 } | 767 } |
796 } | 768 } |
797 if (unwind_info->flags & UNW_FLAG_CHAININFO) { | 769 if (unwind_info->flags & UNW_FLAG_CHAININFO) { |
| 770 // unwind_code[] is followed by an IMAGE_RUNTIME_FUNCTION_ENTRY |
798 PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func = | 771 PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func = |
799 reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>( | 772 reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>( |
800 (unwind_info->unwind_code + | 773 (unwind_info->unwind_code + |
801 ((unwind_info->count_of_codes + 1) & ~1))); | 774 ((unwind_info->count_of_codes + 1) & ~1))); |
802 | 775 |
803 unwind_info = static_cast<UnwindInfo *>( | 776 unwind_info = static_cast<UnwindInfo *>( |
804 ImageRvaToVa(img->FileHeader, | 777 t.XDataRvaToVa(chained_func->UnwindInfoAddress)); |
805 img->MappedAddress, | |
806 chained_func->UnwindInfoAddress, | |
807 &img->LastRvaSection)); | |
808 } else { | 778 } else { |
809 unwind_info = NULL; | 779 unwind_info = NULL; |
810 } | 780 } |
811 } while (unwind_info); | 781 } while (unwind_info); |
812 fprintf(output_, "STACK CFI INIT %x %x .cfa: $rsp .ra: .cfa %d - ^\n", | 782 fprintf(output, "STACK CFI INIT %x %x .cfa: $rsp .ra: .cfa %d - ^\n", |
813 funcs[i].BeginAddress, | 783 funcs[i].BeginAddress, |
814 funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset); | 784 funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset); |
815 fprintf(output_, "STACK CFI %x .cfa: $rsp %d +\n", | 785 fprintf(output, "STACK CFI %x .cfa: $rsp %d +\n", |
816 funcs[i].BeginAddress, stack_size); | 786 funcs[i].BeginAddress, stack_size); |
817 } | 787 } |
818 | 788 |
819 return true; | 789 return true; |
820 } | 790 } |
821 | 791 |
| 792 // In a LOADED_IMAGE, we can simply use ImageRvaToVa() to translate RVAs |
| 793 class ImageRvaToVaTraits { |
| 794 public: |
| 795 ImageRvaToVaTraits(PLOADED_IMAGE img) |
| 796 : img_(img) |
| 797 { |
| 798 }; |
| 799 |
| 800 PVOID XDataRvaToVa(DWORD rva) const { |
| 801 return ImageRvaToVa(img_->FileHeader, |
| 802 img_->MappedAddress, |
| 803 rva, |
| 804 &img_->LastRvaSection); |
| 805 }; |
| 806 |
| 807 PVOID PDataRvaToVa(DWORD rva) const { |
| 808 return ImageRvaToVa(img_->FileHeader, |
| 809 img_->MappedAddress, |
| 810 rva, |
| 811 &img_->LastRvaSection); |
| 812 }; |
| 813 |
| 814 private: |
| 815 PLOADED_IMAGE img_; |
| 816 }; |
| 817 |
| 818 bool PDBSourceLineWriter::PrintFrameDataUsingEXE() { |
| 819 if (code_file_.empty() && !FindPEFile()) { |
| 820 fprintf(stderr, "Couldn't locate EXE or DLL file.\n"); |
| 821 return false; |
| 822 } |
| 823 |
| 824 // Convert wchar to native charset because ImageLoad only takes |
| 825 // a PSTR as input. |
| 826 string code_file; |
| 827 if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) { |
| 828 return false; |
| 829 } |
| 830 |
| 831 AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL)); |
| 832 if (!img) { |
| 833 fprintf(stderr, "Failed to load %s\n", code_file.c_str()); |
| 834 return false; |
| 835 } |
| 836 PIMAGE_OPTIONAL_HEADER64 optional_header = |
| 837 &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader; |
| 838 if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { |
| 839 fprintf(stderr, "Not a PE32+ image\n"); |
| 840 return false; |
| 841 } |
| 842 |
| 843 // Read Exception Directory |
| 844 DWORD exception_rva = optional_header-> |
| 845 DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress; |
| 846 DWORD exception_size = optional_header-> |
| 847 DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size; |
| 848 |
| 849 PVOID pdata = static_cast<PVOID>( |
| 850 ImageRvaToVa(img->FileHeader, |
| 851 img->MappedAddress, |
| 852 exception_rva, |
| 853 &img->LastRvaSection)); |
| 854 |
| 855 ImageRvaToVaTraits t(img); |
| 856 |
| 857 return PrintCFIFromXData(output_, pdata, exception_size, t); |
| 858 } |
| 859 |
| 860 // We have the XDATA/PDATA streams from the PDB, along with their base RVAs |
| 861 // provided by IDiaImageData. It is assumed that all the RVAs we access lie |
| 862 // within the range of RVAs covered by the stream. |
| 863 class PdbRvaToVaTraits { |
| 864 public: |
| 865 PdbRvaToVaTraits(PVOID pdata, size_t pdata_size, DWORD pdata_base_rva, |
| 866 PVOID xdata, size_t xdata_size, DWORD xdata_base_rva) |
| 867 : pdata_(pdata), pdata_size_(pdata_size), pdata_base_rva_(pdata_base_rva), |
| 868 xdata_(xdata), xdata_size_(xdata_size), xdata_base_rva_(xdata_base_rva) |
| 869 { |
| 870 }; |
| 871 |
| 872 PVOID XDataRvaToVa(DWORD rva) const { |
| 873 assert(rva >= xdata_base_rva_); |
| 874 assert(rva < xdata_base_rva_ + xdata_size_); |
| 875 |
| 876 return rva - xdata_base_rva_ + static_cast<PBYTE>(xdata_); |
| 877 }; |
| 878 |
| 879 PVOID PDataRvaToVa(DWORD rva) const { |
| 880 assert(rva >= pdata_base_rva_); |
| 881 assert(rva < pdata_base_rva_ + pdata_size_); |
| 882 |
| 883 return rva - pdata_base_rva_ + static_cast<PBYTE>(pdata_); |
| 884 }; |
| 885 |
| 886 private: |
| 887 PVOID pdata_; |
| 888 size_t pdata_size_; |
| 889 DWORD pdata_base_rva_; |
| 890 PVOID xdata_; |
| 891 size_t xdata_size_; |
| 892 DWORD xdata_base_rva_; |
| 893 }; |
| 894 |
| 895 bool PDBSourceLineWriter::PrintFrameDataUsingPDBXData() { |
| 896 static const wchar_t kPdataStreamName[] = L"PDATA"; |
| 897 static const wchar_t kXdataStreamName[] = L"XDATA"; |
| 898 |
| 899 std::vector<BYTE> pdata; |
| 900 std::vector<BYTE> xdata; |
| 901 DWORD pdata_base_rva; |
| 902 DWORD xdata_base_rva; |
| 903 |
| 904 if (FindAndLoadDebugStream(kPdataStreamName, session_, &pdata, |
| 905 &pdata_base_rva) && pdata_base_rva && |
| 906 FindAndLoadDebugStream(kXdataStreamName, session_, &xdata, |
| 907 &xdata_base_rva) && xdata_base_rva) { |
| 908 |
| 909 PdbRvaToVaTraits t(&pdata[0], pdata.size(), pdata_base_rva, |
| 910 &xdata[0], xdata.size(), xdata_base_rva); |
| 911 |
| 912 return PrintCFIFromXData(output_, &pdata[0], pdata.size(), t); |
| 913 } |
| 914 |
| 915 return false; |
| 916 } |
| 917 |
822 bool PDBSourceLineWriter::PrintFrameData() { | 918 bool PDBSourceLineWriter::PrintFrameData() { |
823 PDBModuleInfo info; | 919 PDBModuleInfo info; |
824 if (GetModuleInfo(&info) && info.cpu == L"x86_64") { | 920 if (GetModuleInfo(&info) && info.cpu == L"x86_64") { |
| 921 // Print CFI using .pdata/.xdata streams in PDB |
| 922 if (PrintFrameDataUsingPDBXData()) |
| 923 return true; |
| 924 // If they are not present, fall-back to reading the .pdata/.xdata from the |
| 925 // corresponding PE/COFF executable, if we can find it. |
825 return PrintFrameDataUsingEXE(); | 926 return PrintFrameDataUsingEXE(); |
826 } else { | 927 } else { |
827 return PrintFrameDataUsingPDB(); | 928 return PrintFrameDataUsingPDB(); |
828 } | 929 } |
829 return false; | 930 return false; |
830 } | 931 } |
831 | 932 |
832 bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) { | 933 bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) { |
833 BOOL is_code; | 934 BOOL is_code; |
834 if (FAILED(symbol->get_code(&is_code))) { | 935 if (FAILED(symbol->get_code(&is_code))) { |
(...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1350 // an old-style CodeView record if a real 128-bit GUID has its first 32 | 1451 // an old-style CodeView record if a real 128-bit GUID has its first 32 |
1351 // bits set the same as the module's signature (timestamp) and the rest of | 1452 // bits set the same as the module's signature (timestamp) and the rest of |
1352 // the GUID is set to 0. This is highly unlikely. | 1453 // the GUID is set to 0. This is highly unlikely. |
1353 | 1454 |
1354 GUID signature_guid = {signature}; // 0-initializes other members | 1455 GUID signature_guid = {signature}; // 0-initializes other members |
1355 *uses_guid = !IsEqualGUID(guid, signature_guid); | 1456 *uses_guid = !IsEqualGUID(guid, signature_guid); |
1356 return true; | 1457 return true; |
1357 } | 1458 } |
1358 | 1459 |
1359 } // namespace google_breakpad | 1460 } // namespace google_breakpad |
OLD | NEW |