From 26d7b2afd5048731ca7923f29c2b46638a43538d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Bastian?= Date: Fri, 11 May 2018 13:09:35 +0200 Subject: [PATCH] Add C++ code to make use of .pc_list --- src/CodeGenerator.cpp | 35 +++++++++++++++++++++++++++++++---- src/CodeGenerator.hpp | 4 ++++ src/Makefile | 8 +++++++- src/PcListReader.cpp | 32 ++++++++++++++++++++++++++++++++ src/PcListReader.hpp | 30 ++++++++++++++++++++++++++++++ src/main.cpp | 11 +++++++++++ src/settings.cpp | 1 + src/settings.hpp | 3 +++ 8 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 src/PcListReader.cpp create mode 100644 src/PcListReader.hpp diff --git a/src/CodeGenerator.cpp b/src/CodeGenerator.cpp index 7019dbc..7dbbd76 100644 --- a/src/CodeGenerator.cpp +++ b/src/CodeGenerator.cpp @@ -2,6 +2,8 @@ #include "gen_context_struct.hpp" #include "settings.hpp" +#include + using namespace std; static const char* PRELUDE = @@ -13,8 +15,12 @@ CodeGenerator::CodeGenerator( const SimpleDwarf& dwarf, std::ostream& os, NamingScheme naming_scheme): - dwarf(dwarf), os(os), naming_scheme(naming_scheme) -{} + dwarf(dwarf), os(os), pc_list(nullptr), naming_scheme(naming_scheme) +{ + if(!settings::pc_list.empty()) { + pc_list = make_unique(settings::pc_list); + } +} void CodeGenerator::generate() { gen_of_dwarf(); @@ -95,8 +101,7 @@ void CodeGenerator::gen_of_row( const SimpleDwarf::DwRow& row, uintptr_t row_end) { - os << "\t\tcase " << std::hex << "0x" << row.ip - << " ... 0x" << row_end << ":" << std::dec << endl; + gen_case(row.ip, row_end); os << "\t\t\t" << "out_ctx.rsp = "; gen_of_reg(row.cfa); @@ -113,6 +118,28 @@ void CodeGenerator::gen_of_row( os << "\t\t\treturn " << "out_ctx" << ";" << endl; } +void CodeGenerator::gen_case(uintptr_t low_bound, uintptr_t high_bound) { + if(pc_list == nullptr) { + os << "\t\tcase " << std::hex << "0x" << low_bound + << " ... 0x" << high_bound << ":" << std::dec << endl; + } + else { + const auto& first_it = lower_bound( + pc_list->get_list().begin(), + pc_list->get_list().end(), + low_bound); + const auto& last_it = upper_bound( + pc_list->get_list().begin(), + pc_list->get_list().end(), + high_bound); + + os << std::hex; + for(auto it = first_it; it != last_it; ++it) + os << "\t\tcase 0x" << *it << ":\n"; + os << std::dec; + } +} + static const char* ctx_of_dw_name(SimpleDwarf::MachineRegister reg) { switch(reg) { case SimpleDwarf::REG_RIP: diff --git a/src/CodeGenerator.hpp b/src/CodeGenerator.hpp index 30cdfb6..696c603 100644 --- a/src/CodeGenerator.hpp +++ b/src/CodeGenerator.hpp @@ -4,8 +4,10 @@ #include #include +#include #include "SimpleDwarf.hpp" +#include "PcListReader.hpp" class CodeGenerator { public: @@ -38,6 +40,7 @@ class CodeGenerator { void gen_of_row( const SimpleDwarf::DwRow& row, uintptr_t row_end); + void gen_case(uintptr_t low_bound, uintptr_t high_bound); void gen_of_reg( const SimpleDwarf::DwRegister& reg); @@ -46,6 +49,7 @@ class CodeGenerator { private: SimpleDwarf dwarf; std::ostream& os; + std::unique_ptr pc_list; NamingScheme naming_scheme; }; diff --git a/src/Makefile b/src/Makefile index 58aa7d1..430c010 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,7 +4,13 @@ CXXFLAGS=$(CXXLOCS) -Wall -Wextra -std=c++14 -O2 -g CXXLIBS=-lelf -ldwarf -ldwarfpp -lsrk31c++ -lc++fileno TARGET=dwarf-assembly -OBJS=DwarfReader.o SimpleDwarf.o CodeGenerator.o settings.o main.o +OBJS=\ + DwarfReader.o \ + SimpleDwarf.o \ + CodeGenerator.o \ + PcListReader.o \ + settings.o \ + main.o ############################################################################### diff --git a/src/PcListReader.cpp b/src/PcListReader.cpp new file mode 100644 index 0000000..1359d31 --- /dev/null +++ b/src/PcListReader.cpp @@ -0,0 +1,32 @@ +#include "PcListReader.hpp" + +#include + +using namespace std; + +PcListReader::PcListReader(const std::string& path): path(path) +{} + +void PcListReader::read() { + ifstream handle(path, ifstream::in | ifstream::binary); + if(!handle.good()) { + throw PcListReader::CannotReadFile(); + } + + uintptr_t last_pc; + unsigned char buffer[8]; + + while(!handle.eof()) { + handle.read((char*)buffer, 8); + if(handle.gcount() != 8) + throw PcListReader::BadFormat(); + + last_pc = 0; + for(int shift = 0; shift < 8; ++shift) { + uintptr_t c_byte = buffer[shift]; + c_byte <<= 8*shift; + last_pc |= c_byte; + } + pc_list.push_back(last_pc); + } +} diff --git a/src/PcListReader.hpp b/src/PcListReader.hpp new file mode 100644 index 0000000..e30daf3 --- /dev/null +++ b/src/PcListReader.hpp @@ -0,0 +1,30 @@ +/** Reads .pc_list files, containing a list of valid program counters for some + * elf file. + */ + +#pragma once + +#include +#include +#include + +class PcListReader { + public: + /// Thrown when the file is somehow not readable + class CannotReadFile: std::exception {}; + + /// Thrown when the file contains bad content (probably not aligned 8B) + class BadFormat: std::exception {}; + + PcListReader(const std::string& path); + + /// Actually read and process the file + void read(); + + /// Access the PC list (filled iff `read` was called before) + std::vector& get_list() { return pc_list; } + + private: + std::string path; + std::vector pc_list; +}; diff --git a/src/main.cpp b/src/main.cpp index 5c4ce8f..52640d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,6 +45,17 @@ MainOptions options_parse(int argc, char** argv) { settings::switch_generation_policy = settings::SGP_GlobalSwitch; } + + else if(option == "--pc-list") { + if(option_pos + 1 == argc) { // missing parameter + exit_status = 1; + print_helptext = true; + } + else { + ++option_pos; + settings::pc_list = argv[option_pos]; + } + } } if(!seen_switch_gen_policy) { diff --git a/src/settings.cpp b/src/settings.cpp index ea9012b..97b1661 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -2,4 +2,5 @@ namespace settings { SwitchGenerationPolicy switch_generation_policy = SGP_SwitchPerFunc; + std::string pc_list = ""; } diff --git a/src/settings.hpp b/src/settings.hpp index aeac573..1c9e9f1 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -4,6 +4,8 @@ #pragma once +#include + namespace settings { /// Controls how the eh_elf switches are generated enum SwitchGenerationPolicy { @@ -12,4 +14,5 @@ namespace settings { }; extern SwitchGenerationPolicy switch_generation_policy; + extern std::string pc_list; }