refactor: unified data_format IO.

This commit is contained in:
2025-02-28 22:19:27 +08:00
parent 5f4a912e30
commit 5dce170b89
19 changed files with 150 additions and 132 deletions

View File

@@ -6,8 +6,8 @@ namespace di::data_format {
constexpr int BOUND_SYMBOL_LIST_FORMAT_VERSION = 1;
BoundSymbolList::BoundSymbolList(std::string_view path) {
std::ifstream ifs(path.data());
void BoundSymbolList::read(const std::filesystem::path& path) {
std::ifstream ifs(path);
if (!ifs) {
throw std::runtime_error("Failed to open data path.");
}
@@ -17,6 +17,7 @@ BoundSymbolList::BoundSymbolList(std::string_view path) {
throw std::runtime_error("Unsupported data version.");
}
m_entities.clear();
for (const auto& entity : data["data"]) {
m_entities.emplace(
BoundSymbol{entity["symbol"], entity["rva"], entity["is_function"]}
@@ -24,15 +25,7 @@ BoundSymbolList::BoundSymbolList(std::string_view path) {
}
}
void BoundSymbolList::record(
std::string_view symbol,
uint64_t rva,
bool is_function
) {
m_entities.emplace(BoundSymbol{std::string(symbol), rva, is_function});
}
void BoundSymbolList::write_to(const std::string& path) const {
void BoundSymbolList::write(const std::filesystem::path& path) const {
std::ofstream ofs(path);
if (!ofs) {
throw std::runtime_error("Failed to open file!");
@@ -52,4 +45,12 @@ void BoundSymbolList::write_to(const std::string& path) const {
ofs << data.dump(4);
}
void BoundSymbolList::record(
std::string_view symbol,
uint64_t rva,
bool is_function
) {
m_entities.emplace(BoundSymbol{std::string(symbol), rva, is_function});
}
} // namespace di::data_format

View File

@@ -1,18 +1,18 @@
#pragma once
#include "data_format/io_base.h"
#include "data_format/type/bound_symbol.h"
namespace di::data_format {
class BoundSymbolList {
class BoundSymbolList : public IOBase {
public:
using for_each_callback_t = std::function<void(BoundSymbol const&)>;
explicit BoundSymbolList() = default;
explicit BoundSymbolList(std::string_view path);
void read(const std::filesystem::path& path) override;
void write(const std::filesystem::path& path) const override;
void record(std::string_view symbol, uint64_t rva, bool is_function);
void write_to(const std::string& path) const;
constexpr void for_each(const for_each_callback_t& callback) const {
for (const auto& entity : m_entities) callback(entity);

View File

@@ -1,20 +0,0 @@
#include "data_format/human_readable_symbol_list.h"
namespace di::data_format {
void HumanReadableSymbolList::record(std::string_view symbol, uint64_t rva) {
m_symbol_rva_map.try_emplace(std::string(symbol), rva);
}
void HumanReadableSymbolList::write_to(std::string_view path) const {
std::ofstream ofs(path.data());
if (!ofs) {
throw std::runtime_error("Failed to open save file.");
}
for (const auto& [symbol, rva] : m_symbol_rva_map) {
ofs << std::format("[{:#x}] {}\n", rva, symbol);
}
}
} // namespace di::data_format

View File

@@ -1,14 +0,0 @@
#pragma once
namespace di::data_format {
class HumanReadableSymbolList {
public:
void record(std::string_view symbol, uint64_t rva);
void write_to(std::string_view path) const;
protected:
std::unordered_map<std::string, uint64_t> m_symbol_rva_map;
};
} // namespace di::data_format

13
src/data_format/io_base.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
namespace di::data_format {
class IOBase {
public:
virtual ~IOBase() = default;
virtual void read(const std::filesystem::path& path) = 0;
virtual void write(const std::filesystem::path& path) const = 0;
};
} // namespace di::data_format

View File

@@ -2,13 +2,16 @@
namespace di::data_format {
void RawText::record(std::string_view content) {
m_data += content;
m_data += '\n';
void RawText::read(const std::filesystem::path& path) {
std::ifstream ifs(path);
auto size = std::filesystem::file_size(path);
m_data.reserve(size);
m_data.assign(std::istreambuf_iterator<char>(ifs), {});
}
void RawText::write_to(std::string_view path) const {
std::ofstream ofs(path.data());
void RawText::write(const std::filesystem::path& path) const {
std::ofstream ofs(path);
if (!ofs) {
throw std::runtime_error("Failed to open save file.");
}
@@ -16,4 +19,9 @@ void RawText::write_to(std::string_view path) const {
ofs << m_data;
}
void RawText::record(std::string_view content) {
m_data += content;
m_data += '\n';
}
} // namespace di::data_format

View File

@@ -1,11 +1,15 @@
#pragma once
#include "data_format/io_base.h"
namespace di::data_format {
class RawText {
class RawText : public IOBase {
public:
void read(const std::filesystem::path& path) override;
void write(const std::filesystem::path& path) const override;
void record(std::string_view line);
void write_to(std::string_view path) const;
private:
std::string m_data;

View File

@@ -12,11 +12,13 @@ using namespace llvm::pdb;
namespace di::data_format {
RawTypeData::RawTypeData(std::string_view path)
: m_storaged_TPI(m_allocator),
m_storaged_IPI(m_allocator) {
void RawTypeData::read(const std::filesystem::path& path) {
std::unique_ptr<IPDBSession> pdb_session;
if (llvm::pdb::loadDataForPDB(PDB_ReaderType::Native, path, pdb_session)) {
if (llvm::pdb::loadDataForPDB(
PDB_ReaderType::Native,
path.string(),
pdb_session
)) {
throw std::runtime_error("Failed to load PDB.");
}

View File

@@ -1,17 +1,24 @@
#pragma once
#include "data_format/io_base.h"
#include <llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h>
namespace di::data_format {
class RawTypeData {
class RawTypeData : public IOBase {
public:
using for_each_callback_t =
std::function<void(codeview::TypeIndex, codeview::CVType)>;
enum TypedStream { TPI, IPI };
explicit RawTypeData(std::string_view path);
RawTypeData() : m_storaged_IPI(m_allocator), m_storaged_TPI(m_allocator) {}
void read(const std::filesystem::path& path) override;
void write(const std::filesystem::path& path) const override {
throw std::runtime_error("Unsupported operation.");
}
template <TypedStream Stream>
void for_each(const for_each_callback_t& callback) /*const*/ {
@@ -26,8 +33,8 @@ public:
private:
BumpPtrAllocator m_allocator;
codeview::MergingTypeTableBuilder m_storaged_TPI;
codeview::MergingTypeTableBuilder m_storaged_IPI;
codeview::MergingTypeTableBuilder m_storaged_TPI;
};
} // namespace di::data_format

View File

@@ -64,6 +64,35 @@ public:
constexpr Enum data() const { return m_data; }
constexpr std::string string() const {
using namespace util::string;
// clang-format off
switch (m_data) {
#define HSTR(x) \
case x: \
return #x;
HSTR(Function);
HSTR(CXXDeductionGuide);
HSTR(CXXMethod);
HSTR(CXXConstructor);
HSTR(CXXConversion);
HSTR(CXXDestructor);
HSTR(Var);
HSTR(Decomposition);
HSTR(ImplicitParam);
HSTR(OMPCapturedExpr);
HSTR(ParamVar);
HSTR(VarTemplateSpecialization);
#undef HSTR
default:
throw std::runtime_error("Unexpected decl type.");
}
// clang-format on
}
constexpr bool operator==(const DeclType& other) const {
return m_data == other.m_data;
}

View File

@@ -2,33 +2,40 @@
namespace di::data_format {
TypedSymbolList::TypedSymbolList(const std::vector<std::string>& paths) {
for (const auto& path : paths) {
std::ifstream ifs(path.data());
if (!ifs) {
throw std::runtime_error("Failed to open symlist file.");
void TypedSymbolList::read(const std::filesystem::path& path) {
std::ifstream ifs(path);
if (!ifs) {
throw std::runtime_error("Failed to open symlist file.");
}
std::string line;
while (std::getline(ifs, line)) {
if (line.empty()) continue;
auto sep_pos = line.find(", ");
if (sep_pos == std::string::npos) {
throw std::runtime_error(
"Symbol data is not included declType, please re-generate "
"symlist file with -record-decl-name."
);
}
std::string line;
while (std::getline(ifs, line)) {
if (line.empty()) continue;
auto decl_type_s = line.substr(0, sep_pos);
auto symbol = line.substr(sep_pos + 2);
auto separator_pos = line.find(", ");
if (separator_pos == std::string::npos) {
throw std::runtime_error(
"Symbol data is not included declType, please re-generate "
"symlist file with -record-decl-name."
);
}
auto declType_s = line.substr(0, separator_pos);
auto symbol = line.substr(separator_pos + 2);
m_data.emplace(symbol, DeclType(declType_s));
}
std::println("Read {} symbols from dumped symlist.", m_data.size());
m_data.emplace(symbol, DeclType(decl_type_s));
}
}
void TypedSymbolList::write(const std::filesystem::path& path) const {
std::ofstream ofs;
for (const auto& [symbol, decl_type] : m_data) {
ofs << symbol << ", " << decl_type.string() << "\n";
}
}
void TypedSymbolList::record(std::string_view symbol, DeclType type) {
m_data.emplace(symbol, type);
}
} // namespace di::data_format

View File

@@ -1,16 +1,22 @@
#pragma once
#include "data_format/io_base.h"
#include "data_format/type/decl_type.h"
#include "data_format/type/typed_symbol.h"
namespace di::data_format {
class TypedSymbolList {
class TypedSymbolList : public IOBase {
public:
using for_each_callback_t = std::function<void(TypedSymbol const&)>;
explicit TypedSymbolList(const std::string& path)
: TypedSymbolList(std::vector<std::string>{path}) {};
explicit TypedSymbolList(const std::vector<std::string>& paths);
// this method in this class supports multiple calls (reading multiple
// files)
void read(const std::filesystem::path& path) override;
void write(const std::filesystem::path& path) const override;
void record(std::string_view name, DeclType type);
constexpr void for_each(const for_each_callback_t& callback) const {
for (const auto& entity : m_data) callback(entity);

View File

@@ -2,10 +2,10 @@
namespace di::object_file {
COFF::COFF(std::string_view path) {
COFF::COFF(const std::filesystem::path& path) {
using namespace object;
auto obj_or_err = ObjectFile::createObjectFile(path);
auto obj_or_err = ObjectFile::createObjectFile(path.string());
if (!obj_or_err) {
throw std::runtime_error("Failed to create object file.");
}

View File

@@ -6,7 +6,7 @@ namespace di::object_file {
class COFF {
public:
explicit COFF(std::string_view path);
explicit COFF(const std::filesystem::path& path);
codeview::PDB70DebugInfo get_debug_info() const;

View File

@@ -24,11 +24,11 @@ PDB::PDB() : m_builder(m_allocator) {
}
}
void PDB::write(std::string_view path) {
void PDB::write(const std::filesystem::path& path) {
build();
auto guid = m_builder.getInfoBuilder().getGuid();
if (m_builder.commit(path, &guid)) {
codeview::GUID out_guid;
if (m_builder.commit(path.string(), &out_guid)) {
throw std::runtime_error("Failed to create pdb!");
}
}

View File

@@ -30,7 +30,7 @@ public:
m_owning_raw_type_data = std::move(raw_type_data);
}
void write(std::string_view path);
void write(const std::filesystem::path& path);
private:
void build();

View File

@@ -6,6 +6,7 @@ using namespace llvm;
// Standard Libraries
#include <filesystem>
#include <fstream>
#include <print>

View File

@@ -1,7 +1,4 @@
#include "util/string.h"
#include "data_format/bound_symbol_list.h"
#include "data_format/human_readable_symbol_list.h"
#include "data_format/raw_text.h"
#include "data_format/typed_symbol_list.h"
@@ -11,15 +8,12 @@
#include <pl/SymbolProvider.h>
#endif
enum class OutputFormat { Text, MakePDB };
using namespace di;
[[nodiscard]] auto load_args(int argc, char* argv[]) {
argparse::ArgumentParser program("askrva");
struct {
OutputFormat m_output_format;
std::vector<std::string> m_input_paths;
std::string m_output_path;
@@ -54,25 +48,6 @@ using namespace di;
program.parse_args(argc, argv);
args.m_output_format = [&output_format, &args]() -> OutputFormat {
using namespace util::string;
switch (H(output_format)) {
case H("text"):
return OutputFormat::Text;
case H("makepdb"):
return OutputFormat::MakePDB;
case H("auto"):
default: {
if (args.m_output_path.ends_with(".json")) {
return OutputFormat::MakePDB;
} else {
return OutputFormat::Text;
}
}
}
}();
if (program.is_used("--output-failed")) {
args.m_output_failed_path = program.get<std::string>("--output-failed");
}
@@ -83,11 +58,10 @@ using namespace di;
int main(int argc, char* argv[]) try {
auto args = load_args(argc, argv);
auto symlist = data_format::TypedSymbolList(args.m_input_paths);
auto symlist = data_format::TypedSymbolList();
data_format::BoundSymbolList bound_symbol_list;
data_format::HumanReadableSymbolList human_readable_symbol_list;
data_format::RawText raw_text;
data_format::BoundSymbolList bound_symbol_list;
data_format::RawText raw_text;
symlist.for_each([&](const TypedSymbol& symbol) {
auto& sym = symbol.m_name;
@@ -110,9 +84,9 @@ int main(int argc, char* argv[]) try {
}
});
bound_symbol_list.write_to(args.m_output_path);
bound_symbol_list.write(args.m_output_path);
if (args.m_output_failed_path) {
raw_text.write_to(*args.m_output_failed_path);
raw_text.write(*args.m_output_failed_path);
}
std::println("Everything is OK.");

View File

@@ -55,13 +55,13 @@ int main(int argc, char* argv[]) try {
auto server_program =
std::make_unique<object_file::COFF>(args.server_program_path);
auto symbol_data =
std::make_unique<data_format::BoundSymbolList>(args.symbol_data_path);
auto symbol_data = std::make_unique<data_format::BoundSymbolList>();
symbol_data->read(args.symbol_data_path);
std::unique_ptr<data_format::RawTypeData> raw_type_data;
if (args.typeinfo_pdb_path) {
raw_type_data =
std::make_unique<data_format::RawTypeData>(*args.typeinfo_pdb_path);
raw_type_data = std::make_unique<data_format::RawTypeData>();
raw_type_data->read(*args.typeinfo_pdb_path);
}
object_file::PDB pdb;