refactor: unified data_format IO.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
13
src/data_format/io_base.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -6,6 +6,7 @@ using namespace llvm;
|
||||
|
||||
// Standard Libraries
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <print>
|
||||
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user