refactor: merge symbol-extractor and type-extractor into io/pdb.
This commit is contained in:
@@ -1,57 +0,0 @@
|
|||||||
#include "data_format/raw_type_data.h"
|
|
||||||
|
|
||||||
#include <llvm/DebugInfo/CodeView/TypeStreamMerger.h>
|
|
||||||
#include <llvm/DebugInfo/PDB/IPDBSession.h>
|
|
||||||
#include <llvm/DebugInfo/PDB/Native/NativeSession.h>
|
|
||||||
#include <llvm/DebugInfo/PDB/Native/PDBFile.h>
|
|
||||||
#include <llvm/DebugInfo/PDB/Native/TpiStream.h>
|
|
||||||
#include <llvm/DebugInfo/PDB/PDB.h>
|
|
||||||
#include <llvm/DebugInfo/PDB/PDBTypes.h>
|
|
||||||
|
|
||||||
using namespace llvm::pdb;
|
|
||||||
|
|
||||||
namespace di::data_format {
|
|
||||||
|
|
||||||
void RawTypeData::read(const fs::path& path) {
|
|
||||||
std::unique_ptr<IPDBSession> pdb_session;
|
|
||||||
if (llvm::pdb::loadDataForPDB(
|
|
||||||
PDB_ReaderType::Native,
|
|
||||||
path.string(),
|
|
||||||
pdb_session
|
|
||||||
)) {
|
|
||||||
throw std::runtime_error("Failed to load PDB.");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto native_session = static_cast<NativeSession*>(pdb_session.get());
|
|
||||||
auto& pdb_file = native_session->getPDBFile();
|
|
||||||
|
|
||||||
SmallVector<codeview::TypeIndex, 128> type_map;
|
|
||||||
SmallVector<codeview::TypeIndex, 128> id_map;
|
|
||||||
|
|
||||||
if (auto tpi_stream = pdb_file.getPDBTpiStream()) {
|
|
||||||
if (codeview::mergeTypeRecords(
|
|
||||||
m_storaged_TPI,
|
|
||||||
type_map,
|
|
||||||
(*tpi_stream).typeArray()
|
|
||||||
)) {
|
|
||||||
throw std::runtime_error("Failed to merge type record.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("TPI is not valid.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto ipi_stream = pdb_file.getPDBIpiStream()) {
|
|
||||||
if (codeview::mergeIdRecords(
|
|
||||||
m_storaged_IPI,
|
|
||||||
type_map,
|
|
||||||
id_map,
|
|
||||||
(*ipi_stream).typeArray()
|
|
||||||
)) {
|
|
||||||
throw std::runtime_error("Failed to merge id record.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("IPI is not valid.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace di::data_format
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "data_format/io/io_base.h"
|
|
||||||
|
|
||||||
#include <llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h>
|
|
||||||
|
|
||||||
namespace di::data_format {
|
|
||||||
|
|
||||||
class RawTypeData : public IOBase {
|
|
||||||
public:
|
|
||||||
using for_each_callback_t =
|
|
||||||
std::function<void(codeview::TypeIndex, codeview::CVType)>;
|
|
||||||
|
|
||||||
enum TypedStream { TPI, IPI };
|
|
||||||
|
|
||||||
RawTypeData() : m_storaged_IPI(m_allocator), m_storaged_TPI(m_allocator) {}
|
|
||||||
|
|
||||||
void read(const fs::path& path) override;
|
|
||||||
void write(const fs::path& path) const override {
|
|
||||||
throw std::runtime_error("Unsupported operation.");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <TypedStream Stream>
|
|
||||||
void for_each(const for_each_callback_t& callback) /*const*/ {
|
|
||||||
if constexpr (Stream == TPI) {
|
|
||||||
return m_storaged_TPI.ForEachRecord(callback);
|
|
||||||
}
|
|
||||||
if constexpr (Stream == IPI) {
|
|
||||||
return m_storaged_IPI.ForEachRecord(callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BumpPtrAllocator m_allocator;
|
|
||||||
|
|
||||||
codeview::MergingTypeTableBuilder m_storaged_IPI;
|
|
||||||
codeview::MergingTypeTableBuilder m_storaged_TPI;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace di::data_format
|
|
||||||
@@ -1,133 +1,221 @@
|
|||||||
#include "object_file/pdb.h"
|
#include "object_file/pdb.h"
|
||||||
|
|
||||||
|
#include <llvm/DebugInfo/CodeView/SymbolDeserializer.h>
|
||||||
|
#include <llvm/DebugInfo/CodeView/TypeStreamMerger.h>
|
||||||
#include <llvm/DebugInfo/MSF/MSFBuilder.h>
|
#include <llvm/DebugInfo/MSF/MSFBuilder.h>
|
||||||
|
#include <llvm/DebugInfo/PDB/IPDBSession.h>
|
||||||
#include <llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h>
|
#include <llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h>
|
||||||
#include <llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h>
|
#include <llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h>
|
||||||
#include <llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h>
|
#include <llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h>
|
||||||
|
#include <llvm/DebugInfo/PDB/Native/PDBFile.h>
|
||||||
|
#include <llvm/DebugInfo/PDB/Native/PublicsStream.h>
|
||||||
#include <llvm/DebugInfo/PDB/Native/RawConstants.h>
|
#include <llvm/DebugInfo/PDB/Native/RawConstants.h>
|
||||||
|
#include <llvm/DebugInfo/PDB/Native/SymbolStream.h>
|
||||||
|
#include <llvm/DebugInfo/PDB/Native/TpiStream.h>
|
||||||
#include <llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h>
|
#include <llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h>
|
||||||
|
#include <llvm/DebugInfo/PDB/PDB.h>
|
||||||
|
#include <llvm/DebugInfo/PDB/PDBTypes.h>
|
||||||
|
|
||||||
using namespace llvm::pdb;
|
using namespace llvm::pdb;
|
||||||
|
using namespace llvm::codeview;
|
||||||
|
|
||||||
namespace di::object_file {
|
namespace di::object_file {
|
||||||
|
|
||||||
PDB::PDB() : m_builder(m_allocator) {
|
void PDB::read(const fs::path& path) {
|
||||||
constexpr auto block_size = 4096;
|
if (loadDataForPDB(PDB_ReaderType::Native, path.string(), m_session)) {
|
||||||
if (m_builder.initialize(block_size)) {
|
throw std::runtime_error("Failed to load PDB.");
|
||||||
throw std::runtime_error("Failed to initialize pdb file builder.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t idx = 0; idx < pdb::kSpecialStreamCount; ++idx) {
|
std::unique_ptr<IPDBSession> pdb_session;
|
||||||
if (!m_builder.getMsfBuilder().addStream(0)) {
|
if (llvm::pdb::loadDataForPDB(
|
||||||
throw std::runtime_error("Failed to add initial stream.");
|
PDB_ReaderType::Native,
|
||||||
|
path.string(),
|
||||||
|
pdb_session
|
||||||
|
)) {
|
||||||
|
throw std::runtime_error("Failed to load PDB.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto native_session = static_cast<NativeSession*>(pdb_session.get());
|
||||||
|
auto& pdb_file = native_session->getPDBFile();
|
||||||
|
|
||||||
|
SmallVector<codeview::TypeIndex, 128> type_map;
|
||||||
|
SmallVector<codeview::TypeIndex, 128> id_map;
|
||||||
|
|
||||||
|
if (auto tpi_stream = pdb_file.getPDBTpiStream()) {
|
||||||
|
if (codeview::mergeTypeRecords(
|
||||||
|
*m_storaged_Tpi,
|
||||||
|
type_map,
|
||||||
|
(*tpi_stream).typeArray()
|
||||||
|
)) {
|
||||||
|
throw std::runtime_error("Failed to merge type record.");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("TPI is not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto ipi_stream = pdb_file.getPDBIpiStream()) {
|
||||||
|
if (codeview::mergeIdRecords(
|
||||||
|
*m_storaged_Ipi,
|
||||||
|
type_map,
|
||||||
|
id_map,
|
||||||
|
(*ipi_stream).typeArray()
|
||||||
|
)) {
|
||||||
|
throw std::runtime_error("Failed to merge id record.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("IPI is not valid.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDB::write(const fs::path& path) {
|
void PDB::_write(const fs::path& path) {
|
||||||
build();
|
build();
|
||||||
|
|
||||||
codeview::GUID out_guid;
|
GUID out_guid;
|
||||||
if (m_builder.commit(path.string(), &out_guid)) {
|
if (m_builder->commit(path.string(), &out_guid)) {
|
||||||
throw std::runtime_error("Failed to create pdb!");
|
throw std::runtime_error("Failed to create pdb!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NativeSession& PDB::get_native_session() {
|
||||||
|
return *static_cast<NativeSession*>(m_session.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
pdb::PDBFile& PDB::get_pdb_file() { return get_native_session().getPDBFile(); }
|
||||||
|
|
||||||
|
void PDB::_for_each_public(const for_each_symbol_callback_t& callback) {
|
||||||
|
using namespace codeview;
|
||||||
|
auto& file = get_pdb_file();
|
||||||
|
auto publics_stream = file.getPDBPublicsStream();
|
||||||
|
if (!publics_stream) {
|
||||||
|
throw std::runtime_error("Failed to get public stream from PDB.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto publics_symbol_stream = file.getPDBSymbolStream();
|
||||||
|
if (!publics_symbol_stream) {
|
||||||
|
throw std::runtime_error("Failed to get symbol stream from PDB.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto publics_symbols =
|
||||||
|
publics_symbol_stream->getSymbolArray().getUnderlyingStream();
|
||||||
|
for (auto offset : publics_stream->getPublicsTable()) {
|
||||||
|
auto cv_symbol = readSymbolFromStream(publics_symbols, offset);
|
||||||
|
auto public_sym32 =
|
||||||
|
SymbolDeserializer::deserializeAs<PublicSym32>(cv_symbol.get());
|
||||||
|
if (!public_sym32) {
|
||||||
|
throw std::runtime_error("Unsupported symbol type.");
|
||||||
|
}
|
||||||
|
callback(*public_sym32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PDB::build() {
|
void PDB::build() {
|
||||||
build_Info();
|
constexpr auto block_size = 4096;
|
||||||
build_DBI();
|
|
||||||
build_TPI();
|
|
||||||
build_GSI();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PDB::build_Info() {
|
m_builder.reset(new PDBFileBuilder{m_Alloc});
|
||||||
auto pdb_info = m_owning_coff->get_debug_info();
|
|
||||||
auto& Info = m_builder.getInfoBuilder();
|
|
||||||
|
|
||||||
Info.setVersion(PdbRaw_ImplVer::PdbImplVC70);
|
if (m_builder->initialize(block_size)) {
|
||||||
Info.setAge(pdb_info.Age);
|
throw std::runtime_error("Failed to initialize pdb file builder.");
|
||||||
Info.setGuid(*reinterpret_cast<codeview::GUID*>(pdb_info.Signature));
|
|
||||||
Info.addFeature(PdbRaw_FeatureSig::VC140);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PDB::build_DBI() {
|
|
||||||
auto pdb_info = m_owning_coff->get_debug_info();
|
|
||||||
auto& DBI = m_builder.getDbiBuilder();
|
|
||||||
|
|
||||||
DBI.setVersionHeader(PdbRaw_DbiVer::PdbDbiV70);
|
|
||||||
DBI.setAge(pdb_info.Age);
|
|
||||||
DBI.setMachineType(PDB_Machine::Amd64);
|
|
||||||
DBI.setFlags(DbiFlags::FlagStrippedMask);
|
|
||||||
DBI.setBuildNumber(14, 11); // LLVM is compatible with LINK 14.11
|
|
||||||
|
|
||||||
// Add sections.
|
|
||||||
auto section_table = m_owning_coff->get_section_table();
|
|
||||||
auto number_of_sections = m_owning_coff->get_number_of_sections();
|
|
||||||
|
|
||||||
auto section_data_ref = ArrayRef<uint8_t>(
|
|
||||||
(uint8_t*)section_table,
|
|
||||||
m_owning_coff->get_number_of_sections() * sizeof(object::coff_section)
|
|
||||||
);
|
|
||||||
|
|
||||||
auto section_table_ref = ArrayRef<object::coff_section>(
|
|
||||||
(const object::coff_section*)section_data_ref.data(),
|
|
||||||
number_of_sections
|
|
||||||
);
|
|
||||||
|
|
||||||
DBI.createSectionMap(section_table_ref);
|
|
||||||
|
|
||||||
// Add COFF section header stream.
|
|
||||||
if (DBI.addDbgStream(DbgHeaderType::SectionHdr, section_data_ref)) {
|
|
||||||
throw std::runtime_error("Failed to add dbg stream.");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void PDB::build_TPI() {
|
for (uint32_t idx = 0; idx < pdb::kSpecialStreamCount; ++idx) {
|
||||||
auto& TPI = m_builder.getTpiBuilder();
|
if (!m_builder->getMsfBuilder().addStream(0)) {
|
||||||
auto& IPI = m_builder.getIpiBuilder();
|
throw std::runtime_error("Failed to add initial stream.");
|
||||||
|
}
|
||||||
TPI.setVersionHeader(PdbRaw_TpiVer::PdbTpiV80);
|
|
||||||
IPI.setVersionHeader(PdbRaw_TpiVer::PdbTpiV80);
|
|
||||||
|
|
||||||
if (m_owning_raw_type_data) {
|
|
||||||
m_owning_raw_type_data->for_each<data_format::RawTypeData::TPI>(
|
|
||||||
[&TPI](codeview::TypeIndex index, const codeview::CVType& type) {
|
|
||||||
TPI.addTypeRecord(type.RecordData, std::nullopt);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
m_owning_raw_type_data->for_each<data_format::RawTypeData::IPI>(
|
|
||||||
[&IPI](codeview::TypeIndex index, const codeview::CVType& type) {
|
|
||||||
IPI.addTypeRecord(type.RecordData, std::nullopt);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void PDB::build_GSI() {
|
// INFO
|
||||||
std::vector<BulkPublic> publics;
|
{
|
||||||
m_owning_symbol_data->for_each([&publics, this](const BoundSymbol& entity) {
|
auto pdb_info = m_owning_coff->get_debug_info();
|
||||||
BulkPublic symbol;
|
auto& Info = m_builder->getInfoBuilder();
|
||||||
|
|
||||||
auto section_index =
|
Info.setVersion(PdbRaw_ImplVer::PdbImplVC70);
|
||||||
m_owning_coff->get_section_index(entity.m_rva - m_image_base);
|
Info.setAge(pdb_info.Age);
|
||||||
auto section_or_err =
|
Info.setGuid(*reinterpret_cast<GUID*>(pdb_info.Signature));
|
||||||
m_owning_coff->get_owning_coff().getSection(section_index + 1);
|
Info.addFeature(PdbRaw_FeatureSig::VC140);
|
||||||
if (!section_or_err) {
|
}
|
||||||
throw std::runtime_error("Invalid section.");
|
|
||||||
|
// DBI
|
||||||
|
{
|
||||||
|
auto pdb_info = m_owning_coff->get_debug_info();
|
||||||
|
auto& Dbi = m_builder->getDbiBuilder();
|
||||||
|
|
||||||
|
Dbi.setVersionHeader(PdbRaw_DbiVer::PdbDbiV70);
|
||||||
|
Dbi.setAge(pdb_info.Age);
|
||||||
|
Dbi.setMachineType(PDB_Machine::Amd64);
|
||||||
|
Dbi.setFlags(DbiFlags::FlagStrippedMask);
|
||||||
|
Dbi.setBuildNumber(14, 11); // LLVM is compatible with LINK 14.11
|
||||||
|
|
||||||
|
// Add sections.
|
||||||
|
auto section_table = m_owning_coff->get_section_table();
|
||||||
|
auto number_of_sections = m_owning_coff->get_number_of_sections();
|
||||||
|
|
||||||
|
auto section_data_ref = ArrayRef<uint8_t>(
|
||||||
|
(uint8_t*)section_table,
|
||||||
|
m_owning_coff->get_number_of_sections()
|
||||||
|
* sizeof(object::coff_section)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto section_table_ref = ArrayRef<object::coff_section>(
|
||||||
|
(const object::coff_section*)section_data_ref.data(),
|
||||||
|
number_of_sections
|
||||||
|
);
|
||||||
|
|
||||||
|
Dbi.createSectionMap(section_table_ref);
|
||||||
|
|
||||||
|
// Add COFF section header stream.
|
||||||
|
if (Dbi.addDbgStream(DbgHeaderType::SectionHdr, section_data_ref)) {
|
||||||
|
throw std::runtime_error("Failed to add dbg stream.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TPI & IPI
|
||||||
|
{
|
||||||
|
auto& Tpi = m_builder->getTpiBuilder();
|
||||||
|
auto& Ipi = m_builder->getIpiBuilder();
|
||||||
|
|
||||||
|
Tpi.setVersionHeader(PdbRaw_TpiVer::PdbTpiV80);
|
||||||
|
Ipi.setVersionHeader(PdbRaw_TpiVer::PdbTpiV80);
|
||||||
|
|
||||||
|
if (m_storaged_Tpi) {
|
||||||
|
for_each<TPI>([&Tpi](TypeIndex index, const CVType& type) {
|
||||||
|
Tpi.addTypeRecord(type.RecordData, std::nullopt);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol.Name = strdup(entity.m_symbol_name.c_str());
|
if (m_storaged_Ipi) {
|
||||||
symbol.NameLen = entity.m_symbol_name.size();
|
for_each<IPI>([&Ipi](TypeIndex index, const CVType& type) {
|
||||||
symbol.Segment = section_index + 1;
|
Ipi.addTypeRecord(type.RecordData, std::nullopt);
|
||||||
symbol.Offset =
|
});
|
||||||
entity.m_rva - m_image_base - section_or_err.get()->VirtualAddress;
|
}
|
||||||
if (entity.m_is_function)
|
}
|
||||||
symbol.setFlags(codeview::PublicSymFlags::Function);
|
|
||||||
|
|
||||||
publics.emplace_back(symbol);
|
// PUBLIC
|
||||||
});
|
{
|
||||||
|
std::vector<BulkPublic> publics;
|
||||||
|
m_owning_symbol_data->for_each([&publics,
|
||||||
|
this](const BoundSymbol& entity) {
|
||||||
|
BulkPublic symbol;
|
||||||
|
|
||||||
m_builder.getGsiBuilder().addPublicSymbols(std::move(publics));
|
auto section_index =
|
||||||
|
m_owning_coff->get_section_index(entity.m_rva - m_image_base);
|
||||||
|
auto section_or_err =
|
||||||
|
m_owning_coff->get_owning_coff().getSection(section_index + 1);
|
||||||
|
if (!section_or_err) {
|
||||||
|
throw std::runtime_error("Invalid section.");
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol.Name = strdup(entity.m_symbol_name.c_str());
|
||||||
|
symbol.NameLen = entity.m_symbol_name.size();
|
||||||
|
symbol.Segment = section_index + 1;
|
||||||
|
symbol.Offset = entity.m_rva - m_image_base
|
||||||
|
- section_or_err.get()->VirtualAddress;
|
||||||
|
if (entity.m_is_function) symbol.setFlags(PublicSymFlags::Function);
|
||||||
|
|
||||||
|
publics.emplace_back(symbol);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_builder->getGsiBuilder().addPublicSymbols(std::move(publics));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace di::object_file
|
} // namespace di::object_file
|
||||||
|
|||||||
@@ -1,23 +1,59 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "data_format/bound_symbol_list.h"
|
||||||
|
#include "io/io_base.h"
|
||||||
#include "object_file/coff.h"
|
#include "object_file/coff.h"
|
||||||
|
|
||||||
#include "data_format/bound_symbol_list.h"
|
#include <llvm/DebugInfo/CodeView/CVRecord.h>
|
||||||
#include "data_format/raw_type_data.h"
|
#include <llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h>
|
||||||
|
#include <llvm/DebugInfo/CodeView/SymbolRecord.h>
|
||||||
|
#include <llvm/DebugInfo/PDB/Native/NativeSession.h>
|
||||||
#include <llvm/DebugInfo/PDB/Native/PDBFileBuilder.h>
|
#include <llvm/DebugInfo/PDB/Native/PDBFileBuilder.h>
|
||||||
#include <llvm/Support/Allocator.h>
|
#include <llvm/Support/Allocator.h>
|
||||||
|
|
||||||
namespace di::object_file {
|
namespace di::object_file {
|
||||||
|
|
||||||
class PDB {
|
class PDB : public IOBase {
|
||||||
public:
|
public:
|
||||||
using owning_coff_t = std::unique_ptr<COFF>;
|
using owning_coff_t = std::unique_ptr<COFF>;
|
||||||
using owning_symbol_data_t = std::unique_ptr<data_format::BoundSymbolList>;
|
using owning_symbol_data_t = std::unique_ptr<data_format::BoundSymbolList>;
|
||||||
using owning_type_data_t = std::unique_ptr<data_format::RawTypeData>;
|
|
||||||
|
|
||||||
explicit PDB();
|
using for_each_symbol_callback_t =
|
||||||
|
std::function<void(codeview::PublicSym32 const&)>;
|
||||||
|
using for_each_type_callback_t =
|
||||||
|
std::function<void(codeview::TypeIndex, codeview::CVType)>;
|
||||||
|
|
||||||
|
enum IterableStream { TPI, IPI, Public };
|
||||||
|
|
||||||
|
void read(const fs::path& path) override;
|
||||||
|
void write(const fs::path& path) const override {
|
||||||
|
const_cast<PDB*>(this)->_write(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// r
|
||||||
|
pdb::NativeSession& get_native_session();
|
||||||
|
pdb::PDBFile& get_pdb_file();
|
||||||
|
|
||||||
|
template <IterableStream Stream, typename CallbackT>
|
||||||
|
void for_each(const CallbackT& callback) const {
|
||||||
|
if constexpr (Stream == TPI) {
|
||||||
|
return const_cast<PDB*>(this)->_for_each_ipi(
|
||||||
|
*m_storaged_Tpi,
|
||||||
|
callback
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if constexpr (Stream == IPI) {
|
||||||
|
return const_cast<PDB*>(this)->_for_each_ipi(
|
||||||
|
*m_storaged_Ipi,
|
||||||
|
callback
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if constexpr (Stream == Public) {
|
||||||
|
return const_cast<PDB*>(this)->_for_each_public(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// w
|
||||||
void set_coff_object(owning_coff_t coff_object) {
|
void set_coff_object(owning_coff_t coff_object) {
|
||||||
m_owning_coff = std::move(coff_object);
|
m_owning_coff = std::move(coff_object);
|
||||||
m_image_base = m_owning_coff->get_owning_coff().getImageBase();
|
m_image_base = m_owning_coff->get_owning_coff().getImageBase();
|
||||||
@@ -26,28 +62,35 @@ public:
|
|||||||
void set_symbol_data(owning_symbol_data_t symbol_data) {
|
void set_symbol_data(owning_symbol_data_t symbol_data) {
|
||||||
m_owning_symbol_data = std::move(symbol_data);
|
m_owning_symbol_data = std::move(symbol_data);
|
||||||
}
|
}
|
||||||
void set_raw_type_data(owning_type_data_t raw_type_data) {
|
|
||||||
m_owning_raw_type_data = std::move(raw_type_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const fs::path& path);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void build();
|
void build();
|
||||||
|
|
||||||
inline void build_Info();
|
// helpers
|
||||||
inline void build_DBI();
|
void _write(const fs::path& path);
|
||||||
inline void build_TPI();
|
|
||||||
inline void build_GSI();
|
void _for_each_public(const for_each_symbol_callback_t& callback);
|
||||||
|
void _for_each_ipi(
|
||||||
|
codeview::MergingTypeTableBuilder& type_table,
|
||||||
|
const for_each_type_callback_t& callback
|
||||||
|
) {
|
||||||
|
type_table.ForEachRecord(callback);
|
||||||
|
}
|
||||||
|
|
||||||
owning_coff_t m_owning_coff;
|
owning_coff_t m_owning_coff;
|
||||||
owning_symbol_data_t m_owning_symbol_data;
|
owning_symbol_data_t m_owning_symbol_data;
|
||||||
owning_type_data_t m_owning_raw_type_data;
|
|
||||||
|
|
||||||
addr_t m_image_base;
|
addr_t m_image_base;
|
||||||
|
|
||||||
BumpPtrAllocator m_allocator;
|
BumpPtrAllocator m_Alloc;
|
||||||
pdb::PDBFileBuilder m_builder;
|
|
||||||
|
// w
|
||||||
|
std::unique_ptr<pdb::PDBFileBuilder> m_builder;
|
||||||
|
|
||||||
|
// r
|
||||||
|
std::unique_ptr<pdb::IPDBSession> m_session;
|
||||||
|
std::unique_ptr<codeview::MergingTypeTableBuilder> m_storaged_Ipi;
|
||||||
|
std::unique_ptr<codeview::MergingTypeTableBuilder> m_storaged_Tpi;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace di::object_file
|
} // namespace di::object_file
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
#include <llvm/DebugInfo/CodeView/CVRecord.h>
|
|
||||||
#include <llvm/DebugInfo/CodeView/SymbolDeserializer.h>
|
|
||||||
#include <llvm/DebugInfo/PDB/IPDBSession.h>
|
|
||||||
#include <llvm/DebugInfo/PDB/Native/NativeSession.h>
|
|
||||||
#include <llvm/DebugInfo/PDB/Native/PDBFile.h>
|
|
||||||
#include <llvm/DebugInfo/PDB/Native/PublicsStream.h>
|
|
||||||
#include <llvm/DebugInfo/PDB/Native/SymbolStream.h>
|
|
||||||
#include <llvm/DebugInfo/PDB/PDB.h>
|
|
||||||
|
|
||||||
#include <argparse/argparse.hpp>
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
using namespace llvm;
|
#include <llvm/DebugInfo/CodeView/SymbolRecord.h>
|
||||||
using namespace llvm::pdb;
|
|
||||||
using namespace llvm::codeview;
|
#include "data_format/typed_symbol_list.h"
|
||||||
|
#include "object_file/pdb.h"
|
||||||
|
|
||||||
|
using namespace di;
|
||||||
|
using namespace di::object_file;
|
||||||
|
|
||||||
auto load_args(int argc, char* argv[]) {
|
auto load_args(int argc, char* argv[]) {
|
||||||
argparse::ArgumentParser program("extractpdb");
|
argparse::ArgumentParser program("extractpdb");
|
||||||
@@ -44,50 +39,23 @@ int main(int argc, char* argv[]) try {
|
|||||||
|
|
||||||
auto args = load_args(argc, argv);
|
auto args = load_args(argc, argv);
|
||||||
|
|
||||||
std::unique_ptr<IPDBSession> pdb_session;
|
PDB pdb;
|
||||||
if (llvm::pdb::loadDataForPDB(
|
pdb.read(args.m_program_database_path);
|
||||||
PDB_ReaderType::Native,
|
|
||||||
args.m_program_database_path,
|
|
||||||
pdb_session
|
|
||||||
)) {
|
|
||||||
throw std::runtime_error("Failed to load PDB.");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto native_session = static_cast<NativeSession*>(pdb_session.get());
|
data_format::TypedSymbolList symbol_list;
|
||||||
auto& pdb_file = native_session->getPDBFile();
|
|
||||||
|
|
||||||
auto publics_stream = pdb_file.getPDBPublicsStream();
|
pdb.for_each<PDB::Public>([&symbol_list](const codeview::PublicSym32& symbol
|
||||||
if (!publics_stream) {
|
) {
|
||||||
throw std::runtime_error("Failed to get public stream from PDB.");
|
using codeview::PublicSymFlags;
|
||||||
}
|
|
||||||
|
|
||||||
auto publics_symbol_stream = pdb_file.getPDBSymbolStream();
|
auto is_fun =
|
||||||
if (!publics_symbol_stream) {
|
(symbol.Flags & PublicSymFlags::Function) != PublicSymFlags::None;
|
||||||
throw std::runtime_error("Failed to get symbol stream from PDB.");
|
symbol_list.record(
|
||||||
}
|
symbol.Name.str(),
|
||||||
|
is_fun ? DeclType::Function : DeclType::Var
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
std::ofstream ofs(args.m_output_path);
|
|
||||||
if (!ofs) {
|
|
||||||
throw std::runtime_error("Failed to open output file.");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto publics_symbols =
|
|
||||||
publics_symbol_stream->getSymbolArray().getUnderlyingStream();
|
|
||||||
for (auto offset : publics_stream->getPublicsTable()) {
|
|
||||||
auto cv_symbol = readSymbolFromStream(publics_symbols, offset);
|
|
||||||
auto public_sym32 =
|
|
||||||
SymbolDeserializer::deserializeAs<PublicSym32>(cv_symbol.get());
|
|
||||||
if (!public_sym32) {
|
|
||||||
throw std::runtime_error("Unsupported symbol type.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ofs
|
|
||||||
<< ((public_sym32->Flags & PublicSymFlags::Function)
|
|
||||||
!= PublicSymFlags::None
|
|
||||||
? "Function, "
|
|
||||||
: "Var, ")
|
|
||||||
<< public_sym32->Name.str() << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include "object_file/pdb.h"
|
#include "object_file/pdb.h"
|
||||||
|
|
||||||
#include "data_format/bound_symbol_list.h"
|
#include "data_format/bound_symbol_list.h"
|
||||||
#include "data_format/raw_type_data.h"
|
|
||||||
|
|
||||||
using namespace di;
|
using namespace di;
|
||||||
|
|
||||||
@@ -58,16 +57,13 @@ int main(int argc, char* argv[]) try {
|
|||||||
auto symbol_data = std::make_unique<data_format::BoundSymbolList>();
|
auto symbol_data = std::make_unique<data_format::BoundSymbolList>();
|
||||||
symbol_data->read(args.symbol_data_path);
|
symbol_data->read(args.symbol_data_path);
|
||||||
|
|
||||||
std::unique_ptr<data_format::RawTypeData> raw_type_data;
|
object_file::PDB pdb;
|
||||||
if (args.typeinfo_pdb_path) {
|
if (args.typeinfo_pdb_path) {
|
||||||
raw_type_data = std::make_unique<data_format::RawTypeData>();
|
pdb.read(*args.typeinfo_pdb_path);
|
||||||
raw_type_data->read(*args.typeinfo_pdb_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object_file::PDB pdb;
|
|
||||||
pdb.set_coff_object(std::move(server_program));
|
pdb.set_coff_object(std::move(server_program));
|
||||||
pdb.set_symbol_data(std::move(symbol_data));
|
pdb.set_symbol_data(std::move(symbol_data));
|
||||||
pdb.set_raw_type_data(std::move(raw_type_data));
|
|
||||||
|
|
||||||
pdb.write(args.output_path);
|
pdb.write(args.output_path);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user