feat: IPI & TPI stream merger.

This commit is contained in:
2025-02-12 02:03:14 +08:00
parent a19692c659
commit 2d1179e418
5 changed files with 167 additions and 30 deletions

View File

@@ -11,10 +11,7 @@ using namespace llvm::pdb;
namespace makepdb::binary {
PDB::PDB(COFF&& coff, SymbolData&& symbol_data)
: m_owning_coff(std::move(coff)),
m_owning_symbol_data(std::move(symbol_data)),
m_builder(m_allocator) {
PDB::PDB() : m_builder(m_allocator) {
constexpr uint32_t block_size = 4096;
if (m_builder.initialize(block_size)) {
throw std::runtime_error("Failed to initialize pdb file builder.");
@@ -25,8 +22,6 @@ PDB::PDB(COFF&& coff, SymbolData&& symbol_data)
throw std::runtime_error("Failed to add initial stream.");
}
}
m_image_base = m_owning_coff.get_owning_coff().getImageBase();
}
void PDB::write(std::string_view path) {
@@ -46,18 +41,17 @@ void PDB::build() {
}
void PDB::build_Info() {
auto pdb_info = m_owning_coff.get_debug_info();
auto& info_builder = m_builder.getInfoBuilder();
auto pdb_info = m_owning_coff->get_debug_info();
auto& Info = m_builder.getInfoBuilder();
info_builder.setVersion(PdbRaw_ImplVer::PdbImplVC70);
info_builder.setAge(pdb_info.Age);
info_builder.setGuid(*reinterpret_cast<codeview::GUID*>(pdb_info.Signature)
);
info_builder.addFeature(PdbRaw_FeatureSig::VC140);
Info.setVersion(PdbRaw_ImplVer::PdbImplVC70);
Info.setAge(pdb_info.Age);
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 pdb_info = m_owning_coff->get_debug_info();
auto& DBI = m_builder.getDbiBuilder();
DBI.setVersionHeader(PdbRaw_DbiVer::PdbDbiV70);
@@ -67,12 +61,12 @@ void PDB::build_DBI() {
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_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)
m_owning_coff->get_number_of_sections() * sizeof(object::coff_section)
);
auto section_table_ref = ArrayRef<object::coff_section>(
@@ -89,20 +83,36 @@ void PDB::build_DBI() {
}
void PDB::build_TPI() {
m_builder.getTpiBuilder().setVersionHeader(PdbRaw_TpiVer::PdbTpiV80);
m_builder.getIpiBuilder().setVersionHeader(PdbRaw_TpiVer::PdbTpiV80);
auto& TPI = m_builder.getTpiBuilder();
auto& IPI = m_builder.getIpiBuilder();
TPI.setVersionHeader(PdbRaw_TpiVer::PdbTpiV80);
IPI.setVersionHeader(PdbRaw_TpiVer::PdbTpiV80);
if (m_owning_raw_type_data) {
m_owning_raw_type_data->for_each<RawTypeData::TPI>(
[&TPI](codeview::TypeIndex index, const codeview::CVType& type) {
TPI.addTypeRecord(type.RecordData, std::nullopt);
}
);
m_owning_raw_type_data->for_each<RawTypeData::IPI>(
[&IPI](codeview::TypeIndex index, const codeview::CVType& type) {
IPI.addTypeRecord(type.RecordData, std::nullopt);
}
);
}
}
void PDB::build_GSI() {
std::vector<BulkPublic> publics;
m_owning_symbol_data.for_each([&publics,
this](const SymbolDataEntity& entity) {
m_owning_symbol_data->for_each([&publics,
this](const SymbolDataEntity& entity) {
BulkPublic symbol;
auto section_index =
m_owning_coff.get_section_index(entity.rva - m_image_base);
m_owning_coff->get_section_index(entity.rva - m_image_base);
auto section_or_err =
m_owning_coff.get_owning_coff().getSection(section_index + 1);
m_owning_coff->get_owning_coff().getSection(section_index + 1);
if (!section_or_err) {
throw std::runtime_error("Invalid section.");
}

View File

@@ -1,6 +1,8 @@
#pragma once
#include "binary/COFF.h"
#include "raw_type_data.h"
#include "symbol_data.h"
#include <llvm/DebugInfo/PDB/Native/PDBFileBuilder.h>
@@ -10,7 +12,23 @@ namespace makepdb::binary {
class PDB {
public:
explicit PDB(COFF&& coff, SymbolData&& symbol_data);
using OwningCOFF = std::unique_ptr<COFF>;
using OwningSymbolData = std::unique_ptr<SymbolData>;
using OwningRawTypeData = std::unique_ptr<RawTypeData>;
explicit PDB();
void set_coff_object(OwningCOFF coff_object) {
m_owning_coff = std::move(coff_object);
m_image_base = m_owning_coff->get_owning_coff().getImageBase();
}
void set_symbol_data(OwningSymbolData symbol_data) {
m_owning_symbol_data = std::move(symbol_data);
}
void set_raw_type_data(OwningRawTypeData raw_type_data) {
m_owning_raw_type_data = std::move(raw_type_data);
}
void write(std::string_view path);
@@ -22,8 +40,9 @@ private:
inline void build_TPI();
inline void build_GSI();
COFF m_owning_coff;
SymbolData m_owning_symbol_data;
OwningCOFF m_owning_coff;
OwningSymbolData m_owning_symbol_data;
OwningRawTypeData m_owning_raw_type_data;
uint64_t m_image_base;

View File

@@ -3,6 +3,7 @@
#include "binary/COFF.h"
#include "binary/PDB.h"
#include "raw_type_data.h"
#include "symbol_data.h"
using namespace makepdb;
@@ -14,8 +15,9 @@ using namespace makepdb;
struct {
std::string server_program_path;
std::string symbol_data_path;
std::string typeinfo_pdb_path;
std::string output_path;
std::optional<std::string> typeinfo_pdb_path;
} args;
program.add_argument("--program")
@@ -28,6 +30,10 @@ using namespace makepdb;
.store_into(args.symbol_data_path)
.required();
program.add_argument("--typeinfo")
.help("Path to compiler PDB which contains TPI & IPI (will merged into "
"result PDB).");
program.add_argument("--output", "-o")
.help("Path to output PDB.")
.store_into(args.output_path)
@@ -35,6 +41,10 @@ using namespace makepdb;
program.parse_args(argc, argv);
if (program.is_used("--typeinfo")) {
args.typeinfo_pdb_path = program.get<std::string>("--typeinfo");
}
return args;
}
@@ -42,10 +52,20 @@ int main(int argc, char* argv[]) try {
auto args = load_args(argc, argv);
binary::COFF server_program(args.server_program_path);
SymbolData symbol_data(args.symbol_data_path);
auto server_program =
std::make_unique<binary::COFF>(args.server_program_path);
binary::PDB pdb(std::move(server_program), std::move(symbol_data));
auto symbol_data = std::make_unique<SymbolData>(args.symbol_data_path);
std::unique_ptr<RawTypeData> raw_type_data;
if (args.typeinfo_pdb_path) {
raw_type_data = std::make_unique<RawTypeData>(*args.typeinfo_pdb_path);
}
binary::PDB pdb;
pdb.set_coff_object(std::move(server_program));
pdb.set_symbol_data(std::move(symbol_data));
pdb.set_raw_type_data(std::move(raw_type_data));
pdb.write(args.output_path);

View File

@@ -0,0 +1,54 @@
#include "raw_type_data.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 makepdb {
RawTypeData::RawTypeData(std::string_view path)
: m_storaged_TPI(m_allocator),
m_storaged_IPI(m_allocator) {
std::unique_ptr<IPDBSession> pdb_session;
if (llvm::pdb::loadDataForPDB(PDB_ReaderType::Native, path, 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 makepdb

View File

@@ -0,0 +1,34 @@
#pragma once
#include <llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h>
#include <llvm/DebugInfo/CodeView/TypeStreamMerger.h>
namespace makepdb {
class RawTypeData {
public:
using ForEachTpiCallback =
std::function<void(codeview::TypeIndex, codeview::CVType)>;
enum TypedStream { TPI, IPI };
explicit RawTypeData(std::string_view path);
template <TypedStream Stream>
void for_each(const ForEachTpiCallback& 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_TPI;
codeview::MergingTypeTableBuilder m_storaged_IPI;
};
} // namespace makepdb