提取符号偏移地址

使用DIA接口获取符号的偏移地址

#include <windows.h>



// DIA headers must come after windows headers.
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
#endif
#include <dia2.h>
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#include <diacreate.h>

//
#include <wrl/client.h>

#include <iostream>

#include "base/at_exit.h"
#include "base/check.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/types/expected.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_com_initializer.h"

namespace switches {
constexpr char kSymbolName[] = "symbol";
constexpr char kSymbolServer[] = "srv";
constexpr char kPdb[] = "pdb";
constexpr char kImage[] = "image";
}  // namespace switches

namespace {
// clang-format off
constexpr wchar_t kDefaultSymbolSearchPath[] =
    L"SRV*D:\\SYMBOL.NT*https://msdl.microsoft.com/download/symbols"
    L";SRV*D:\\SYMBOL.NT*https://chromium-browser-symsrv.commondatastorage.googleapis.com";
// clang-format on

const std::wstring& SymbolServer() {
  static base::NoDestructor<std::wstring> srv([]{
    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
    if (command_line->HasSwitch(switches::kSymbolServer)) {
      return std::wstring(
          command_line->GetSwitchValueNative(switches::kSymbolServer));
    }
    return std::wstring(kDefaultSymbolSearchPath);
  }());
  return *srv;
}

HRESULT CreateDiaSessionFromPdb(const std::wstring& pdb_path,
                                IDiaSession** dia_session) {
  Microsoft::WRL::ComPtr<IDiaDataSource> dia_data_source;
  HRESULT hr = ::NoRegCoCreate(L"msdia140.dll", __uuidof(DiaSource),
                               IID_PPV_ARGS(&dia_data_source));
  if (FAILED(hr)) {
    return hr;
  }

  hr = dia_data_source->loadDataFromPdb(pdb_path.c_str());
  if (FAILED(hr)) {
    return hr;
  }

  hr = dia_data_source->openSession(dia_session);
  if (FAILED(hr)) {
    return hr;
  }
  return S_OK;
}

HRESULT CreateDiaSessionForImage(const std::wstring& image_path,
                                 IDiaSession** dia_session) {
  Microsoft::WRL::ComPtr<IDiaDataSource> dia_data_source;
  HRESULT hr = ::NoRegCoCreate(L"msdia140.dll", __uuidof(DiaSource),
                               IID_PPV_ARGS(&dia_data_source));
  if (FAILED(hr)) {
    return hr;
  }
  hr = dia_data_source->loadDataForExe(image_path.c_str(),
                                       SymbolServer().c_str(), nullptr);
  if (FAILED(hr)) {
    return hr;
  }

  hr = dia_data_source->openSession(dia_session);
  if (FAILED(hr)) {
    return hr;
  }

  return S_OK;
}

struct RAVResult {
  RAVResult(ULONGLONG rav, std::vector<std::string> lines)
      : rav(rav), lines(std::move(lines)) {}

  RAVResult(const RAVResult&) = default;
  RAVResult& operator=(const RAVResult&) = default;

  ~RAVResult() = default;

  ULONGLONG rav;
  std::vector<std::string> lines;
};

base::expected<std::vector<std::string>, HRESULT> GetSymbolLocation(
    IDiaSession* session,
    IDiaSymbol* symbol) {
  DWORD rva = 0;
  HRESULT hr = symbol->get_relativeVirtualAddress(&rva);
  if (FAILED(hr)) {
    return base::unexpected(hr);
  }

  Microsoft::WRL::ComPtr<IDiaEnumLineNumbers> lines;
  ULONGLONG length = 0;
  hr = symbol->get_length(&length);
  if (FAILED(hr)) {
    return base::unexpected(hr);
  }

  hr = session->findLinesByRVA(rva, (DWORD)length, &lines);
  if (FAILED(hr)) {
    return base::unexpected(hr);
  }

  std::vector<std::string> result;
  ULONG c = 0;
  Microsoft::WRL::ComPtr<IDiaLineNumber> line;
  while (SUCCEEDED(lines->Next(1, line.ReleaseAndGetAddressOf(), &c)) &&
         c == 1) {
    DWORD line_number;
    base::win::ScopedBstr filename;
    if (FAILED(line->get_lineNumber(&line_number))) {
      continue;
    }

    Microsoft::WRL::ComPtr<IDiaSourceFile> source_file;
    if (FAILED(line->get_sourceFile(source_file.ReleaseAndGetAddressOf()))) {
      continue;
    }

    if (FAILED(source_file->get_fileName(filename.Receive()))) {
      continue;
    }

    if (filename.Get()) {
      result.push_back(base::StringPrintf(
          "%s(%d)", base::SysWideToUTF8(filename.Get()).c_str(), line_number));
    }
  }

  return base::ok(std::move(result));
}

base::expected<std::vector<RAVResult>, HRESULT> GetRAVForSymbol(IDiaSession* session,
                                                   const std::wstring& symbol) {
  Microsoft::WRL::ComPtr<IDiaSymbol> global_symbol;
  HRESULT hr = session->get_globalScope(global_symbol.GetAddressOf());
  if (FAILED(hr)) {
    return base::unexpected(hr);
  }

  Microsoft::WRL::ComPtr<IDiaEnumSymbols> dia_enum_symbols;
  hr = global_symbol->findChildrenEx(SymTagFunction, symbol.c_str(), nsNone,
                                     dia_enum_symbols.GetAddressOf());
  if (FAILED(hr)) {
    return base::unexpected(hr);
  }

  std::vector<RAVResult> results;
  ULONG celt = 0;
  Microsoft::WRL::ComPtr<IDiaSymbol> dia_symbol;
  while (SUCCEEDED(dia_enum_symbols->Next(
             1, dia_symbol.ReleaseAndGetAddressOf(), &celt)) &&
         celt == 1) {
    ULONGLONG rav;
    dia_symbol->get_virtualAddress(&rav);

    auto lines = GetSymbolLocation(session, dia_symbol.Get());

    results.emplace_back(rav, lines.has_value() ? std::move(lines.value())
                                                : std::vector<std::string>{});
  }

  return base::ok(std::move(results));
}

void PrintUsage() {
  std::cout << "Usage: symbol.exe --" << switches::kSymbolName
            << "=<symbol> (--" << switches::kPdb << "=<pdb_path> | --"
            << switches::kImage << "=<image_path>) [--"
            << switches::kSymbolServer << "=<server_path>]" << std::endl
            << std::endl;
  std::cout << "Options:" << std::endl;
  std::cout << "  --" << switches::kSymbolName
            << ": The name of the symbol to find." << std::endl;
  std::cout << "  --" << switches::kPdb
            << ": Path to the PDB file. Mutually exclusive with --"
            << switches::kImage << "." << std::endl;
  std::cout << "  --" << switches::kImage
            << ": Path to the image (exe/dll). Mutually exclusive with --"
            << switches::kPdb << "." << std::endl;
  std::cout << "  --" << switches::kSymbolServer
            << ": Optional. Symbol server path to use with --"
            << switches::kImage << "." << std::endl;
}
}



int main(int argc, char** argv) {
  base::AtExitManager at_exit;
  base::CommandLine::Init(0, nullptr);
  base::win::ScopedCOMInitializer scoped_com_initializer;

  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  if ((!command_line->HasSwitch(switches::kImage) &&
       !command_line->HasSwitch(switches::kPdb)) ||
      !command_line->HasSwitch(switches::kSymbolName)) {
    PrintUsage();
    return -1;
  }

  Microsoft::WRL::ComPtr<IDiaSession> dia_session;
  if (command_line->HasSwitch(switches::kPdb)) {
    if (FAILED(CreateDiaSessionFromPdb(
            command_line->GetSwitchValueNative(switches::kPdb),
            dia_session.ReleaseAndGetAddressOf()))) {
      return -1;
    }
  } else {
    CHECK(command_line->HasSwitch(switches::kImage));

    if (FAILED(CreateDiaSessionForImage(
            command_line->GetSwitchValueNative(switches::kImage),
            dia_session.ReleaseAndGetAddressOf()))) {
      return -1;
    }
  }

  CHECK(dia_session);
  CHECK(command_line->HasSwitch(switches::kSymbolName));

  auto result = GetRAVForSymbol(
      dia_session.Get(),
      command_line->GetSwitchValueNative(switches::kSymbolName));
  if (result.has_value()) {
    for (const auto& rav : result.value()) {
      std::cout << "RAV: " << rav.rav;
      if (!rav.lines.empty()) {
        std::cout << "\n\t" << rav.lines[0];
      }
      std::cout<< std::endl;
    }
  } else {
    return result.error();
  }

  return 0;
}
posted @ 2025-09-08 18:53  吱吱的笔记  阅读(0)  评论(0)    收藏  举报