refactor: new project structure.
This commit is contained in:
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# vscode
|
||||
.vscode
|
||||
|
||||
# c++/xmake
|
||||
.xmake
|
||||
build
|
||||
|
||||
# c++/clangd
|
||||
.cache
|
||||
.clangd
|
||||
|
||||
# python
|
||||
__pycache__
|
||||
.venv
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "DumpSYM"]
|
||||
path = DumpSYM
|
||||
url = https://github.com/Redbeanw44602/dumpsym.git
|
||||
@@ -1,46 +0,0 @@
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: BlockIndent
|
||||
AlignArrayOfStructures: Left
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: true
|
||||
PadOperators: true
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AlignOperands: AlignAfterOperator
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakTemplateDeclarations: 'Yes'
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerIndentWidth: 0
|
||||
IndentWidth: 4
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: 2
|
||||
PackConstructorInitializers: CurrentLine
|
||||
PointerAlignment: Left
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
SortIncludes: CaseSensitive
|
||||
9
AskRVA/.gitignore
vendored
9
AskRVA/.gitignore
vendored
@@ -1,9 +0,0 @@
|
||||
# VSCode
|
||||
.vscode
|
||||
|
||||
# XMake
|
||||
.xmake
|
||||
build
|
||||
|
||||
# ClangD
|
||||
.cache
|
||||
@@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "symbol.h"
|
||||
@@ -1,37 +0,0 @@
|
||||
#include "format/input/decl_type.h"
|
||||
|
||||
#include "util/string.h"
|
||||
|
||||
namespace format::input {
|
||||
|
||||
DeclType::DeclType(std::string_view str) {
|
||||
using namespace util::string;
|
||||
|
||||
// clang-format off
|
||||
|
||||
switch (H(str)) {
|
||||
#define HSTR(x) \
|
||||
case H(#x): \
|
||||
m_data = x; \
|
||||
break
|
||||
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::invalid_argument("Unexpected decl type.");
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
} // namespace format::input
|
||||
@@ -1,55 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace format::input {
|
||||
|
||||
class DeclType {
|
||||
public:
|
||||
enum Enum {
|
||||
Function,
|
||||
CXXDeductionGuide,
|
||||
CXXMethod,
|
||||
CXXConstructor,
|
||||
CXXConversion,
|
||||
CXXDestructor,
|
||||
|
||||
Var,
|
||||
Decomposition,
|
||||
ImplicitParam,
|
||||
OMPCapturedExpr,
|
||||
ParamVar,
|
||||
VarTemplateSpecialization,
|
||||
|
||||
COUNT
|
||||
};
|
||||
|
||||
explicit DeclType(Enum value) : m_data(value) {}
|
||||
explicit DeclType(std::string_view str);
|
||||
|
||||
bool isFunction() const { return m_data >= Function && m_data < Var; }
|
||||
bool isVar() const { return m_data >= Var && m_data < COUNT; }
|
||||
|
||||
Enum data() const { return m_data; }
|
||||
|
||||
bool operator==(const DeclType& other) const { return m_data == other.m_data; }
|
||||
|
||||
private:
|
||||
Enum m_data;
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
std::string m_name;
|
||||
DeclType m_type;
|
||||
|
||||
bool operator==(const Symbol& other) const { return m_name == other.m_name; }
|
||||
};
|
||||
|
||||
} // namespace format::input
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct hash<format::input::Symbol> {
|
||||
size_t operator()(const format::input::Symbol& symbol) const { return hash<string>{}(symbol.m_name); }
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "format/input/decl_type.h"
|
||||
|
||||
namespace format::input {
|
||||
|
||||
class SymbolListFile {
|
||||
public:
|
||||
[[nodiscard]] static SymbolListFile load(std::string_view path);
|
||||
[[nodiscard]] static SymbolListFile load(const std::vector<std::string>& path);
|
||||
|
||||
void for_each(const std::function<void(Symbol)>& callback);
|
||||
|
||||
private:
|
||||
SymbolListFile() = default;
|
||||
|
||||
std::unordered_set<Symbol> m_data;
|
||||
};
|
||||
|
||||
} // namespace format::input
|
||||
@@ -1,35 +0,0 @@
|
||||
#include "format/output/all.h"
|
||||
|
||||
#include "format/output/fakepdb.h"
|
||||
#include "format/output/makepdb.h"
|
||||
#include "format/output/text.h"
|
||||
|
||||
namespace format::output {
|
||||
|
||||
void DefaultOutputFile::record_failure(std::string_view symbol) { m_failed_symbols.emplace(symbol); }
|
||||
|
||||
void DefaultOutputFile::save_failure(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 : m_failed_symbols) {
|
||||
ofs << symbol << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<IOutputFile> create(OutputFormat format) {
|
||||
switch (format) {
|
||||
case OutputFormat::Text:
|
||||
return std::make_unique<OutputTextFile>();
|
||||
case OutputFormat::FakePDB:
|
||||
return std::make_unique<OutputFakePDBFile>();
|
||||
case OutputFormat::MakePDB:
|
||||
return std::make_unique<OutputMakePDBFile>();
|
||||
default:
|
||||
throw std::invalid_argument("Invalid output file format.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace format::output
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace format {
|
||||
|
||||
enum class OutputFormat { Text, FakePDB, MakePDB };
|
||||
|
||||
namespace output {
|
||||
|
||||
class IOutputFile {
|
||||
public:
|
||||
virtual ~IOutputFile() = default;
|
||||
|
||||
virtual void record(std::string_view symbol, uint64_t rva, bool is_function) = 0;
|
||||
virtual void save(std::string_view path) const = 0;
|
||||
|
||||
virtual void record_failure(std::string_view symbol) = 0;
|
||||
virtual void save_failure(std::string_view path) const = 0;
|
||||
};
|
||||
|
||||
class DefaultOutputFile : public IOutputFile {
|
||||
public:
|
||||
void record_failure(std::string_view symbol) override;
|
||||
void save_failure(std::string_view path) const override;
|
||||
|
||||
protected:
|
||||
std::unordered_set<std::string> m_failed_symbols;
|
||||
};
|
||||
|
||||
std::unique_ptr<IOutputFile> create(OutputFormat format);
|
||||
|
||||
} // namespace output
|
||||
|
||||
} // namespace format
|
||||
@@ -1,21 +0,0 @@
|
||||
#include "format/output/fakepdb.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace format::output {
|
||||
|
||||
void OutputFakePDBFile::save(std::string_view path) const {
|
||||
std::ofstream ofs(path.data());
|
||||
if (!ofs) {
|
||||
throw std::runtime_error("Failed to open save file.");
|
||||
}
|
||||
|
||||
nlohmann::json data;
|
||||
for (const auto& [symbol, rva] : m_symbol_rva_map) {
|
||||
data[symbol] = std::format("{:#x}", rva);
|
||||
}
|
||||
|
||||
ofs << data.dump(4);
|
||||
}
|
||||
|
||||
} // namespace format::output
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "format/output/text.h"
|
||||
|
||||
namespace format::output {
|
||||
|
||||
class OutputFakePDBFile : public OutputTextFile {
|
||||
public:
|
||||
void save(std::string_view path) const override;
|
||||
};
|
||||
|
||||
} // namespace format::output
|
||||
@@ -1,33 +0,0 @@
|
||||
#include "format/output/makepdb.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace format::output {
|
||||
|
||||
void OutputMakePDBFile::record(std::string_view symbol, uint64_t rva, bool is_function) {
|
||||
m_records.emplace(std::string(symbol), rva, is_function);
|
||||
}
|
||||
|
||||
void OutputMakePDBFile::save(std::string_view path) const {
|
||||
std::ofstream ofs(path.data());
|
||||
if (!ofs) {
|
||||
throw std::runtime_error("Failed to open save file.");
|
||||
}
|
||||
|
||||
nlohmann::json data;
|
||||
|
||||
// MakePDB - Format V1
|
||||
data["version"] = 1;
|
||||
|
||||
for (const auto& [symbol, rva, is_fun] : m_records) {
|
||||
data["data"].emplace_back(nlohmann::json{
|
||||
{"symbol", symbol},
|
||||
{"rva", rva },
|
||||
{"is_function", is_fun}
|
||||
});
|
||||
}
|
||||
|
||||
ofs << data.dump(4);
|
||||
}
|
||||
|
||||
} // namespace format::output
|
||||
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "format/output/all.h"
|
||||
|
||||
namespace format::output {
|
||||
|
||||
class OutputMakePDBFile : public DefaultOutputFile {
|
||||
public:
|
||||
void record(std::string_view symbol, uint64_t rva, bool is_function) override;
|
||||
void save(std::string_view path) const override;
|
||||
|
||||
private:
|
||||
std::unordered_set<std::tuple<std::string, uint64_t, bool>> m_records;
|
||||
};
|
||||
|
||||
} // namespace format::output
|
||||
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "format/output/all.h"
|
||||
|
||||
namespace format::output {
|
||||
|
||||
class OutputTextFile : public DefaultOutputFile {
|
||||
public:
|
||||
void record(std::string_view symbol, uint64_t rva, bool is_function) override;
|
||||
void save(std::string_view path) const override;
|
||||
|
||||
protected:
|
||||
std::unordered_map<std::string, uint64_t> m_symbol_rva_map;
|
||||
};
|
||||
|
||||
} // namespace format::output
|
||||
@@ -1,31 +0,0 @@
|
||||
add_rules('mode.debug', 'mode.release')
|
||||
|
||||
set_allowedplats('windows')
|
||||
set_allowedarchs('x64')
|
||||
|
||||
add_repositories('liteldev-repo https://github.com/LiteLDev/xmake-repo.git')
|
||||
|
||||
-- from xmake-repo
|
||||
add_requires('argparse 3.1')
|
||||
add_requires('nlohmann_json 3.11.3')
|
||||
|
||||
-- from liteldev-repo
|
||||
add_requires('preloader 1.12.0')
|
||||
|
||||
target('askrva')
|
||||
set_kind('binary')
|
||||
add_files('src/**.cpp')
|
||||
add_includedirs('src')
|
||||
set_warnings('all')
|
||||
set_languages('c23', 'c++23')
|
||||
set_pcxxheader('src/pch.h')
|
||||
|
||||
add_packages(
|
||||
'argparse',
|
||||
'nlohmann_json',
|
||||
'preloader'
|
||||
)
|
||||
|
||||
if is_mode('debug') then
|
||||
add_defines('DEBUG')
|
||||
end
|
||||
9
BlobExtractor/.gitignore
vendored
9
BlobExtractor/.gitignore
vendored
@@ -1,9 +0,0 @@
|
||||
# VSCode
|
||||
.vscode
|
||||
|
||||
# XMake
|
||||
.xmake
|
||||
build
|
||||
|
||||
# ClangD
|
||||
.cache
|
||||
@@ -1,14 +0,0 @@
|
||||
add_rules('mode.debug', 'mode.release')
|
||||
|
||||
add_requires('xxhash')
|
||||
|
||||
target('blob-extractor')
|
||||
set_kind('binary')
|
||||
add_files('src/**.cpp')
|
||||
add_includedirs('src')
|
||||
set_warnings('all')
|
||||
set_languages('c23', 'c++23')
|
||||
|
||||
if is_mode('debug') then
|
||||
add_defines('DEBUG')
|
||||
end
|
||||
5
Bootstrap/.gitignore
vendored
5
Bootstrap/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
# Python
|
||||
.venv
|
||||
|
||||
# VSCode
|
||||
.vscode
|
||||
6
DeThunk/.gitignore
vendored
6
DeThunk/.gitignore
vendored
@@ -1,6 +0,0 @@
|
||||
# Python
|
||||
__pycache__
|
||||
.venv
|
||||
|
||||
# VSCode
|
||||
.vscode
|
||||
@@ -1,17 +0,0 @@
|
||||
# Same as Black.
|
||||
line-length = 100
|
||||
indent-width = 4
|
||||
|
||||
# Assume Python 3.12
|
||||
target-version = "py312"
|
||||
|
||||
[lint]
|
||||
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
|
||||
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
|
||||
# McCabe complexity (`C901`) by default.
|
||||
select = ["E", "F", "W"]
|
||||
ignore = ["E501"]
|
||||
|
||||
[format]
|
||||
# Like Black, use double quotes for strings.
|
||||
quote-style = "single"
|
||||
1
DumpSYM
1
DumpSYM
Submodule DumpSYM deleted from 6cf0947308
@@ -1,45 +0,0 @@
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: BlockIndent
|
||||
AlignArrayOfStructures: Left
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: true
|
||||
PadOperators: true
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AlignOperands: AlignAfterOperator
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakTemplateDeclarations: "Yes"
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
CommentPragmas: "^ IWYU pragma:"
|
||||
ConstructorInitializerIndentWidth: 0
|
||||
IndentWidth: 4
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: 2
|
||||
PackConstructorInitializers: CurrentLine
|
||||
PointerAlignment: Left
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
SortIncludes: CaseSensitive
|
||||
9
ExtractSYM/.gitignore
vendored
9
ExtractSYM/.gitignore
vendored
@@ -1,9 +0,0 @@
|
||||
# VSCode
|
||||
.vscode
|
||||
|
||||
# XMake
|
||||
.xmake
|
||||
build
|
||||
|
||||
# ClangD
|
||||
.cache
|
||||
@@ -1,22 +0,0 @@
|
||||
add_rules('mode.debug', 'mode.release')
|
||||
|
||||
add_requires('llvm')
|
||||
add_requires('argparse 3.1')
|
||||
|
||||
target('extractsym')
|
||||
set_kind('binary')
|
||||
add_files('src/**.cpp')
|
||||
add_includedirs('src')
|
||||
set_warnings('all')
|
||||
set_languages('c23', 'c++23')
|
||||
|
||||
add_packages(
|
||||
'llvm',
|
||||
'argparse'
|
||||
)
|
||||
|
||||
add_links('LLVM')
|
||||
|
||||
if is_mode('debug') then
|
||||
add_defines('DEBUG')
|
||||
end
|
||||
@@ -1,45 +0,0 @@
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: BlockIndent
|
||||
AlignArrayOfStructures: Left
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: true
|
||||
PadOperators: true
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AlignOperands: AlignAfterOperator
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakTemplateDeclarations: "Yes"
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
CommentPragmas: "^ IWYU pragma:"
|
||||
ConstructorInitializerIndentWidth: 0
|
||||
IndentWidth: 4
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: 2
|
||||
PackConstructorInitializers: CurrentLine
|
||||
PointerAlignment: Left
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
SortIncludes: CaseSensitive
|
||||
9
MakePDB/.gitignore
vendored
9
MakePDB/.gitignore
vendored
@@ -1,9 +0,0 @@
|
||||
# VSCode
|
||||
.vscode
|
||||
|
||||
# XMake
|
||||
.xmake
|
||||
build
|
||||
|
||||
# ClangD
|
||||
.cache
|
||||
@@ -1,53 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "binary/COFF.h"
|
||||
|
||||
#include "raw_type_data.h"
|
||||
#include "symbol_data.h"
|
||||
|
||||
#include <llvm/DebugInfo/PDB/Native/PDBFileBuilder.h>
|
||||
#include <llvm/Support/Allocator.h>
|
||||
|
||||
namespace makepdb::binary {
|
||||
|
||||
class PDB {
|
||||
public:
|
||||
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);
|
||||
|
||||
private:
|
||||
void build();
|
||||
|
||||
inline void build_Info();
|
||||
inline void build_DBI();
|
||||
inline void build_TPI();
|
||||
inline void build_GSI();
|
||||
|
||||
OwningCOFF m_owning_coff;
|
||||
OwningSymbolData m_owning_symbol_data;
|
||||
OwningRawTypeData m_owning_raw_type_data;
|
||||
|
||||
uint64_t m_image_base;
|
||||
|
||||
BumpPtrAllocator m_allocator;
|
||||
pdb::PDBFileBuilder m_builder;
|
||||
};
|
||||
|
||||
} // namespace makepdb::binary
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
template <typename To, typename From>
|
||||
constexpr auto static_unique_ptr_cast(std::unique_ptr<From>&& F) {
|
||||
return std::unique_ptr<To>(static_cast<To*>(F.release()));
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
|
||||
// Work on llvm namespace.
|
||||
|
||||
namespace llvm {}
|
||||
using namespace llvm;
|
||||
|
||||
// Standard Libraries
|
||||
|
||||
#include <fstream>
|
||||
#include <print>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
// Helper
|
||||
|
||||
#include "nonstd.h"
|
||||
@@ -1,32 +0,0 @@
|
||||
#include "symbol_data.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace makepdb {
|
||||
|
||||
SymbolData::SymbolData(std::string_view path) {
|
||||
std::ifstream ifs(path.data());
|
||||
if (!ifs) {
|
||||
throw std::runtime_error("Failed to open data path.");
|
||||
}
|
||||
|
||||
auto data = nlohmann::json::parse(ifs);
|
||||
if (data["version"] != 1) {
|
||||
throw std::runtime_error("Unsupported data version.");
|
||||
}
|
||||
|
||||
for (const auto& entity : data["data"]) {
|
||||
m_entities.emplace(SymbolDataEntity{
|
||||
entity["symbol"],
|
||||
entity["rva"],
|
||||
entity["is_function"]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolData::for_each(const std::function<void(SymbolDataEntity)> callback
|
||||
) const {
|
||||
for (const auto& entity : m_entities) callback(entity);
|
||||
}
|
||||
|
||||
} // namespace makepdb
|
||||
@@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace makepdb {
|
||||
|
||||
struct SymbolDataEntity {
|
||||
std::string symbol_name;
|
||||
uint64_t rva;
|
||||
bool is_function;
|
||||
|
||||
bool operator==(const SymbolDataEntity& other) const {
|
||||
return symbol_name == other.symbol_name && rva == other.rva
|
||||
&& is_function == other.is_function;
|
||||
}
|
||||
|
||||
struct Hash {
|
||||
size_t operator()(const SymbolDataEntity entity) const {
|
||||
size_t h1 = std::hash<std::string>{}(entity.symbol_name);
|
||||
size_t h2 = std::hash<uint64_t>{}(entity.rva);
|
||||
size_t h3 = std::hash<bool>{}(entity.is_function);
|
||||
return h1 ^ (h2 << 1) ^ (h3 << 2);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class SymbolData {
|
||||
public:
|
||||
explicit SymbolData(std::string_view path);
|
||||
|
||||
void for_each(const std::function<void(SymbolDataEntity)> callback) const;
|
||||
|
||||
private:
|
||||
std::unordered_set<SymbolDataEntity, SymbolDataEntity::Hash> m_entities;
|
||||
};
|
||||
|
||||
} // namespace makepdb
|
||||
@@ -1,25 +0,0 @@
|
||||
add_rules('mode.debug', 'mode.release')
|
||||
|
||||
add_requires('llvm')
|
||||
add_requires('nlohmann_json 3.11.3')
|
||||
add_requires('argparse 3.1')
|
||||
|
||||
target('makepdb')
|
||||
set_kind('binary')
|
||||
add_files('src/**.cpp')
|
||||
add_includedirs('src')
|
||||
set_warnings('all')
|
||||
set_languages('c23', 'c++23')
|
||||
set_pcxxheader('src/pch.h')
|
||||
|
||||
add_packages(
|
||||
'llvm',
|
||||
'nlohmann_json',
|
||||
'argparse'
|
||||
)
|
||||
|
||||
add_links('LLVM')
|
||||
|
||||
if is_mode('debug') then
|
||||
add_defines('DEBUG')
|
||||
end
|
||||
60
README.md
60
README.md
@@ -1,60 +1,78 @@
|
||||
# DebugInfo
|
||||
|
||||
This repository regenerates debug information (like PDB) from LeviLamina's public data.
|
||||
|
||||
## Background
|
||||
- After 1.21.3.01, Mojang removed debug information from BDS.
|
||||
- Mojang no longer provides any debugging information (both server and client) to the community.
|
||||
- Mojang has an agreement with LiteLDev to provide them with debug data.
|
||||
- LiteLDev generates header files and obfuscated symbol to RVA lookup tables from debug data and provides them to the community.
|
||||
|
||||
- After 1.21.3.01, Mojang removed debug information from BDS.
|
||||
- Mojang no longer provides any debugging information (both server and client) to the community.
|
||||
- Mojang has an agreement with LiteLDev to provide them with debug data.
|
||||
- LiteLDev generates header files and obfuscated symbol to RVA lookup tables from debug data and provides them to the community.
|
||||
|
||||
### Problems caused by Mojang's collaboration with LiteLDev
|
||||
- Mojang's collaboration with LiteLDev is opaque and we have no idea what they do.
|
||||
- LiteLDev has completed its monopoly, and there will no longer be a second mod loader in the community.
|
||||
- Due to the obfuscated format, the community can no longer reverse engineer BDS.
|
||||
|
||||
- Mojang's collaboration with LiteLDev is opaque and we have no idea what they do.
|
||||
- LiteLDev has completed its monopoly, and there will no longer be a second mod loader in the community.
|
||||
- Due to the obfuscated format, the community can no longer reverse engineer BDS.
|
||||
|
||||
### Header files, obfuscation format and security
|
||||
- LeviLamina's design necessitates that they publish header files.
|
||||
- The header file contains all the declaration information so that symbols can be generated.
|
||||
- The RVA of the corresponding symbol can be extracted from the obfuscated format at runtime.
|
||||
- The obfuscated format is actually a carrier of the complete "symbol table", which used to be PDB/DWARF.
|
||||
|
||||
- LeviLamina's design necessitates that they publish header files.
|
||||
- The header file contains all the declaration information so that symbols can be generated.
|
||||
- The RVA of the corresponding symbol can be extracted from the obfuscated format at runtime.
|
||||
- The obfuscated format is actually a carrier of the complete "symbol table", which used to be PDB/DWARF.
|
||||
|
||||
## Tool for restoring original DebugInfo from obfuscated format
|
||||
|
||||
> [!NOTE]
|
||||
> LiteLDev has not yet released bedrock_runtime_data/magicblob for the Linux server.
|
||||
|
||||
They are dethunk, dumpsym, askrva and makepdb. Each tool is in a directory with the same name as it, and also has a README to help you use it.
|
||||
In short, the PDB is generated by the following steps:
|
||||
- Preprocess the header files published by LiteLDev by dethunk.
|
||||
|
||||
- Preprocess the header files published by LiteLDev by dethunk.
|
||||
|
||||
```
|
||||
python main.py {HEADER_PROJECT_DIR}/src
|
||||
```
|
||||
- Compile the header file and load the dumpsym plugin in the compilation parameters.
|
||||
|
||||
- Compile the header file and load the dumpsym plugin in the compilation parameters.
|
||||
|
||||
```
|
||||
xmake f -c -p windows -a x64 -m release --sdk=/opt/msvc --cxflags="-fplugin=/path/to/libdumpsym.so -fplugin-arg-dumpsym-record-decl-name" --toolchain=clang
|
||||
xmake -v
|
||||
```
|
||||
- Find the generated symbols file.
|
||||
|
||||
- Find the generated symbols file.
|
||||
|
||||
```
|
||||
{HEADER_PROJECT_DIR}/build/.objs/bdsheader/windows/x64/release/test/__cpp_main.cpp.cpp.symbols
|
||||
```
|
||||
- Generate symbol table using askrva.
|
||||
|
||||
- Generate symbol table using askrva.
|
||||
|
||||
```
|
||||
./askrva __cpp_main.cpp.cpp.symbols --output succeed.json --output-failed failed.txt --output-format=makepdb
|
||||
```
|
||||
- Generate PDB using makepdb.
|
||||
|
||||
- Generate PDB using makepdb.
|
||||
|
||||
```
|
||||
./makepdb --program bedrock_server.exe --symbol-data succeed.json --output bedrock_server.pdb
|
||||
```
|
||||
|
||||
## TODO
|
||||
- [ ] Tap into more available symbols.
|
||||
- [ ] Fully open source HeaderGen.
|
||||
- [ ] Bootstrap.
|
||||
- [ ] Opti project structure.
|
||||
|
||||
- [ ] Tap into more available symbols.
|
||||
- [ ] Fully open source HeaderGen.
|
||||
- [ ] Bootstrap.
|
||||
|
||||
## Be with us
|
||||
|
||||
Our vision is to build an open and inclusive Minecraft: Bedrock Edition ecosystem.
|
||||
- [https://t.me/bdsplugins](https://t.me/s/bdsplugins)
|
||||
|
||||
- [https://t.me/bdsplugins](https://t.me/s/bdsplugins)
|
||||
|
||||
## LICENSE
|
||||
|
||||
All tools are open source under the MIT license.
|
||||
|
||||
@@ -18,7 +18,7 @@ known as magicblob), PreLoader no longer handles PDB. The source code in the cur
|
||||
|
||||
### Usage
|
||||
|
||||
- --output-format can be `auto` / `txt` / `fakepdb` / `makepdb`
|
||||
- --output-format can be `auto` / `txt` / `makepdb`
|
||||
|
||||
```
|
||||
Usage: askrva [--help] [--version] --output VAR [--output-failed VAR] [--output-format VAR] path
|
||||
38
docs/dump-sym.md
Normal file
38
docs/dump-sym.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# DumpSYM
|
||||
|
||||
Sometimes, we need to extract symbols from declarations. So this compiler plugin was born.
|
||||
|
||||
### Build
|
||||
|
||||
> As far as I know, there are some problems with the clang plugin executing under Windows, so I recommend that all operations be performed under Linux.
|
||||
|
||||
- Building llvm will consume a lot of time and resources, it is recommended to pre-install llvm from your system package manager, xmake can detect system packages.
|
||||
- Run `xmake` to build.
|
||||
|
||||
### Usage
|
||||
|
||||
Simply pass `-fplugin=...` to clang and the plugin will run automatically.
|
||||
|
||||
#### Optional Arguments
|
||||
|
||||
- `record-decl-name` - Add the name of the Decl in the output, reference: [FunctionDecl](https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html), [VarDecl](https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html)
|
||||
|
||||
> [!NOTE]
|
||||
> Because LLVM is used, both ItaniumABI and MicrosoftABI are supported.
|
||||
|
||||
- Example:
|
||||
|
||||
```
|
||||
$ clang++ -fplugin=/path/to/plugin/libdumpsym.so -fplugin-arg-dumpsym-record-decl-name test.cpp
|
||||
```
|
||||
|
||||
- The result will be generated in the `<TU>.symbols` file
|
||||
|
||||
```
|
||||
$ cat test.cpp.symbols
|
||||
Function, main
|
||||
CXXDestructor, ??_DThreadPool@OS@@QEAAXXZ
|
||||
CXXConstructor, ??0SpinLockImpl@@QEAA@AEBV0@@Z
|
||||
CXXMethod, ??4SpinLockImpl@@QEAAAEAV0@AEBV0@@Z
|
||||
Var, ?Low@OSThreadPriority@Threading@Bedrock@@2V123@B
|
||||
```
|
||||
55
src/data_format/bound_symbol_list.cpp
Normal file
55
src/data_format/bound_symbol_list.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "data_format/bound_symbol_list.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace di::data_format {
|
||||
|
||||
constexpr int BOUND_SYMBOL_LIST_FORMAT_VERSION = 1;
|
||||
|
||||
BoundSymbolList::BoundSymbolList(std::string_view path) {
|
||||
std::ifstream ifs(path.data());
|
||||
if (!ifs) {
|
||||
throw std::runtime_error("Failed to open data path.");
|
||||
}
|
||||
|
||||
auto data = nlohmann::json::parse(ifs);
|
||||
if (data["version"] != BOUND_SYMBOL_LIST_FORMAT_VERSION) {
|
||||
throw std::runtime_error("Unsupported data version.");
|
||||
}
|
||||
|
||||
for (const auto& entity : data["data"]) {
|
||||
m_entities.emplace(
|
||||
BoundSymbol{entity["symbol"], entity["rva"], entity["is_function"]}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
std::ofstream ofs(path);
|
||||
if (!ofs) {
|
||||
throw std::runtime_error("Failed to open file!");
|
||||
}
|
||||
|
||||
nlohmann::json data;
|
||||
|
||||
data["version"] = BOUND_SYMBOL_LIST_FORMAT_VERSION;
|
||||
for (const auto& entity : m_entities) {
|
||||
data["data"].emplace_back(nlohmann::json{
|
||||
{"symbol", entity.m_symbol_name},
|
||||
{"rva", entity.m_rva },
|
||||
{"is_function", entity.m_is_function}
|
||||
});
|
||||
}
|
||||
|
||||
ofs << data.dump(4);
|
||||
}
|
||||
|
||||
} // namespace di::data_format
|
||||
25
src/data_format/bound_symbol_list.h
Normal file
25
src/data_format/bound_symbol_list.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "data_format/type/bound_symbol.h"
|
||||
|
||||
namespace di::data_format {
|
||||
|
||||
class BoundSymbolList {
|
||||
public:
|
||||
using for_each_callback_t = std::function<void(BoundSymbol const&)>;
|
||||
|
||||
explicit BoundSymbolList() = default;
|
||||
explicit BoundSymbolList(std::string_view path);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_set<BoundSymbol> m_entities;
|
||||
};
|
||||
|
||||
} // namespace di::data_format
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "format/output/text.h"
|
||||
#include "data_format/human_readable_symbol_list.h"
|
||||
|
||||
namespace format::output {
|
||||
namespace di::data_format {
|
||||
|
||||
void OutputTextFile::record(std::string_view symbol, uint64_t rva, bool is_function) {
|
||||
void HumanReadableSymbolList::record(std::string_view symbol, uint64_t rva) {
|
||||
m_symbol_rva_map.try_emplace(std::string(symbol), rva);
|
||||
}
|
||||
|
||||
void OutputTextFile::save(std::string_view path) const {
|
||||
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.");
|
||||
@@ -17,4 +17,4 @@ void OutputTextFile::save(std::string_view path) const {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace format::output
|
||||
} // namespace di::data_format
|
||||
14
src/data_format/human_readable_symbol_list.h
Normal file
14
src/data_format/human_readable_symbol_list.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#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
|
||||
19
src/data_format/raw_text.cpp
Normal file
19
src/data_format/raw_text.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "data_format/raw_text.h"
|
||||
|
||||
namespace di::data_format {
|
||||
|
||||
void RawText::record(std::string_view content) {
|
||||
m_data += content;
|
||||
m_data += '\n';
|
||||
}
|
||||
|
||||
void RawText::write_to(std::string_view path) const {
|
||||
std::ofstream ofs(path.data());
|
||||
if (!ofs) {
|
||||
throw std::runtime_error("Failed to open save file.");
|
||||
}
|
||||
|
||||
ofs << m_data;
|
||||
}
|
||||
|
||||
} // namespace di::data_format
|
||||
14
src/data_format/raw_text.h
Normal file
14
src/data_format/raw_text.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace di::data_format {
|
||||
|
||||
class RawText {
|
||||
public:
|
||||
void record(std::string_view line);
|
||||
void write_to(std::string_view path) const;
|
||||
|
||||
private:
|
||||
std::string m_data;
|
||||
};
|
||||
|
||||
} // namespace di::data_format
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "raw_type_data.h"
|
||||
#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>
|
||||
@@ -9,7 +10,7 @@
|
||||
|
||||
using namespace llvm::pdb;
|
||||
|
||||
namespace makepdb {
|
||||
namespace di::data_format {
|
||||
|
||||
RawTypeData::RawTypeData(std::string_view path)
|
||||
: m_storaged_TPI(m_allocator),
|
||||
@@ -51,4 +52,4 @@ RawTypeData::RawTypeData(std::string_view path)
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace makepdb
|
||||
} // namespace di::data_format
|
||||
@@ -1,13 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h>
|
||||
#include <llvm/DebugInfo/CodeView/TypeStreamMerger.h>
|
||||
|
||||
namespace makepdb {
|
||||
namespace di::data_format {
|
||||
|
||||
class RawTypeData {
|
||||
public:
|
||||
using ForEachTpiCallback =
|
||||
using for_each_callback_t =
|
||||
std::function<void(codeview::TypeIndex, codeview::CVType)>;
|
||||
|
||||
enum TypedStream { TPI, IPI };
|
||||
@@ -15,7 +14,7 @@ public:
|
||||
explicit RawTypeData(std::string_view path);
|
||||
|
||||
template <TypedStream Stream>
|
||||
void for_each(const ForEachTpiCallback& callback) /*const*/ {
|
||||
void for_each(const for_each_callback_t& callback) /*const*/ {
|
||||
if constexpr (Stream == TPI) {
|
||||
return m_storaged_TPI.ForEachRecord(callback);
|
||||
}
|
||||
@@ -31,4 +30,4 @@ private:
|
||||
codeview::MergingTypeTableBuilder m_storaged_IPI;
|
||||
};
|
||||
|
||||
} // namespace makepdb
|
||||
} // namespace di::data_format
|
||||
33
src/data_format/type/bound_symbol.h
Normal file
33
src/data_format/type/bound_symbol.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
namespace di {
|
||||
|
||||
struct BoundSymbol {
|
||||
std::string m_symbol_name;
|
||||
uint64_t m_rva;
|
||||
bool m_is_function;
|
||||
|
||||
bool operator==(const BoundSymbol& other) const {
|
||||
return m_symbol_name == other.m_symbol_name && m_rva == other.m_rva
|
||||
&& m_is_function == other.m_is_function;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace di
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct hash<di::BoundSymbol> {
|
||||
constexpr size_t operator()(const di::BoundSymbol& symbol) const {
|
||||
size_t seed = 0;
|
||||
boost::hash_combine(seed, symbol.m_symbol_name);
|
||||
boost::hash_combine(seed, symbol.m_rva);
|
||||
boost::hash_combine(seed, symbol.m_is_function);
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
75
src/data_format/type/decl_type.h
Normal file
75
src/data_format/type/decl_type.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/string.h"
|
||||
|
||||
namespace di {
|
||||
|
||||
class DeclType {
|
||||
public:
|
||||
enum Enum {
|
||||
Function,
|
||||
CXXDeductionGuide,
|
||||
CXXMethod,
|
||||
CXXConstructor,
|
||||
CXXConversion,
|
||||
CXXDestructor,
|
||||
|
||||
Var,
|
||||
Decomposition,
|
||||
ImplicitParam,
|
||||
OMPCapturedExpr,
|
||||
ParamVar,
|
||||
VarTemplateSpecialization,
|
||||
|
||||
COUNT
|
||||
};
|
||||
|
||||
constexpr explicit DeclType(Enum value) : m_data(value) {}
|
||||
constexpr explicit DeclType(std::string_view str) {
|
||||
using namespace util::string;
|
||||
|
||||
// clang-format off
|
||||
|
||||
switch (H(str)) {
|
||||
#define HSTR(x) \
|
||||
case H(#x): \
|
||||
m_data = x; \
|
||||
break
|
||||
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::invalid_argument("Unexpected decl type.");
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
constexpr bool is_function() const {
|
||||
return m_data >= Function && m_data < Var;
|
||||
}
|
||||
constexpr bool is_variable() const {
|
||||
return m_data >= Var && m_data < COUNT;
|
||||
}
|
||||
|
||||
constexpr Enum data() const { return m_data; }
|
||||
|
||||
constexpr bool operator==(const DeclType& other) const {
|
||||
return m_data == other.m_data;
|
||||
}
|
||||
|
||||
private:
|
||||
Enum m_data;
|
||||
};
|
||||
|
||||
} // namespace di
|
||||
27
src/data_format/type/typed_symbol.h
Normal file
27
src/data_format/type/typed_symbol.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "data_format/type/decl_type.h"
|
||||
|
||||
namespace di {
|
||||
|
||||
struct TypedSymbol {
|
||||
std::string m_name;
|
||||
DeclType m_type;
|
||||
|
||||
constexpr bool operator==(const TypedSymbol& other) const {
|
||||
return m_name == other.m_name;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace di
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct hash<di::TypedSymbol> {
|
||||
constexpr size_t operator()(const di::TypedSymbol& symbol) const {
|
||||
return std::hash<std::string>{}(symbol.m_name);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
@@ -1,12 +1,8 @@
|
||||
#include "format/input/symbol.h"
|
||||
#include "data_format/typed_symbol_list.h"
|
||||
|
||||
namespace format::input {
|
||||
|
||||
SymbolListFile SymbolListFile::load(std::string_view path) { return load(std::vector<std::string>{path.data()}); }
|
||||
|
||||
SymbolListFile SymbolListFile::load(const std::vector<std::string>& paths) {
|
||||
SymbolListFile result;
|
||||
namespace di::data_format {
|
||||
|
||||
TypedSymbolList::TypedSymbolList(const std::vector<std::string>& paths) {
|
||||
for (const auto& path : paths) {
|
||||
std::ifstream ifs(path.data());
|
||||
if (!ifs) {
|
||||
@@ -20,24 +16,19 @@ SymbolListFile SymbolListFile::load(const std::vector<std::string>& paths) {
|
||||
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."
|
||||
"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);
|
||||
|
||||
result.m_data.emplace(symbol, DeclType(declType_s));
|
||||
m_data.emplace(symbol, DeclType(declType_s));
|
||||
}
|
||||
|
||||
std::println("Read {} symbols from dumped symlist.", result.m_data.size());
|
||||
std::println("Read {} symbols from dumped symlist.", m_data.size());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SymbolListFile::for_each(const std::function<void(Symbol)>& callback) {
|
||||
for (const auto& entity : m_data) callback(entity);
|
||||
}
|
||||
|
||||
} // namespace format::input
|
||||
} // namespace di::data_format
|
||||
23
src/data_format/typed_symbol_list.h
Normal file
23
src/data_format/typed_symbol_list.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "data_format/type/typed_symbol.h"
|
||||
|
||||
namespace di::data_format {
|
||||
|
||||
class TypedSymbolList {
|
||||
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);
|
||||
|
||||
constexpr void for_each(const for_each_callback_t& callback) const {
|
||||
for (const auto& entity : m_data) callback(entity);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_set<TypedSymbol> m_data;
|
||||
};
|
||||
|
||||
} // namespace di::data_format
|
||||
119
src/frontend_action/dump_symbol.cpp
Normal file
119
src/frontend_action/dump_symbol.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "frontend_action/dump_symbol.h"
|
||||
|
||||
#include <clang/AST/ASTConsumer.h>
|
||||
#include <clang/AST/Mangle.h>
|
||||
#include <clang/AST/RecursiveASTVisitor.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
|
||||
bool config_record_decl_name = false;
|
||||
|
||||
class Container : private std::unordered_set<std::string> {
|
||||
public:
|
||||
void put(const std::string& symbol) { emplace(symbol); }
|
||||
|
||||
void write_to(const std::string& path) {
|
||||
std::ofstream ofs(path);
|
||||
if (ofs) {
|
||||
for (const auto& E : *this) {
|
||||
ofs << E << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Visitor : public RecursiveASTVisitor<Visitor> {
|
||||
public:
|
||||
Visitor(ASTContext& context, Container& container)
|
||||
: m_namegen(context),
|
||||
m_symbol_container(container) {}
|
||||
|
||||
bool VisitNamedDecl(NamedDecl* decl) {
|
||||
if (!decl || !decl->getDeclName()) return true;
|
||||
|
||||
// FIXME: There are likely other contexts in which it makes
|
||||
// no sense to ask for a mangled name.
|
||||
if (isa<RequiresExprBodyDecl>(decl->getDeclContext())) return true;
|
||||
|
||||
// If the declaration is dependent or is in a dependent
|
||||
// context, then the mangling is unlikely to be meaningful
|
||||
// (and in some cases may cause "don't know how to mangle
|
||||
// this" assertion failures.
|
||||
if (decl->isTemplated()) return true;
|
||||
|
||||
// Mangled names are not meaningful for locals, and may not
|
||||
// be well-defined in the case of VLAs.
|
||||
auto* var_decl = dyn_cast<VarDecl>(decl);
|
||||
if (var_decl && var_decl->hasLocalStorage()) return true;
|
||||
|
||||
// Do not mangle template deduction guides.
|
||||
if (isa<CXXDeductionGuideDecl>(decl)) return true;
|
||||
|
||||
std::string mangled_name = m_namegen.getName(decl);
|
||||
if (!mangled_name.empty()) {
|
||||
if (config_record_decl_name) {
|
||||
mangled_name = std::format(
|
||||
"{}, {}",
|
||||
decl->getDeclKindName(),
|
||||
mangled_name
|
||||
);
|
||||
}
|
||||
m_symbol_container.put(mangled_name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
ASTNameGenerator m_namegen;
|
||||
Container& m_symbol_container;
|
||||
};
|
||||
|
||||
class Consumer : public ASTConsumer {
|
||||
public:
|
||||
explicit Consumer(ASTContext& Context) {}
|
||||
|
||||
void HandleTranslationUnit(ASTContext& Context) override {
|
||||
Container Symbols;
|
||||
|
||||
Visitor(Context, Symbols)
|
||||
.TraverseDecl(Context.getTranslationUnitDecl());
|
||||
|
||||
// Save
|
||||
auto& SM = Context.getSourceManager();
|
||||
auto Loc = SM.getLocForStartOfFile(SM.getMainFileID());
|
||||
Symbols.write_to(SM.getFilename(Loc).str() + ".symbols");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace di::frontend_action {
|
||||
|
||||
std::unique_ptr<ASTConsumer> DumpSymbolFrontendAction::CreateASTConsumer(
|
||||
CompilerInstance& instance,
|
||||
llvm::StringRef
|
||||
) {
|
||||
return std::make_unique<Consumer>(instance.getASTContext());
|
||||
}
|
||||
|
||||
bool DumpSymbolFrontendAction::ParseArgs(
|
||||
const CompilerInstance&,
|
||||
const std::vector<std::string>& args
|
||||
) {
|
||||
for (const auto& arg : args) {
|
||||
if (arg.ends_with("record-decl-name")) {
|
||||
config_record_decl_name = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PluginASTAction::ActionType DumpSymbolFrontendAction::getActionType() {
|
||||
return AddAfterMainAction;
|
||||
}
|
||||
|
||||
} // namespace di::frontend_action
|
||||
27
src/frontend_action/dump_symbol.h
Normal file
27
src/frontend_action/dump_symbol.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <clang/Frontend/FrontendAction.h>
|
||||
|
||||
namespace clang {
|
||||
class ASTConsumer;
|
||||
class CompilerInstance;
|
||||
} // namespace clang
|
||||
|
||||
namespace di::frontend_action {
|
||||
|
||||
class DumpSymbolFrontendAction : public clang::PluginASTAction {
|
||||
protected:
|
||||
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
|
||||
clang::CompilerInstance& instance,
|
||||
llvm::StringRef
|
||||
) override;
|
||||
|
||||
bool ParseArgs(
|
||||
const clang::CompilerInstance&,
|
||||
const std::vector<std::string>& args
|
||||
) override;
|
||||
|
||||
ActionType getActionType() override;
|
||||
};
|
||||
|
||||
} // namespace di::frontend_action
|
||||
@@ -1,5 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
template <typename To, typename From>
|
||||
constexpr auto static_unique_ptr_cast(std::unique_ptr<From>&& F) {
|
||||
return std::unique_ptr<To>(static_cast<To*>(F.release()));
|
||||
}
|
||||
|
||||
// From:
|
||||
// https://stackoverflow.com/questions/7110301/generic-hash-for-tuples-in-unordered-map-unordered-set
|
||||
|
||||
@@ -29,7 +34,9 @@ struct HashValueImpl {
|
||||
|
||||
template <class Tuple>
|
||||
struct HashValueImpl<Tuple, 0> {
|
||||
static void apply(size_t& seed, Tuple const& tuple) { hash_combine(seed, std::get<0>(tuple)); }
|
||||
static void apply(size_t& seed, Tuple const& tuple) {
|
||||
hash_combine(seed, std::get<0>(tuple));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "binary/COFF.h"
|
||||
#include "object_file/COFF.h"
|
||||
|
||||
namespace makepdb::binary {
|
||||
namespace di::object_file {
|
||||
|
||||
COFF::COFF(std::string_view path) {
|
||||
using namespace object;
|
||||
@@ -67,4 +67,4 @@ object::COFFObjectFile const& COFF::get_owning_coff() const {
|
||||
return *m_owning_binary.getBinary();
|
||||
}
|
||||
|
||||
} // namespace makepdb::binary
|
||||
} // namespace di::object_file
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <llvm/Object/COFF.h>
|
||||
|
||||
namespace makepdb::binary {
|
||||
namespace di::object_file {
|
||||
|
||||
class COFF {
|
||||
public:
|
||||
@@ -20,4 +20,4 @@ private:
|
||||
object::OwningBinary<object::COFFObjectFile> m_owning_binary;
|
||||
};
|
||||
|
||||
} // namespace makepdb::binary
|
||||
} // namespace di::object_file
|
||||
@@ -1,15 +1,15 @@
|
||||
#include "binary/PDB.h"
|
||||
#include "object_file/PDB.h"
|
||||
|
||||
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
|
||||
#include <llvm/DebugInfo/MSF/MSFBuilder.h>
|
||||
#include <llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h>
|
||||
#include <llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h>
|
||||
#include <llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h>
|
||||
#include <llvm/DebugInfo/PDB/Native/RawConstants.h>
|
||||
#include <llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h>
|
||||
|
||||
using namespace llvm::pdb;
|
||||
|
||||
namespace makepdb::binary {
|
||||
namespace di::object_file {
|
||||
|
||||
PDB::PDB() : m_builder(m_allocator) {
|
||||
constexpr uint32_t block_size = 4096;
|
||||
@@ -90,12 +90,12 @@ void PDB::build_TPI() {
|
||||
IPI.setVersionHeader(PdbRaw_TpiVer::PdbTpiV80);
|
||||
|
||||
if (m_owning_raw_type_data) {
|
||||
m_owning_raw_type_data->for_each<RawTypeData::TPI>(
|
||||
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<RawTypeData::IPI>(
|
||||
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);
|
||||
}
|
||||
@@ -105,24 +105,23 @@ void PDB::build_TPI() {
|
||||
|
||||
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 BoundSymbol& entity) {
|
||||
BulkPublic symbol;
|
||||
|
||||
auto section_index =
|
||||
m_owning_coff->get_section_index(entity.rva - m_image_base);
|
||||
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.symbol_name.c_str());
|
||||
symbol.NameLen = entity.symbol_name.size();
|
||||
symbol.Name = strdup(entity.m_symbol_name.c_str());
|
||||
symbol.NameLen = entity.m_symbol_name.size();
|
||||
symbol.Segment = section_index + 1;
|
||||
symbol.Offset =
|
||||
entity.rva - m_image_base - section_or_err.get()->VirtualAddress;
|
||||
if (entity.is_function)
|
||||
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);
|
||||
@@ -131,4 +130,4 @@ void PDB::build_GSI() {
|
||||
m_builder.getGsiBuilder().addPublicSymbols(std::move(publics));
|
||||
}
|
||||
|
||||
} // namespace makepdb::binary
|
||||
} // namespace di::object_file
|
||||
53
src/object_file/PDB.h
Normal file
53
src/object_file/PDB.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "object_file/COFF.h"
|
||||
|
||||
#include "data_format/bound_symbol_list.h"
|
||||
#include "data_format/raw_type_data.h"
|
||||
|
||||
#include <llvm/DebugInfo/PDB/Native/PDBFileBuilder.h>
|
||||
#include <llvm/Support/Allocator.h>
|
||||
|
||||
namespace di::object_file {
|
||||
|
||||
class PDB {
|
||||
public:
|
||||
using owning_coff_t = std::unique_ptr<COFF>;
|
||||
using owning_symbol_data_t = std::unique_ptr<data_format::BoundSymbolList>;
|
||||
using owning_type_data_t = std::unique_ptr<data_format::RawTypeData>;
|
||||
|
||||
explicit PDB();
|
||||
|
||||
void set_coff_object(owning_coff_t coff_object) {
|
||||
m_owning_coff = std::move(coff_object);
|
||||
m_image_base = m_owning_coff->get_owning_coff().getImageBase();
|
||||
}
|
||||
|
||||
void set_symbol_data(owning_symbol_data_t 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(std::string_view path);
|
||||
|
||||
private:
|
||||
void build();
|
||||
|
||||
inline void build_Info();
|
||||
inline void build_DBI();
|
||||
inline void build_TPI();
|
||||
inline void build_GSI();
|
||||
|
||||
owning_coff_t m_owning_coff;
|
||||
owning_symbol_data_t m_owning_symbol_data;
|
||||
owning_type_data_t m_owning_raw_type_data;
|
||||
|
||||
uint64_t m_image_base;
|
||||
|
||||
BumpPtrAllocator m_allocator;
|
||||
pdb::PDBFileBuilder m_builder;
|
||||
};
|
||||
|
||||
} // namespace di::object_file
|
||||
@@ -1,13 +1,18 @@
|
||||
|
||||
// Work on llvm namespace.
|
||||
|
||||
namespace llvm {}
|
||||
using namespace llvm;
|
||||
|
||||
// Standard Libraries
|
||||
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
|
||||
|
||||
#include <fstream>
|
||||
#include <print>
|
||||
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
@@ -16,5 +21,8 @@
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <bitset>
|
||||
|
||||
// Helper
|
||||
|
||||
#include "nonstd.h"
|
||||
@@ -1,22 +1,26 @@
|
||||
#include "format/input/all.h"
|
||||
#include "format/output/all.h"
|
||||
|
||||
#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"
|
||||
|
||||
#include <argparse/argparse.hpp>
|
||||
|
||||
#if DI_USE_NATIVE_SYMBOL_RESOLVER
|
||||
#include <pl/SymbolProvider.h>
|
||||
#endif
|
||||
|
||||
using namespace format;
|
||||
enum class OutputFormat { Text, MakePDB };
|
||||
|
||||
constexpr auto VERSION = "1.0.0";
|
||||
using namespace di;
|
||||
|
||||
[[nodiscard]] auto load_args(int argc, char* argv[]) {
|
||||
argparse::ArgumentParser program("askrva", VERSION);
|
||||
argparse::ArgumentParser program("askrva");
|
||||
|
||||
struct {
|
||||
OutputFormat m_output_format;
|
||||
std::vector<std::string> m_input_path;
|
||||
std::vector<std::string> m_input_paths;
|
||||
std::string m_output_path;
|
||||
|
||||
std::optional<std::string> m_output_failed_path;
|
||||
@@ -28,7 +32,7 @@ constexpr auto VERSION = "1.0.0";
|
||||
|
||||
program.add_argument("path")
|
||||
.help("Path to the symbol list file.")
|
||||
.store_into(args.m_input_path)
|
||||
.store_into(args.m_input_paths)
|
||||
.nargs(argparse::nargs_pattern::at_least_one)
|
||||
.required();
|
||||
|
||||
@@ -42,7 +46,7 @@ constexpr auto VERSION = "1.0.0";
|
||||
|
||||
program.add_argument("--output-format")
|
||||
.help("Specify output format.")
|
||||
.choices("auto", "text", "fakepdb", "makepdb")
|
||||
.choices("auto", "text", "makepdb")
|
||||
.default_value("auto")
|
||||
.store_into(output_format);
|
||||
|
||||
@@ -56,8 +60,6 @@ constexpr auto VERSION = "1.0.0";
|
||||
switch (H(output_format)) {
|
||||
case H("text"):
|
||||
return OutputFormat::Text;
|
||||
case H("fakepdb"):
|
||||
return OutputFormat::FakePDB;
|
||||
case H("makepdb"):
|
||||
return OutputFormat::MakePDB;
|
||||
case H("auto"):
|
||||
@@ -81,23 +83,36 @@ constexpr auto VERSION = "1.0.0";
|
||||
int main(int argc, char* argv[]) try {
|
||||
|
||||
auto args = load_args(argc, argv);
|
||||
auto symlist = input::SymbolListFile::load(args.m_input_path);
|
||||
auto symlist = data_format::TypedSymbolList(args.m_input_paths);
|
||||
|
||||
auto output_file = output::create(args.m_output_format);
|
||||
data_format::BoundSymbolList bound_symbol_list;
|
||||
data_format::HumanReadableSymbolList human_readable_symbol_list;
|
||||
data_format::RawText raw_text;
|
||||
|
||||
symlist.for_each([&output_file](const input::Symbol& symbol) {
|
||||
symlist.for_each([&](const TypedSymbol& symbol) {
|
||||
auto& sym = symbol.m_name;
|
||||
auto rva = pl::symbol_provider::pl_resolve_symbol_silent_n(sym.c_str(), sym.size());
|
||||
#if DI_USE_NATIVE_SYMBOL_RESOLVER
|
||||
auto rva = pl::symbol_provider::pl_resolve_symbol_silent_n(
|
||||
sym.c_str(),
|
||||
sym.size()
|
||||
);
|
||||
#else
|
||||
auto rva = (void*)nullptr; // TODO
|
||||
#endif
|
||||
if (rva) {
|
||||
output_file->record(symbol.m_name, reinterpret_cast<uint64_t>(rva), symbol.m_type.isFunction());
|
||||
bound_symbol_list.record(
|
||||
symbol.m_name,
|
||||
reinterpret_cast<uint64_t>(rva),
|
||||
symbol.m_type.is_function()
|
||||
);
|
||||
} else {
|
||||
output_file->record_failure(symbol.m_name);
|
||||
raw_text.record(symbol.m_name);
|
||||
}
|
||||
});
|
||||
|
||||
output_file->save(args.m_output_path);
|
||||
bound_symbol_list.write_to(args.m_output_path);
|
||||
if (args.m_output_failed_path) {
|
||||
output_file->save_failure(*args.m_output_failed_path);
|
||||
raw_text.write_to(*args.m_output_failed_path);
|
||||
}
|
||||
|
||||
std::println("Everything is OK.");
|
||||
@@ -1,8 +1,3 @@
|
||||
#include <bitset>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <print>
|
||||
#include <unordered_map>
|
||||
|
||||
#define XXH_INLINE_ALL
|
||||
#include "xxhash.h"
|
||||
9
src/tools/dumpsym/plugin.cpp
Normal file
9
src/tools/dumpsym/plugin.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "frontend_action/dump_symbol.h"
|
||||
|
||||
#include <clang/Frontend/FrontendPluginRegistry.h>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
static FrontendPluginRegistry::Add<
|
||||
di::frontend_action::DumpSymbolFrontendAction>
|
||||
X("dumpsym", "Extract all declared symbols from a TU.");
|
||||
@@ -9,9 +9,6 @@
|
||||
|
||||
#include <argparse/argparse.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <print>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
using namespace llvm::codeview;
|
||||
@@ -1,16 +1,16 @@
|
||||
#include <argparse/argparse.hpp>
|
||||
|
||||
#include "binary/COFF.h"
|
||||
#include "binary/PDB.h"
|
||||
#include "object_file/COFF.h"
|
||||
#include "object_file/PDB.h"
|
||||
|
||||
#include "raw_type_data.h"
|
||||
#include "symbol_data.h"
|
||||
#include "data_format/bound_symbol_list.h"
|
||||
#include "data_format/raw_type_data.h"
|
||||
|
||||
using namespace makepdb;
|
||||
using namespace di;
|
||||
|
||||
[[nodiscard]] auto load_args(int argc, char* argv[]) {
|
||||
|
||||
argparse::ArgumentParser program("makepdb", "1.1.0");
|
||||
argparse::ArgumentParser program("makepdb");
|
||||
|
||||
struct {
|
||||
std::string server_program_path;
|
||||
@@ -53,16 +53,18 @@ int main(int argc, char* argv[]) try {
|
||||
auto args = load_args(argc, argv);
|
||||
|
||||
auto server_program =
|
||||
std::make_unique<binary::COFF>(args.server_program_path);
|
||||
std::make_unique<object_file::COFF>(args.server_program_path);
|
||||
|
||||
auto symbol_data = std::make_unique<SymbolData>(args.symbol_data_path);
|
||||
auto symbol_data =
|
||||
std::make_unique<data_format::BoundSymbolList>(args.symbol_data_path);
|
||||
|
||||
std::unique_ptr<RawTypeData> raw_type_data;
|
||||
std::unique_ptr<data_format::RawTypeData> raw_type_data;
|
||||
if (args.typeinfo_pdb_path) {
|
||||
raw_type_data = std::make_unique<RawTypeData>(*args.typeinfo_pdb_path);
|
||||
raw_type_data =
|
||||
std::make_unique<data_format::RawTypeData>(*args.typeinfo_pdb_path);
|
||||
}
|
||||
|
||||
binary::PDB pdb;
|
||||
object_file::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));
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
namespace util::string {
|
||||
namespace di::util::string {
|
||||
|
||||
constexpr unsigned int H(std::string_view str, unsigned int hash = 0) {
|
||||
for (char c : str) hash = hash * 31 + static_cast<unsigned int>(c);
|
||||
return hash;
|
||||
}
|
||||
|
||||
} // namespace util::string
|
||||
} // namespace di::util::string
|
||||
120
xmake.lua
Normal file
120
xmake.lua
Normal file
@@ -0,0 +1,120 @@
|
||||
add_rules('mode.debug', 'mode.release')
|
||||
|
||||
add_requires('argparse 3.1')
|
||||
add_requires('nlohmann_json 3.11.3')
|
||||
add_requires('xxhash 0.8.3')
|
||||
add_requires('boost 1.87.0')
|
||||
|
||||
add_requires('llvm')
|
||||
|
||||
--- options
|
||||
|
||||
option('symbol-resolver')
|
||||
set_default('builtin')
|
||||
set_showmenu(true)
|
||||
set_description('Select a symbol resolver.')
|
||||
set_values('builtin', 'native')
|
||||
before_check(function (option)
|
||||
-- the native symbol resolution backend is only available under windows, because liteldev
|
||||
-- has not released a linux version.
|
||||
if option:value() == 'native' and not is_plat('windows') then
|
||||
raise('the native symbol resolver does not support this platform.')
|
||||
end
|
||||
end)
|
||||
option_end()
|
||||
|
||||
if is_config('symbol-resolver', 'native') then
|
||||
add_repositories('liteldev-repo https://github.com/LiteLDev/xmake-repo.git')
|
||||
add_requires('preloader 1.12.0')
|
||||
end
|
||||
|
||||
--- global settings
|
||||
|
||||
set_languages('c23', 'c++23')
|
||||
set_warnings('all')
|
||||
|
||||
add_includedirs('src')
|
||||
|
||||
set_policy("build.optimization.lto", true)
|
||||
|
||||
if is_mode('debug') then
|
||||
add_defines('DI_DEBUG')
|
||||
end
|
||||
|
||||
--- targets
|
||||
|
||||
target('libdi')
|
||||
set_kind('static')
|
||||
add_files('src/**.cpp')
|
||||
set_pcxxheader('src/pch.h')
|
||||
|
||||
set_basename('di')
|
||||
|
||||
add_packages(
|
||||
'nlohmann_json'
|
||||
)
|
||||
|
||||
remove_files('src/tools/**')
|
||||
|
||||
target('askrva')
|
||||
set_kind('binary')
|
||||
add_deps('libdi')
|
||||
add_files('src/tools/askrva/**.cpp')
|
||||
set_pcxxheader('src/pch.h')
|
||||
|
||||
add_packages(
|
||||
'argparse',
|
||||
'nlohmann_json'
|
||||
)
|
||||
|
||||
if is_config('symbol-resolver', 'native') then
|
||||
add_packages('preloader')
|
||||
add_defines('DI_USE_NATIVE_SYMBOL_RESOLVER=1')
|
||||
end
|
||||
|
||||
target('blob-extractor')
|
||||
set_kind('binary')
|
||||
add_deps('libdi')
|
||||
add_files('src/tools/blob-extractor/**.cpp')
|
||||
set_pcxxheader('src/pch.h')
|
||||
|
||||
target('dumpsym')
|
||||
set_kind('shared')
|
||||
add_deps('libdi')
|
||||
add_files('src/tools/dumpsym/**.cpp')
|
||||
set_pcxxheader('src/pch.h')
|
||||
|
||||
add_packages(
|
||||
'llvm'
|
||||
)
|
||||
|
||||
target('extractsym')
|
||||
set_kind('binary')
|
||||
add_deps('libdi')
|
||||
add_files('src/tools/extractsym/**.cpp')
|
||||
set_pcxxheader('src/pch.h')
|
||||
|
||||
add_packages(
|
||||
'llvm',
|
||||
'argparse'
|
||||
)
|
||||
|
||||
if is_plat('linux') then -- workaround to fix link problem.
|
||||
add_links('LLVM')
|
||||
end
|
||||
|
||||
target('makepdb')
|
||||
set_kind('binary')
|
||||
add_deps('libdi')
|
||||
add_files('src/tools/makepdb/**.cpp')
|
||||
set_pcxxheader('src/pch.h')
|
||||
|
||||
add_packages(
|
||||
'llvm',
|
||||
'nlohmann_json',
|
||||
'argparse'
|
||||
)
|
||||
|
||||
if is_plat('linux') then
|
||||
add_links('LLVM')
|
||||
end
|
||||
Reference in New Issue
Block a user