From c67055bad3cdfc93e2ac57d87f36c6e0993af690 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Wed, 17 May 2017 06:00:20 +0300 Subject: initial commit --- utils/CMakeLists.txt | 14 ++++++ utils/addr2name.cpp | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ utils/command_line.hpp | 86 ++++++++++++++++++++++++++++++++ utils/enum_symbols.cpp | 117 +++++++++++++++++++++++++++++++++++++++++++ utils/name2addr.cpp | 132 +++++++++++++++++++++++++++++++++++++++++++++++++ utils/pdb_descr.hpp | 86 ++++++++++++++++++++++++++++++++ 6 files changed, 565 insertions(+) create mode 100644 utils/CMakeLists.txt create mode 100644 utils/addr2name.cpp create mode 100644 utils/command_line.hpp create mode 100644 utils/enum_symbols.cpp create mode 100644 utils/name2addr.cpp create mode 100644 utils/pdb_descr.hpp (limited to 'utils') diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt new file mode 100644 index 0000000..60f5b9f --- /dev/null +++ b/utils/CMakeLists.txt @@ -0,0 +1,14 @@ +find_package(Boost REQUIRED COMPONENTS filesystem program_options system) + +add_executable(enum_symbols enum_symbols.cpp command_line.hpp pdb_descr.hpp) +target_compile_definitions(enum_symbols PRIVATE _NO_CVCONST_H) +target_include_directories(enum_symbols SYSTEM PRIVATE ${Boost_INCLUDE_DIRS}) +target_link_libraries(enum_symbols PRIVATE pdb_repo ${Boost_LIBRARIES}) + +add_executable(name2addr name2addr.cpp) +target_include_directories(name2addr SYSTEM PRIVATE ${Boost_INCLUDE_DIRS}) +target_link_libraries(name2addr PRIVATE pdb_repo ${Boost_LIBRARIES}) + +add_executable(addr2name addr2name.cpp command_line.hpp pdb_descr.hpp) +target_include_directories(addr2name SYSTEM PRIVATE ${Boost_INCLUDE_DIRS}) +target_link_libraries(addr2name PRIVATE pdb_repo ${Boost_LIBRARIES}) diff --git a/utils/addr2name.cpp b/utils/addr2name.cpp new file mode 100644 index 0000000..a01f61e --- /dev/null +++ b/utils/addr2name.cpp @@ -0,0 +1,130 @@ +// Copyright (c) 2017 Egor Tensin +// This file is part of the "PDB repository" project. +// For details, see https://github.com/egor-tensin/pdb-repo. +// Distributed under the MIT License. + +#include "command_line.hpp" +#include "pdb_descr.hpp" + +#include "pdb/all.hpp" + +#include + +#include +#include +#include +#include + +namespace +{ + class Addr2Name : public SettingsParser + { + public: + explicit Addr2Name(const std::string& argv0) + : SettingsParser{argv0, build_options(), build_args()} + { } + + bool exit_with_usage() const { return help_flag; } + + const char* get_short_description() const override + { + return "[-h|--help] [--pdb ADDR,PATH]... [--] [ADDR]..."; + } + + std::vector pdbs; + + std::vector addresses; + + private: + Options build_options() + { + namespace program_options = boost::program_options; + Options descr{"options"}; + descr.add_options() + ("help,h", + program_options::bool_switch(&help_flag), + "show this message and exit") + ("pdb", + program_options::value>(&pdbs) + ->value_name("ADDR,PATH"), + "load a PDB file") + ("address", + program_options::value>(&addresses) + ->value_name("ADDR"), + "add an address to resolve"); + return descr; + } + + static Arguments build_args() + { + Arguments descr; + descr.add("address", -1); + return descr; + } + + bool help_flag = false; + }; + + std::string format_address(pdb::Address address) + { + std::ostringstream oss; + oss << std::showbase << std::hex << address; + return oss.str(); + } + + void dump_error(const std::exception& e) + { + std::cerr << "error: " << e.what() << '\n'; + } + + void resolve_symbol(const pdb::Repo& repo, pdb::Address address) + { + try + { + std::cout << repo.resolve_symbol(address).get_name() << '\n'; + } + catch (const std::exception& e) + { + dump_error(e); + std::cout << format_address(address) << '\n'; + } + } +} + +int main(int argc, char* argv[]) +{ + try + { + const Addr2Name settings{argv[0]}; + + try + { + settings.parse(argc, argv); + } + catch (const boost::program_options::error& e) + { + settings.usage_error(e); + return 1; + } + + if (settings.exit_with_usage()) + { + settings.usage(); + return 0; + } + + pdb::Repo repo; + + for (const auto& pdb : settings.pdbs) + repo.add_pdb(pdb.online_base, pdb.path); + + for (const auto& address : settings.addresses) + resolve_symbol(repo, address); + } + catch (const std::exception& e) + { + dump_error(e); + return 1; + } + return 0; +} diff --git a/utils/command_line.hpp b/utils/command_line.hpp new file mode 100644 index 0000000..79fb673 --- /dev/null +++ b/utils/command_line.hpp @@ -0,0 +1,86 @@ +// Copyright (c) 2017 Egor Tensin +// This file is part of the "PDB repository" project. +// For details, see https://github.com/egor-tensin/pdb-repo. +// Distributed under the MIT License. + +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace +{ + class SettingsParser + { + public: + typedef boost::program_options::options_description Options; + typedef boost::program_options::positional_options_description Arguments; + + explicit SettingsParser(const std::string& argv0) + : prog_name{extract_filename(argv0)} + { } + + SettingsParser(const std::string& argv0, const Options& options) + : prog_name{extract_filename(argv0)} + , options{options} + { } + + SettingsParser(const std::string& argv0, const Options& options, const Arguments& args) + : prog_name{extract_filename(argv0)} + , options{options} + , args{args} + { } + + virtual ~SettingsParser() = default; + + virtual const char* get_short_description() const { return "[OPTION]..."; } + + void parse(int argc, char* argv[]) const + { + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::command_line_parser{argc, argv} + .options(options) + .positional(args) + .run(), + vm); + boost::program_options::notify(vm); + } + + void usage() const + { + std::cout << *this; + } + + void usage_error(const std::exception& e) const + { + std::cerr << "usage error: " << e.what() << '\n'; + std::cerr << *this; + } + + private: + static std::string extract_filename(const std::string& path) + { + return boost::filesystem::path{path}.filename().string(); + } + + const std::string prog_name; + const Options options; + const Arguments args; + + friend std::ostream& operator<<(std::ostream&, const SettingsParser&); + }; + + std::ostream& operator<<(std::ostream& os, const SettingsParser& cmd_parser) + { + const auto short_descr = cmd_parser.get_short_description(); + os << "usage: " << cmd_parser.prog_name << ' ' << short_descr << '\n'; + os << cmd_parser.options; + return os; + } +} diff --git a/utils/enum_symbols.cpp b/utils/enum_symbols.cpp new file mode 100644 index 0000000..d7fd417 --- /dev/null +++ b/utils/enum_symbols.cpp @@ -0,0 +1,117 @@ +// Copyright (c) 2017 Egor Tensin +// This file is part of the "PDB repository" project. +// For details, see https://github.com/egor-tensin/pdb-repo. +// Distributed under the MIT License. + +#include "command_line.hpp" +#include "pdb_descr.hpp" + +#include "pdb/all.hpp" + +#include + +#include +#include +#include +#include + +namespace +{ + class EnumSymbols : public SettingsParser + { + public: + explicit EnumSymbols(const std::string& argv0) + : SettingsParser{argv0, build_options()} + { } + + bool exit_with_usage() const { return help_flag; } + + const char* get_short_description() const override + { + return "[-h|--help] [--pdb ADDR,PATH]... [--functions]"; + } + + std::vector pdbs; + + bool type_specified() const + { + return tag != reserved_tag; + } + + pdb::Symbol::Type get_type() const + { + return static_cast(tag); + } + + private: + Options build_options() + { + namespace program_options = boost::program_options; + Options descr{"options"}; + descr.add_options() + ("help,h", + program_options::bool_switch(&help_flag), + "show this message and exit") + ("pdb", + program_options::value>(&pdbs) + ->value_name("ADDR,PATH"), + "load a PDB file") + ("functions", + program_options::value(&tag) + ->implicit_value(function_tag) + ->zero_tokens(), + "only list functions"); + return descr; + } + + bool help_flag = false; + + static const auto reserved_tag = static_cast(pdb::Symbol::Type::RESERVED); + static const auto function_tag = static_cast(pdb::Symbol::Type::Function); + + pdb::Symbol::Tag tag = reserved_tag; + }; +} + +int main(int argc, char* argv[]) +{ + try + { + const EnumSymbols settings{argv[0]}; + + try + { + settings.parse(argc, argv); + } + catch (const boost::program_options::error& e) + { + settings.usage_error(e); + return 1; + } + + if (settings.exit_with_usage()) + { + settings.usage(); + return 0; + } + + pdb::Repo repo; + + for (const auto& pdb : settings.pdbs) + { + const auto id = repo.add_pdb(pdb.online_base, pdb.path); + + repo.enum_symbols(id, [&] (const pdb::Symbol& symbol) + { + if (!settings.type_specified() || settings.get_type() == symbol.get_type()) + std::cout << symbol.get_name() << '\n'; + }); + } + } + catch (const std::exception& e) + { + std::cerr << "error: " << e.what() << '\n'; + return 1; + } + return 0; +} diff --git a/utils/name2addr.cpp b/utils/name2addr.cpp new file mode 100644 index 0000000..055b469 --- /dev/null +++ b/utils/name2addr.cpp @@ -0,0 +1,132 @@ +// Copyright (c) 2017 Egor Tensin +// This file is part of the "PDB repository" project. +// For details, see https://github.com/egor-tensin/pdb-repo. +// Distributed under the MIT License. + +#include "command_line.hpp" +#include "pdb_descr.hpp" + +#include "pdb/all.hpp" + +#include + +#include +#include +#include +#include +#include + +namespace +{ + class Name2Addr : public SettingsParser + { + public: + explicit Name2Addr(const std::string& argv0) + : SettingsParser{argv0, build_options(), build_args()} + { } + + bool exit_with_usage() const { return help_flag; } + + const char* get_short_description() const override + { + return "[-h|--help] [--pdb ADDR,PATH]... [--] [NAME]..."; + } + + std::vector pdbs; + + std::vector names; + + private: + Options build_options() + { + namespace program_options = boost::program_options; + Options descr{"options"}; + descr.add_options() + ("help,h", + program_options::bool_switch(&help_flag), + "show this message and exit") + ("pdb", + program_options::value>(&pdbs) + ->value_name("ADDR,PATH"), + "load a PDB file") + ("name", + program_options::value>(&names) + ->value_name("NAME"), + "add a name to resolve"); + return descr; + } + + static Arguments build_args() + { + Arguments descr; + descr.add("name", -1); + return descr; + } + + bool help_flag = false; + }; + + std::string format_address(pdb::Address address) + { + std::ostringstream oss; + oss << std::showbase << std::hex << address; + return oss.str(); + } + + void dump_error(const std::exception& e) + { + std::cerr << "error: " << e.what() << '\n'; + } + + void resolve_symbol(const pdb::Repo& repo, const std::string& name) + { + try + { + const auto address = repo.resolve_symbol(name).get_online_address(); + std::cout << format_address(address) << '\n'; + } + catch (const std::exception& e) + { + dump_error(e); + std::cout << name << '\n'; + } + } +} + +int main(int argc, char* argv[]) +{ + try + { + const Name2Addr settings{argv[0]}; + + try + { + settings.parse(argc, argv); + } + catch (const boost::program_options::error& e) + { + settings.usage_error(e); + return 1; + } + + if (settings.exit_with_usage()) + { + settings.usage(); + return 0; + } + + pdb::Repo repo; + + for (const auto& pdb : settings.pdbs) + repo.add_pdb(pdb.online_base, pdb.path); + + for (const auto& name : settings.names) + resolve_symbol(repo, name); + } + catch (const std::exception& e) + { + dump_error(e); + return 1; + } + return 0; +} diff --git a/utils/pdb_descr.hpp b/utils/pdb_descr.hpp new file mode 100644 index 0000000..c57a0e9 --- /dev/null +++ b/utils/pdb_descr.hpp @@ -0,0 +1,86 @@ +// Copyright (c) 2017 Egor Tensin +// This file is part of the "PDB repository" project. +// For details, see https://github.com/egor-tensin/pdb-repo. +// Distributed under the MIT License. + +#pragma once + +#include "pdb/all.hpp" + +#include + +#include +#include +#include + +namespace +{ + struct PDB + { + PDB(pdb::Address online_base, const std::string& path) + : online_base{online_base} + , path{path} + { } + + pdb::Address online_base; + std::string path; + + static PDB parse(std::string src) + { + static constexpr auto sep = ','; + const auto sep_pos = src.find(sep); + if (sep_pos == std::string::npos) + boost::throw_exception(boost::program_options::invalid_option_value{src}); + pdb::Address online_base; + if (!parse_address(online_base, src.substr(0, sep_pos))) + boost::throw_exception(boost::program_options::invalid_option_value{src}); + return {online_base, src.substr(sep_pos + 1)}; + } + + static bool parse_address(pdb::Address& dest, const std::string& src) + { + std::istringstream iss{src}; + iss >> std::hex; + char c; + return iss >> dest && !iss.get(c); + } + + static pdb::Address parse_address(const std::string& src) + { + pdb::Address dest; + if (!parse_address(dest, src)) + boost::throw_exception(boost::program_options::invalid_option_value{src}); + return dest; + } + }; +} + +namespace boost +{ + namespace program_options + { + template + void validate( + boost::any& dest, + const std::vector>& src_tokens, + PDB*, + int) + { + validators::check_first_occurrence(dest); + const auto& src_token = validators::get_single_string(src_tokens); + dest = any{PDB::parse(src_token)}; + } + + template + void validate( + boost::any& dest, + const std::vector>& src_tokens, + pdb::Address*, + int) + { + validators::check_first_occurrence(dest); + const auto& src_token = validators::get_single_string(src_tokens); + dest = any{PDB::parse_address(src_token)}; + } + } +} -- cgit v1.2.3