From c67055bad3cdfc93e2ac57d87f36c6e0993af690 Mon Sep 17 00:00:00 2001
From: Egor Tensin <Egor.Tensin@gmail.com>
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 <Egor.Tensin@gmail.com>
+// 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 <boost/program_options.hpp>
+
+#include <exception>
+#include <iostream>
+#include <string>
+#include <vector>
+
+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<PDB> pdbs;
+
+        std::vector<pdb::Address> 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<std::vector<PDB>>(&pdbs)
+                        ->value_name("ADDR,PATH"),
+                    "load a PDB file")
+                ("address",
+                    program_options::value<std::vector<pdb::Address>>(&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 <Egor.Tensin@gmail.com>
+// 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 <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+
+#include <exception>
+#include <iostream>
+#include <ostream>
+#include <string>
+
+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 <Egor.Tensin@gmail.com>
+// 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 <boost/program_options.hpp>
+
+#include <exception>
+#include <iostream>
+#include <string>
+#include <vector>
+
+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<PDB> pdbs;
+
+        bool type_specified() const
+        {
+            return tag != reserved_tag;
+        }
+
+        pdb::Symbol::Type get_type() const
+        {
+            return static_cast<pdb::Symbol::Type>(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<std::vector<PDB>>(&pdbs)
+                        ->value_name("ADDR,PATH"),
+                    "load a PDB file")
+                ("functions",
+                    program_options::value<pdb::Symbol::Tag>(&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::Tag>(pdb::Symbol::Type::RESERVED);
+        static const auto function_tag = static_cast<pdb::Symbol::Tag>(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 <Egor.Tensin@gmail.com>
+// 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 <boost/program_options.hpp>
+
+#include <exception>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+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<PDB> pdbs;
+
+        std::vector<std::string> 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<std::vector<PDB>>(&pdbs)
+                        ->value_name("ADDR,PATH"),
+                    "load a PDB file")
+                ("name",
+                    program_options::value<std::vector<std::string>>(&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 <Egor.Tensin@gmail.com>
+// 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 <boost/program_options.hpp>
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+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 <typename charT>
+        void validate(
+            boost::any& dest,
+            const std::vector<std::basic_string<charT>>& 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 <typename charT>
+        void validate(
+            boost::any& dest,
+            const std::vector<std::basic_string<charT>>& 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