aboutsummaryrefslogtreecommitdiff
path: root/src/common/windows/pdb_source_line_writer.cc
diff options
context:
space:
mode:
authorNelson Billing <nbilling@google.com>2019-06-12 14:19:57 -0700
committerNelson Billing <nbilling@google.com>2019-06-12 21:20:27 +0000
commit87bc4022100020b2d01e5e8a97e3766db6a4ce5b (patch)
treeedec3ba67f0c431c88e33a0e899c17feb2d04b91 /src/common/windows/pdb_source_line_writer.cc
parentPort new symbol upload API to Windows symupload tool. (diff)
downloadbreakpad-87bc4022100020b2d01e5e8a97e3766db6a4ce5b.tar.xz
Enable PE-only metadata dumping for 64bit (aka. PE32+ format) PEs files.
- Implement in common_windows_lib-- added class "PESourceLineWriter". - Add command-line switch to tell dump_syms to use PESourceLineWriter. Symbol data created this way will contain information to correlate the module with ones found in minidumps, along with frame info that allows much higher quality stack-walking in those minidumps. - Significant refactor of PDBSourceLineWriter-- all code concerned with extracting metadata from PE files has been moved into utility functions. This is to allow sharing of this functionality with newly- added PESourceLineWriter. - Added a unit test to dump_syms for the PE-only scenario. Change-Id: If0855f05d424d32d23f484995be5f34232179a37 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/1525325 Reviewed-by: Ivan Penkov <ivanpe@chromium.org>
Diffstat (limited to 'src/common/windows/pdb_source_line_writer.cc')
-rw-r--r--src/common/windows/pdb_source_line_writer.cc273
1 files changed, 12 insertions, 261 deletions
diff --git a/src/common/windows/pdb_source_line_writer.cc b/src/common/windows/pdb_source_line_writer.cc
index b7788ca0..4030a2e9 100644
--- a/src/common/windows/pdb_source_line_writer.cc
+++ b/src/common/windows/pdb_source_line_writer.cc
@@ -45,6 +45,7 @@
#include "common/windows/dia_util.h"
#include "common/windows/guid_string.h"
+#include "common/windows/pe_util.h"
#include "common/windows/string_utils-inl.h"
// This constant may be missing from DbgHelp.h. See the documentation for
@@ -53,56 +54,6 @@
#define UNDNAME_NO_ECSU 0x8000 // Suppresses enum/class/struct/union.
#endif // UNDNAME_NO_ECSU
-/*
- * Not defined in WinNT.h for some reason. Definitions taken from:
- * http://uninformed.org/index.cgi?v=4&a=1&p=13
- *
- */
-typedef unsigned char UBYTE;
-
-#if !defined(_WIN64)
-#define UNW_FLAG_EHANDLER 0x01
-#define UNW_FLAG_UHANDLER 0x02
-#define UNW_FLAG_CHAININFO 0x04
-#endif
-
-union UnwindCode {
- struct {
- UBYTE offset_in_prolog;
- UBYTE unwind_operation_code : 4;
- UBYTE operation_info : 4;
- };
- USHORT frame_offset;
-};
-
-enum UnwindOperationCodes {
- UWOP_PUSH_NONVOL = 0, /* info == register number */
- UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
- UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
- UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
- UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
- UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
- // XXX: these are missing from MSDN!
- // See: http://www.osronline.com/ddkx/kmarch/64bitamd_4rs7.htm
- UWOP_SAVE_XMM,
- UWOP_SAVE_XMM_FAR,
- UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */
- UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
- UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
-};
-
-// See: http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
-// Note: some fields removed as we don't use them.
-struct UnwindInfo {
- UBYTE version : 3;
- UBYTE flags : 5;
- UBYTE size_of_prolog;
- UBYTE count_of_codes;
- UBYTE frame_register : 4;
- UBYTE frame_offset : 4;
- UnwindCode unwind_code[1];
-};
-
namespace google_breakpad {
namespace {
@@ -157,21 +108,7 @@ void MaybeRecordSymbol(DWORD rva,
}
}
-// A helper class to scope a PLOADED_IMAGE.
-class AutoImage {
- public:
- explicit AutoImage(PLOADED_IMAGE img) : img_(img) {}
- ~AutoImage() {
- if (img_)
- ImageUnload(img_);
- }
- operator PLOADED_IMAGE() { return img_; }
- PLOADED_IMAGE operator->() { return img_; }
-
- private:
- PLOADED_IMAGE img_;
-};
bool SymbolsMatch(IDiaSymbol* a, IDiaSymbol* b) {
DWORD a_section, a_offset, b_section, b_offset;
@@ -223,6 +160,7 @@ PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {
}
PDBSourceLineWriter::~PDBSourceLineWriter() {
+ Close();
}
bool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) {
@@ -728,131 +666,7 @@ bool PDBSourceLineWriter::PrintFrameDataUsingEXE() {
return false;
}
- // Convert wchar to native charset because ImageLoad only takes
- // a PSTR as input.
- string code_file;
- if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) {
- return false;
- }
-
- AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL));
- if (!img) {
- fprintf(stderr, "Failed to load %s\n", code_file.c_str());
- return false;
- }
- PIMAGE_OPTIONAL_HEADER64 optional_header =
- &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
- if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- fprintf(stderr, "Not a PE32+ image\n");
- return false;
- }
-
- // Read Exception Directory
- DWORD exception_rva = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
- DWORD exception_size = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
- PIMAGE_RUNTIME_FUNCTION_ENTRY funcs =
- static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- exception_rva,
- &img->LastRvaSection));
- for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) {
- DWORD unwind_rva = funcs[i].UnwindInfoAddress;
- // handle chaining
- while (unwind_rva & 0x1) {
- unwind_rva ^= 0x1;
- PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
- static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- unwind_rva,
- &img->LastRvaSection));
- unwind_rva = chained_func->UnwindInfoAddress;
- }
-
- UnwindInfo *unwind_info = static_cast<UnwindInfo *>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- unwind_rva,
- &img->LastRvaSection));
-
- DWORD stack_size = 8; // minimal stack size is 8 for RIP
- DWORD rip_offset = 8;
- do {
- for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) {
- UnwindCode *unwind_code = &unwind_info->unwind_code[c];
- switch (unwind_code->unwind_operation_code) {
- case UWOP_PUSH_NONVOL: {
- stack_size += 8;
- break;
- }
- case UWOP_ALLOC_LARGE: {
- if (unwind_code->operation_info == 0) {
- c++;
- if (c < unwind_info->count_of_codes)
- stack_size += (unwind_code + 1)->frame_offset * 8;
- } else {
- c += 2;
- if (c < unwind_info->count_of_codes)
- stack_size += (unwind_code + 1)->frame_offset |
- ((unwind_code + 2)->frame_offset << 16);
- }
- break;
- }
- case UWOP_ALLOC_SMALL: {
- stack_size += unwind_code->operation_info * 8 + 8;
- break;
- }
- case UWOP_SET_FPREG:
- case UWOP_SAVE_XMM:
- case UWOP_SAVE_XMM_FAR:
- break;
- case UWOP_SAVE_NONVOL:
- case UWOP_SAVE_XMM128: {
- c++; // skip slot with offset
- break;
- }
- case UWOP_SAVE_NONVOL_FAR:
- case UWOP_SAVE_XMM128_FAR: {
- c += 2; // skip 2 slots with offset
- break;
- }
- case UWOP_PUSH_MACHFRAME: {
- if (unwind_code->operation_info) {
- stack_size += 88;
- } else {
- stack_size += 80;
- }
- rip_offset += 80;
- break;
- }
- }
- }
- if (unwind_info->flags & UNW_FLAG_CHAININFO) {
- PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
- reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
- (unwind_info->unwind_code +
- ((unwind_info->count_of_codes + 1) & ~1)));
-
- unwind_info = static_cast<UnwindInfo *>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- chained_func->UnwindInfoAddress,
- &img->LastRvaSection));
- } else {
- unwind_info = NULL;
- }
- } while (unwind_info);
- fprintf(output_, "STACK CFI INIT %lx %lx .cfa: $rsp .ra: .cfa %lu - ^\n",
- funcs[i].BeginAddress,
- funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset);
- fprintf(output_, "STACK CFI %lx .cfa: $rsp %lu +\n",
- funcs[i].BeginAddress, stack_size);
- }
-
- return true;
+ return PrintPEFrameData(code_file_, output_);
}
bool PDBSourceLineWriter::PrintFrameData() {
@@ -1236,8 +1050,8 @@ next_child:
return param_size;
}
-bool PDBSourceLineWriter::WriteMap(FILE *map_file) {
- output_ = map_file;
+bool PDBSourceLineWriter::WriteSymbols(FILE *symbol_file) {
+ output_ = symbol_file;
// Load the OMAP information, and disable auto-translation of addresses in
// preference of doing it ourselves.
@@ -1259,7 +1073,9 @@ bool PDBSourceLineWriter::WriteMap(FILE *map_file) {
}
void PDBSourceLineWriter::Close() {
- session_.Release();
+ if (session_ != nullptr) {
+ session_.Release();
+ }
}
bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
@@ -1284,17 +1100,7 @@ bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
// Instead, it returns one of the IMAGE_FILE_MACHINE values as
// defined here:
// http://msdn.microsoft.com/en-us/library/ms680313%28VS.85%29.aspx
- switch (machine_type) {
- case IMAGE_FILE_MACHINE_I386:
- info->cpu = L"x86";
- break;
- case IMAGE_FILE_MACHINE_AMD64:
- info->cpu = L"x86_64";
- break;
- default:
- info->cpu = L"unknown";
- break;
- }
+ info->cpu = FileHeaderMachineToCpuString(static_cast<WORD>(machine_type));
} else {
// Unexpected, but handle gracefully.
info->cpu = L"unknown";
@@ -1317,35 +1123,14 @@ bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
return false;
}
- // Use the same format that the MS symbol server uses in filesystem
- // hierarchies.
- wchar_t age_string[9];
- swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]),
- L"%x", age);
-
- // remove when VC++7.1 is no longer supported
- age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0';
-
- info->debug_identifier = GUIDString::GUIDToSymbolServerWString(&guid);
- info->debug_identifier.append(age_string);
+ info->debug_identifier = GenerateDebugIdentifier(age, guid);
} else {
DWORD signature;
if (FAILED(global->get_signature(&signature))) {
return false;
}
- // Use the same format that the MS symbol server uses in filesystem
- // hierarchies.
- wchar_t identifier_string[17];
- swprintf(identifier_string,
- sizeof(identifier_string) / sizeof(identifier_string[0]),
- L"%08X%x", signature, age);
-
- // remove when VC++7.1 is no longer supported
- identifier_string[sizeof(identifier_string) /
- sizeof(identifier_string[0]) - 1] = L'\0';
-
- info->debug_identifier = identifier_string;
+ info->debug_identifier = GenerateDebugIdentifier(age, signature);
}
CComBSTR debug_file_string;
@@ -1368,41 +1153,7 @@ bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) {
return false;
}
- // Convert wchar to native charset because ImageLoad only takes
- // a PSTR as input.
- string code_file;
- if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) {
- return false;
- }
-
- AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL));
- if (!img) {
- fprintf(stderr, "Failed to open PE file: %s\n", code_file.c_str());
- return false;
- }
-
- info->code_file = WindowsStringUtils::GetBaseName(code_file_);
-
- // The date and time that the file was created by the linker.
- DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp;
- // The size of the file in bytes, including all headers.
- DWORD SizeOfImage = 0;
- PIMAGE_OPTIONAL_HEADER64 opt =
- &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader;
- if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- // 64-bit PE file.
- SizeOfImage = opt->SizeOfImage;
- } else {
- // 32-bit PE file.
- SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage;
- }
- wchar_t code_identifier[32];
- swprintf(code_identifier,
- sizeof(code_identifier) / sizeof(code_identifier[0]),
- L"%08X%X", TimeDateStamp, SizeOfImage);
- info->code_identifier = code_identifier;
-
- return true;
+ return ReadPEInfo(code_file_, info);
}
bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) {