diff --git a/src/data_format/bound_symbol_list.cpp b/src/data_format/bound_symbol_list.cpp index 8bfb2ed..0be4a12 100644 --- a/src/data_format/bound_symbol_list.cpp +++ b/src/data_format/bound_symbol_list.cpp @@ -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 diff --git a/src/data_format/bound_symbol_list.h b/src/data_format/bound_symbol_list.h index c616764..c51f3e5 100644 --- a/src/data_format/bound_symbol_list.h +++ b/src/data_format/bound_symbol_list.h @@ -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; - 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); diff --git a/src/data_format/human_readable_symbol_list.cpp b/src/data_format/human_readable_symbol_list.cpp deleted file mode 100644 index 36d53f9..0000000 --- a/src/data_format/human_readable_symbol_list.cpp +++ /dev/null @@ -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 diff --git a/src/data_format/human_readable_symbol_list.h b/src/data_format/human_readable_symbol_list.h deleted file mode 100644 index 6318d07..0000000 --- a/src/data_format/human_readable_symbol_list.h +++ /dev/null @@ -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 m_symbol_rva_map; -}; - -} // namespace di::data_format diff --git a/src/data_format/io_base.h b/src/data_format/io_base.h new file mode 100644 index 0000000..6bcb283 --- /dev/null +++ b/src/data_format/io_base.h @@ -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 diff --git a/src/data_format/raw_text.cpp b/src/data_format/raw_text.cpp index 98a6611..6547a32 100644 --- a/src/data_format/raw_text.cpp +++ b/src/data_format/raw_text.cpp @@ -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(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 diff --git a/src/data_format/raw_text.h b/src/data_format/raw_text.h index 11b6a0a..654a4e1 100644 --- a/src/data_format/raw_text.h +++ b/src/data_format/raw_text.h @@ -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; diff --git a/src/data_format/raw_type_data.cpp b/src/data_format/raw_type_data.cpp index e179729..b3d9b2e 100644 --- a/src/data_format/raw_type_data.cpp +++ b/src/data_format/raw_type_data.cpp @@ -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 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."); } diff --git a/src/data_format/raw_type_data.h b/src/data_format/raw_type_data.h index 57fadec..09238d0 100644 --- a/src/data_format/raw_type_data.h +++ b/src/data_format/raw_type_data.h @@ -1,17 +1,24 @@ #pragma once +#include "data_format/io_base.h" + #include namespace di::data_format { -class RawTypeData { +class RawTypeData : public IOBase { public: using for_each_callback_t = std::function; 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 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 diff --git a/src/data_format/type/decl_type.h b/src/data_format/type/decl_type.h index b9dc1b6..ba20251 100644 --- a/src/data_format/type/decl_type.h +++ b/src/data_format/type/decl_type.h @@ -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; } diff --git a/src/data_format/typed_symbol_list.cpp b/src/data_format/typed_symbol_list.cpp index 0d3880d..550a193 100644 --- a/src/data_format/typed_symbol_list.cpp +++ b/src/data_format/typed_symbol_list.cpp @@ -2,33 +2,40 @@ namespace di::data_format { -TypedSymbolList::TypedSymbolList(const std::vector& 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 diff --git a/src/data_format/typed_symbol_list.h b/src/data_format/typed_symbol_list.h index dba24ae..34c9b62 100644 --- a/src/data_format/typed_symbol_list.h +++ b/src/data_format/typed_symbol_list.h @@ -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; - explicit TypedSymbolList(const std::string& path) - : TypedSymbolList(std::vector{path}) {}; - explicit TypedSymbolList(const std::vector& 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); diff --git a/src/object_file/COFF.cpp b/src/object_file/COFF.cpp index 309edee..52810bc 100644 --- a/src/object_file/COFF.cpp +++ b/src/object_file/COFF.cpp @@ -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."); } diff --git a/src/object_file/COFF.h b/src/object_file/COFF.h index f5fbc44..35429f6 100644 --- a/src/object_file/COFF.h +++ b/src/object_file/COFF.h @@ -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; diff --git a/src/object_file/PDB.cpp b/src/object_file/PDB.cpp index c4b3e9e..c285d1f 100644 --- a/src/object_file/PDB.cpp +++ b/src/object_file/PDB.cpp @@ -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!"); } } diff --git a/src/object_file/PDB.h b/src/object_file/PDB.h index c2cc5ba..e565221 100644 --- a/src/object_file/PDB.h +++ b/src/object_file/PDB.h @@ -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(); diff --git a/src/pch.h b/src/pch.h index bc4a97f..9e53107 100644 --- a/src/pch.h +++ b/src/pch.h @@ -6,6 +6,7 @@ using namespace llvm; // Standard Libraries +#include #include #include diff --git a/src/tools/askrva/main.cpp b/src/tools/askrva/main.cpp index 8ef1265..046fc87 100644 --- a/src/tools/askrva/main.cpp +++ b/src/tools/askrva/main.cpp @@ -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 #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 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("--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."); diff --git a/src/tools/makepdb/main.cpp b/src/tools/makepdb/main.cpp index 5b79c40..1303beb 100644 --- a/src/tools/makepdb/main.cpp +++ b/src/tools/makepdb/main.cpp @@ -55,13 +55,13 @@ int main(int argc, char* argv[]) try { auto server_program = std::make_unique(args.server_program_path); - auto symbol_data = - std::make_unique(args.symbol_data_path); + auto symbol_data = std::make_unique(); + symbol_data->read(args.symbol_data_path); std::unique_ptr raw_type_data; if (args.typeinfo_pdb_path) { - raw_type_data = - std::make_unique(*args.typeinfo_pdb_path); + raw_type_data = std::make_unique(); + raw_type_data->read(*args.typeinfo_pdb_path); } object_file::PDB pdb;