Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(297)

Side by Side Diff: src/common/windows/pdb_source_line_writer.cc

Issue 1773183003: Windows dump_syms: Add dumping of x86_64 CFI from PDB files Base URL: https://chromium.googlesource.com/breakpad/breakpad.git@warning-fix
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/common/windows/pdb_source_line_writer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/common/windows/pdb_source_line_writer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698