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(&parameter_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 + -
显示快捷键?