diff options
Diffstat (limited to 'src/tools/windows/dump_syms/pdb_source_line_writer.cc')
-rw-r--r-- | src/tools/windows/dump_syms/pdb_source_line_writer.cc | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/src/tools/windows/dump_syms/pdb_source_line_writer.cc b/src/tools/windows/dump_syms/pdb_source_line_writer.cc new file mode 100644 index 00000000..61c22514 --- /dev/null +++ b/src/tools/windows/dump_syms/pdb_source_line_writer.cc @@ -0,0 +1,216 @@ +// Copyright (C) 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <stdio.h> +#include <atlbase.h> +#include <dia2.h> +#include "pdb_source_line_writer.h" + +namespace google_airbag { + +PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) { +} + +PDBSourceLineWriter::~PDBSourceLineWriter() { +} + +bool PDBSourceLineWriter::Open(const wstring &pdb_file) { + 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; + } + + if (FAILED(data_source->loadDataFromPdb(pdb_file.c_str()))) { + fprintf(stderr, "loadDataFromPdb failed\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 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 %d %d\n", rva, line_num, source_id); + line.Release(); + } + return true; +} + +bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function) { + // The function format is: + // FUNC <address> <function> + CComBSTR name; + if (FAILED(function->get_name(&name))) { + fprintf(stderr, "failed to get function name\n"); + return false; + } + if (name.Length() == 0) { + fprintf(stderr, "empty function name\n"); + return false; + } + + ULONGLONG length; + if (FAILED(function->get_length(&length))) { + fprintf(stderr, "failed to get function length\n"); + return false; + } + + DWORD rva; + if (FAILED(function->get_relativeVirtualAddress(&rva))) { + fprintf(stderr, "couldn't get rva\n"); + return false; + } + + CComPtr<IDiaEnumLineNumbers> lines; + if (FAILED(session_->findLinesByRVA(rva, DWORD(length), &lines))) { + return false; + } + + fwprintf(output_, L"FUNC %x %s\n", rva, name); + 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; + } + if (tag == SymTagFunction) { + if (!PrintFunction(symbol)) { + return false; + } + } + symbol.Release(); + } while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1); + + return true; +} + +bool PDBSourceLineWriter::WriteMap(FILE *map_file) { + bool ret = false; + output_ = map_file; + if (PrintSourceFiles() && PrintFunctions()) { + ret = true; + } + + output_ = NULL; + return ret; +} + +void PDBSourceLineWriter::Close() { + session_.Release(); +} + +} // namespace google_airbag |