pdb_source_line_writer.cc.svn-base
来自「SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多K」· SVN-BASE 代码 · 共 801 行 · 第 1/2 页
SVN-BASE
801 行
// Copyright (c) 2006, Google Inc.// All rights reserved.//// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following disclaimer// in the documentation and/or other materials provided with the// distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#include <atlbase.h>#include <DbgHelp.h>#include <dia2.h>#include <stdio.h>#include "common/windows/string_utils-inl.h"#include "common/windows/pdb_source_line_writer.h"#include "common/windows/guid_string.h"// This constant may be missing from DbgHelp.h. See the documentation for// IDiaSymbol::get_undecoratedNameEx.#ifndef UNDNAME_NO_ECSU#define UNDNAME_NO_ECSU 0x8000 // Suppresses enum/class/struct/union.#endif // UNDNAME_NO_ECSUnamespace google_breakpad {PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {}PDBSourceLineWriter::~PDBSourceLineWriter() {}bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) { Close(); if (FAILED(CoInitialize(NULL))) { fprintf(stderr, "CoInitialize failed\n"); return false; } CComPtr<IDiaDataSource> data_source; if (FAILED(data_source.CoCreateInstance(CLSID_DiaSource))) { fprintf(stderr, "CoCreateInstance CLSID_DiaSource failed " "(msdia80.dll unregistered?)\n"); return false; } switch (format) { case PDB_FILE: if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { fprintf(stderr, "loadDataFromPdb failed\n"); return false; } break; case EXE_FILE: if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { fprintf(stderr, "loadDataForExe failed\n"); return false; } break; case ANY_FILE: if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { fprintf(stderr, "loadDataForPdb and loadDataFromExe failed\n"); return false; } } break; default: fprintf(stderr, "Unknown file format\n"); return false; } if (FAILED(data_source->openSession(&session_))) { fprintf(stderr, "openSession failed\n"); } return true;}bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) { // The line number format is: // <rva> <line number> <source file id> CComPtr<IDiaLineNumber> line; ULONG count; while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) { DWORD rva; if (FAILED(line->get_relativeVirtualAddress(&rva))) { fprintf(stderr, "failed to get line rva\n"); return false; } DWORD length; if (FAILED(line->get_length(&length))) { fprintf(stderr, "failed to get line code length\n"); return false; } DWORD source_id; if (FAILED(line->get_sourceFileId(&source_id))) { fprintf(stderr, "failed to get line source file id\n"); return false; } DWORD line_num; if (FAILED(line->get_lineNumber(&line_num))) { fprintf(stderr, "failed to get line number\n"); return false; } fprintf(output_, "%x %x %d %d\n", rva, length, line_num, source_id); line.Release(); } return true;}bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function) { // The function format is: // FUNC <address> <length> <param_stack_size> <function> DWORD rva; if (FAILED(function->get_relativeVirtualAddress(&rva))) { fprintf(stderr, "couldn't get rva\n"); return false; } ULONGLONG length; if (FAILED(function->get_length(&length))) { fprintf(stderr, "failed to get function length\n"); return false; } if (length == 0) { // Silently ignore zero-length functions, which can infrequently pop up. return true; } CComBSTR name; int stack_param_size; if (!GetSymbolFunctionName(function, &name, &stack_param_size)) { return false; } // If the decorated name didn't give the parameter size, try to // calculate it. if (stack_param_size < 0) { stack_param_size = GetFunctionStackParamSize(function); } fprintf(output_, "FUNC %x %" WIN_STRING_FORMAT_LL "x %x %ws\n", rva, length, stack_param_size, name); CComPtr<IDiaEnumLineNumbers> lines; if (FAILED(session_->findLinesByRVA(rva, DWORD(length), &lines))) { return false; } if (!PrintLines(lines)) { return false; } return true;}bool PDBSourceLineWriter::PrintSourceFiles() { CComPtr<IDiaSymbol> global; if (FAILED(session_->get_globalScope(&global))) { fprintf(stderr, "get_globalScope failed\n"); return false; } CComPtr<IDiaEnumSymbols> compilands; if (FAILED(global->findChildren(SymTagCompiland, NULL, nsNone, &compilands))) { fprintf(stderr, "findChildren failed\n"); return false; } CComPtr<IDiaSymbol> compiland; ULONG count; while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) { CComPtr<IDiaEnumSourceFiles> source_files; if (FAILED(session_->findFile(compiland, NULL, nsNone, &source_files))) { return false; } CComPtr<IDiaSourceFile> file; while (SUCCEEDED(source_files->Next(1, &file, &count)) && count == 1) { DWORD file_id; if (FAILED(file->get_uniqueId(&file_id))) { return false; } CComBSTR file_name; if (FAILED(file->get_fileName(&file_name))) { return false; } fwprintf(output_, L"FILE %d %s\n", file_id, file_name); file.Release(); } compiland.Release(); } return true;}bool PDBSourceLineWriter::PrintFunctions() { CComPtr<IDiaEnumSymbolsByAddr> symbols; if (FAILED(session_->getSymbolsByAddr(&symbols))) { fprintf(stderr, "failed to get symbol enumerator\n"); return false; } CComPtr<IDiaSymbol> symbol; if (FAILED(symbols->symbolByAddr(1, 0, &symbol))) { fprintf(stderr, "failed to enumerate symbols\n"); return false; } DWORD rva_last = 0; if (FAILED(symbol->get_relativeVirtualAddress(&rva_last))) { fprintf(stderr, "failed to get symbol rva\n"); return false; } ULONG count; do { DWORD tag; if (FAILED(symbol->get_symTag(&tag))) { fprintf(stderr, "failed to get symbol tag\n"); return false; } // For a given function, DIA seems to give either a symbol with // SymTagFunction or SymTagPublicSymbol, but not both. This means // that PDBSourceLineWriter will output either a FUNC or PUBLIC line, // but not both. if (tag == SymTagFunction) { if (!PrintFunction(symbol)) { return false; } } else if (tag == SymTagPublicSymbol) { if (!PrintCodePublicSymbol(symbol)) { return false; } } symbol.Release(); } while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1); return true;}bool PDBSourceLineWriter::PrintFrameData() { // It would be nice if it were possible to output frame data alongside the // associated function, as is done with line numbers, but the DIA API // doesn't make it possible to get the frame data in that way. CComPtr<IDiaEnumTables> tables; if (FAILED(session_->getEnumTables(&tables))) return false; // Pick up the first table that supports IDiaEnumFrameData. CComPtr<IDiaEnumFrameData> frame_data_enum; CComPtr<IDiaTable> table; ULONG count; while (!frame_data_enum && SUCCEEDED(tables->Next(1, &table, &count)) && count == 1) { table->QueryInterface(_uuidof(IDiaEnumFrameData), reinterpret_cast<void**>(&frame_data_enum)); table.Release(); } if (!frame_data_enum) return false; DWORD last_type = -1; DWORD last_rva = -1; DWORD last_code_size = 0; DWORD last_prolog_size = -1; CComPtr<IDiaFrameData> frame_data; while (SUCCEEDED(frame_data_enum->Next(1, &frame_data, &count)) && count == 1) { DWORD type; if (FAILED(frame_data->get_type(&type))) return false; DWORD rva; if (FAILED(frame_data->get_relativeVirtualAddress(&rva))) return false; DWORD code_size; if (FAILED(frame_data->get_lengthBlock(&code_size))) return false; DWORD prolog_size; if (FAILED(frame_data->get_lengthProlog(&prolog_size))) return false; // epliog_size is always 0. DWORD epilog_size = 0; // parameter_size is the size of parameters passed on the stack. If any // parameters are not passed on the stack (such as in registers), their // sizes will not be included in parameter_size. DWORD parameter_size; if (FAILED(frame_data->get_lengthParams(¶meter_size))) return false; DWORD saved_register_size; if (FAILED(frame_data->get_lengthSavedRegisters(&saved_register_size))) return false; DWORD local_size; if (FAILED(frame_data->get_lengthLocals(&local_size))) return false; // get_maxStack can return S_FALSE, just use 0 in that case. DWORD max_stack_size = 0; if (FAILED(frame_data->get_maxStack(&max_stack_size))) return false; // get_programString can return S_FALSE, indicating that there is no // program string. In that case, check whether %ebp is used. HRESULT program_string_result; CComBSTR program_string; if (FAILED(program_string_result = frame_data->get_program( &program_string))) { return false; } // get_allocatesBasePointer can return S_FALSE, treat that as though // %ebp is not used. BOOL allocates_base_pointer = FALSE; if (program_string_result != S_OK) { if (FAILED(frame_data->get_allocatesBasePointer( &allocates_base_pointer))) { return false; } } // Only print out a line if type, rva, code_size, or prolog_size have // changed from the last line. It is surprisingly common (especially in // system library PDBs) for DIA to return a series of identical // IDiaFrameData objects. For kernel32.pdb from Windows XP SP2 on x86, // this check reduces the size of the dumped symbol file by a third. if (type != last_type || rva != last_rva || code_size != last_code_size || prolog_size != last_prolog_size) { fprintf(output_, "STACK WIN %x %x %x %x %x %x %x %x %x %d ", type, rva, code_size, prolog_size, epilog_size, parameter_size, saved_register_size, local_size, max_stack_size, program_string_result == S_OK); if (program_string_result == S_OK) { fprintf(output_, "%ws\n", program_string); } else { fprintf(output_, "%d\n", allocates_base_pointer); } last_type = type; last_rva = rva; last_code_size = code_size; last_prolog_size = prolog_size; } frame_data.Release(); } return true;}bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) { BOOL is_code; if (FAILED(symbol->get_code(&is_code))) { return false; } if (!is_code) { return true; } DWORD rva; if (FAILED(symbol->get_relativeVirtualAddress(&rva))) { return false;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?