diff --git a/generate_eh_elf.py b/generate_eh_elf.py index 09ef49b..921ba47 100755 --- a/generate_eh_elf.py +++ b/generate_eh_elf.py @@ -52,6 +52,7 @@ class Config: use_pc_list=False, c_opt_level='3', enable_deref_arg=False, + keep_holes=False, cc_debug=False, remote=None): self.output = '.' if output is None else output @@ -65,6 +66,7 @@ class Config: self.use_pc_list = use_pc_list self.c_opt_level = c_opt_level self.enable_deref_arg = enable_deref_arg + self.keep_holes = keep_holes self.cc_debug = cc_debug self.remote = remote @@ -78,6 +80,8 @@ class Config: out.append(self.sw_gen_policy.value) if self.enable_deref_arg: out.append('--enable-deref-arg') + if self.keep_holes: + out.append('--keep-holes') return out def cc_opts(self): @@ -309,6 +313,9 @@ def process_args(): "dwarf-assembly, enabling an extra `deref` " "argument for each lookup function, allowing " "to work on remote address spaces.")) + parser.add_argument('--keep-holes', action='store_true', + help=("Keep holes between FDEs instead of filling " + "them with junk. More accurate, less compact.")) parser.add_argument("-g", "--cc-debug", action='store_true', help=("Compile the source file with -g for easy " "debugging")) @@ -356,17 +363,18 @@ def process_args(): def main(): args = process_args() config = Config( - args.output, - args.aux, - args.no_dft_aux, - args.object, - args.sw_gen_policy, - args.force, - args.use_pc_list, - args.c_opt_level, - args.enable_deref_arg, - args.cc_debug, - args.remote, + output=args.output, + aux=args.aux, + no_dft_aux=args.no_dft_aux, + objects=args.object, + sw_gen_policy=args.sw_gen_policy, + force=args.force, + use_pc_list=args.use_pc_list, + c_opt_level=args.c_opt_level, + enable_deref_arg=args.enable_deref_arg, + keep_holes=args.keep_holes, + cc_debug=args.cc_debug, + remote=args.remote, ) for obj in args.object: diff --git a/src/CodeGenerator.cpp b/src/CodeGenerator.cpp index d4ea714..692bad5 100644 --- a/src/CodeGenerator.cpp +++ b/src/CodeGenerator.cpp @@ -271,6 +271,16 @@ void CodeGenerator::gen_of_reg(const SimpleDwarf::DwRegister& reg, } break; } + case SimpleDwarf::DwRegister::REG_PLT_EXPR: { + /* + if(settings::enable_deref_arg) + stream << "(deref("; + else + stream << "*((uintptr_t*)("; + */ + stream << "(((ctx.rip & 15) >= 11) ? 8 : 0) + ctx.rsp"; + break; + } case SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED: stream << "0"; throw UnhandledRegister(); diff --git a/src/ConseqEquivFilter.cpp b/src/ConseqEquivFilter.cpp index e3d871a..154434d 100644 --- a/src/ConseqEquivFilter.cpp +++ b/src/ConseqEquivFilter.cpp @@ -2,7 +2,7 @@ using namespace std; -ConseqEquivFilter::ConseqEquivFilter() {} +ConseqEquivFilter::ConseqEquivFilter(bool enable): SimpleDwarfFilter(enable) {} static bool equiv_reg( const SimpleDwarf::DwRegister& r1, diff --git a/src/ConseqEquivFilter.hpp b/src/ConseqEquivFilter.hpp index fdc7af4..e6178d5 100644 --- a/src/ConseqEquivFilter.hpp +++ b/src/ConseqEquivFilter.hpp @@ -9,7 +9,7 @@ class ConseqEquivFilter: public SimpleDwarfFilter { public: - ConseqEquivFilter(); + ConseqEquivFilter(bool enable=true); private: SimpleDwarf do_apply(const SimpleDwarf& dw) const; diff --git a/src/EmptyFdeDeleter.cpp b/src/EmptyFdeDeleter.cpp new file mode 100644 index 0000000..cd36a79 --- /dev/null +++ b/src/EmptyFdeDeleter.cpp @@ -0,0 +1,21 @@ +#include "EmptyFdeDeleter.hpp" + +#include +#include + +using namespace std; + +EmptyFdeDeleter::EmptyFdeDeleter(bool enable): SimpleDwarfFilter(enable) {} + +SimpleDwarf EmptyFdeDeleter::do_apply(const SimpleDwarf& dw) const { + SimpleDwarf out(dw); + + auto fde = out.fde_list.begin(); + while(fde != out.fde_list.end()) { + if(fde->rows.empty()) + fde = out.fde_list.erase(fde); + else + ++fde; + } + return out; +} diff --git a/src/EmptyFdeDeleter.hpp b/src/EmptyFdeDeleter.hpp new file mode 100644 index 0000000..2aee912 --- /dev/null +++ b/src/EmptyFdeDeleter.hpp @@ -0,0 +1,15 @@ +/** Deletes empty FDEs (that is, FDEs with no rows) from the FDEs collection. + * This is used to ensure they do not interfere with PcHoleFiller and such. */ + +#pragma once + +#include "SimpleDwarf.hpp" +#include "SimpleDwarfFilter.hpp" + +class EmptyFdeDeleter: public SimpleDwarfFilter { + public: + EmptyFdeDeleter(bool enable=true); + + private: + SimpleDwarf do_apply(const SimpleDwarf& dw) const; +}; diff --git a/src/FactoredSwitchCompiler.cpp b/src/FactoredSwitchCompiler.cpp index bf57102..ed8f484 100644 --- a/src/FactoredSwitchCompiler.cpp +++ b/src/FactoredSwitchCompiler.cpp @@ -15,9 +15,11 @@ void FactoredSwitchCompiler::to_stream( JumpPointMap jump_points; gen_binsearch_tree(os, jump_points, sw.switch_var, - sw.cases.begin(), sw.cases.end()); + sw.cases.begin(), sw.cases.end(), + make_pair(sw.cases.front().low_bound, sw.cases.back().high_bound)); - os << indent_str(sw.default_case) << "\n" + os << indent() << "_factor_default:\n" + << indent_str(sw.default_case) << "\n" << indent() << "/* ===== LABELS ============================== */\n\n"; gen_jump_points_code(os, jump_points); @@ -65,7 +67,8 @@ void FactoredSwitchCompiler::gen_binsearch_tree( FactoredSwitchCompiler::JumpPointMap& jump_map, const std::string& sw_var, const FactoredSwitchCompiler::case_iterator_t& begin, - const FactoredSwitchCompiler::case_iterator_t& end) + const FactoredSwitchCompiler::case_iterator_t& end, + const loc_range_t& loc_range) { size_t iter_delta = end - begin; if(iter_delta == 0) @@ -73,6 +76,19 @@ void FactoredSwitchCompiler::gen_binsearch_tree( else if(iter_delta == 1) { FactorJumpPoint jump_point = get_jump_point( jump_map, begin->content); + if(loc_range.first < begin->low_bound) { + os << indent() << "if(" << sw_var << " < 0x" + << hex << begin->low_bound << dec + << ") goto _factor_default; " + << "// IP=0x" << hex << loc_range.first << " ... 0x" + << begin->low_bound - 1 << "\n"; + } + if(begin->high_bound + 1 < loc_range.second) { + os << indent() << "if(0x" << hex << begin->high_bound << dec + << " < " << sw_var << ") goto _factor_default; " + << "// IP=0x" << hex << begin->high_bound + 1 << " ... 0x" + << loc_range.second - 1 << "\n"; + } os << indent() << "// IP=0x" << hex << begin->low_bound << " ... 0x" << begin->high_bound << dec << "\n" << indent() << "goto " << jump_point << ";\n"; @@ -83,11 +99,15 @@ void FactoredSwitchCompiler::gen_binsearch_tree( os << indent() << "if(" << sw_var << " < 0x" << hex << mid->low_bound << dec << ") {\n"; indent_count++; - gen_binsearch_tree(os, jump_map, sw_var, begin, mid); + gen_binsearch_tree( + os, jump_map, sw_var, begin, mid, + make_pair(loc_range.first, mid->low_bound)); indent_count--; os << indent() << "} else {\n"; indent_count++; - gen_binsearch_tree(os, jump_map, sw_var, mid, end); + gen_binsearch_tree( + os, jump_map, sw_var, mid, end, + make_pair(mid->low_bound, loc_range.second)); indent_count--; os << indent() << "}\n"; } diff --git a/src/FactoredSwitchCompiler.hpp b/src/FactoredSwitchCompiler.hpp index b86dd5d..3d1e174 100644 --- a/src/FactoredSwitchCompiler.hpp +++ b/src/FactoredSwitchCompiler.hpp @@ -24,6 +24,7 @@ class FactoredSwitchCompiler: public AbstractSwitchCompiler { JumpPointMap; typedef std::vector::const_iterator case_iterator_t; + typedef std::pair loc_range_t; private: virtual void to_stream(std::ostream& os, const SwitchStatement& sw); @@ -39,7 +40,9 @@ class FactoredSwitchCompiler: public AbstractSwitchCompiler { JumpPointMap& jump_map, const std::string& sw_var, const case_iterator_t& begin, - const case_iterator_t& end); + const case_iterator_t& end, + const loc_range_t& loc_range // [beg, end[ + ); size_t cur_label_id; diff --git a/src/Makefile b/src/Makefile index d6e93bd..6add70f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,6 +12,7 @@ OBJS=\ PcListReader.o \ SimpleDwarfFilter.o \ PcHoleFiller.o \ + EmptyFdeDeleter.o \ ConseqEquivFilter.o \ SwitchStatement.o \ NativeSwitchCompiler.o \ diff --git a/src/PcHoleFiller.cpp b/src/PcHoleFiller.cpp index 763c8c3..c945eca 100644 --- a/src/PcHoleFiller.cpp +++ b/src/PcHoleFiller.cpp @@ -5,7 +5,7 @@ using namespace std; -PcHoleFiller::PcHoleFiller() {} +PcHoleFiller::PcHoleFiller(bool enable): SimpleDwarfFilter(enable) {} SimpleDwarf PcHoleFiller::do_apply(const SimpleDwarf& dw) const { SimpleDwarf out(dw); diff --git a/src/PcHoleFiller.hpp b/src/PcHoleFiller.hpp index ccfad6d..4da4f4f 100644 --- a/src/PcHoleFiller.hpp +++ b/src/PcHoleFiller.hpp @@ -8,7 +8,7 @@ class PcHoleFiller: public SimpleDwarfFilter { public: - PcHoleFiller(); + PcHoleFiller(bool enable=true); private: SimpleDwarf do_apply(const SimpleDwarf& dw) const; diff --git a/src/SimpleDwarfFilter.cpp b/src/SimpleDwarfFilter.cpp index 5466b24..8c5e3c6 100644 --- a/src/SimpleDwarfFilter.cpp +++ b/src/SimpleDwarfFilter.cpp @@ -1,10 +1,11 @@ #include "SimpleDwarfFilter.hpp" -SimpleDwarfFilter::SimpleDwarfFilter() +SimpleDwarfFilter::SimpleDwarfFilter(bool enable): enable(enable) {} SimpleDwarf SimpleDwarfFilter::apply(const SimpleDwarf& dw) const { - // For convenience of future enhancements + if(!enable) + return dw; return do_apply(dw); } diff --git a/src/SimpleDwarfFilter.hpp b/src/SimpleDwarfFilter.hpp index 278f1f9..eb671aa 100644 --- a/src/SimpleDwarfFilter.hpp +++ b/src/SimpleDwarfFilter.hpp @@ -9,7 +9,11 @@ class SimpleDwarfFilter { public: - SimpleDwarfFilter(); + /** Constructor + * + * @param apply set to false to disable this filter. This setting is + * convenient for compact filter-chaining code. */ + SimpleDwarfFilter(bool enable=true); /// Applies the filter SimpleDwarf apply(const SimpleDwarf& dw) const; @@ -19,4 +23,6 @@ class SimpleDwarfFilter { private: virtual SimpleDwarf do_apply(const SimpleDwarf& dw) const = 0; + + bool enable; }; diff --git a/src/main.cpp b/src/main.cpp index cef3866..a98c36b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,7 @@ #include "NativeSwitchCompiler.hpp" #include "FactoredSwitchCompiler.hpp" #include "PcHoleFiller.hpp" +#include "EmptyFdeDeleter.hpp" #include "ConseqEquivFilter.hpp" #include "settings.hpp" @@ -65,6 +66,10 @@ MainOptions options_parse(int argc, char** argv) { else if(option == "--enable-deref-arg") { settings::enable_deref_arg = true; } + + else if(option == "--keep-holes") { + settings::keep_holes = true; + } } if(!seen_switch_gen_policy) { @@ -84,6 +89,7 @@ MainOptions options_parse(int argc, char** argv) { << argv[0] << " [--switch-per-func | --global-switch]" << " [--enable-deref-arg]" + << " [--keep-holes]" << " [--pc-list PC_LIST_FILE] elf_path" << endl; } @@ -98,9 +104,10 @@ int main(int argc, char** argv) { SimpleDwarf parsed_dwarf = DwarfReader(opts.elf_path).read(); SimpleDwarf filtered_dwarf = - PcHoleFiller()( + PcHoleFiller(!settings::keep_holes)( + EmptyFdeDeleter()( ConseqEquivFilter()( - parsed_dwarf)); + parsed_dwarf))); FactoredSwitchCompiler* sw_compiler = new FactoredSwitchCompiler(1); CodeGenerator code_gen( diff --git a/src/settings.cpp b/src/settings.cpp index fb37711..042d53d 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -4,4 +4,5 @@ namespace settings { SwitchGenerationPolicy switch_generation_policy = SGP_SwitchPerFunc; std::string pc_list = ""; bool enable_deref_arg = false; + bool keep_holes = false; } diff --git a/src/settings.hpp b/src/settings.hpp index 4ec239e..f7ede03 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -16,4 +16,6 @@ namespace settings { extern SwitchGenerationPolicy switch_generation_policy; extern std::string pc_list; extern bool enable_deref_arg; + extern bool keep_holes; /**< Keep holes between FDEs. Larger eh_elf files, + but more accurate unwinding. */ }