Can generate PC holes in eh_elfs

Before, the space between FDEs was abstracted away, thought as dead
space that produced an error when queried. This is not the case, though:
empty FDEs indicate undefined DWARF
This commit is contained in:
Théophile Bastian 2018-07-04 18:14:30 +02:00
parent b3c5b647b5
commit 310a348bce
16 changed files with 121 additions and 26 deletions

View file

@ -52,6 +52,7 @@ class Config:
use_pc_list=False, use_pc_list=False,
c_opt_level='3', c_opt_level='3',
enable_deref_arg=False, enable_deref_arg=False,
keep_holes=False,
cc_debug=False, cc_debug=False,
remote=None): remote=None):
self.output = '.' if output is None else output self.output = '.' if output is None else output
@ -65,6 +66,7 @@ class Config:
self.use_pc_list = use_pc_list self.use_pc_list = use_pc_list
self.c_opt_level = c_opt_level self.c_opt_level = c_opt_level
self.enable_deref_arg = enable_deref_arg self.enable_deref_arg = enable_deref_arg
self.keep_holes = keep_holes
self.cc_debug = cc_debug self.cc_debug = cc_debug
self.remote = remote self.remote = remote
@ -78,6 +80,8 @@ class Config:
out.append(self.sw_gen_policy.value) out.append(self.sw_gen_policy.value)
if self.enable_deref_arg: if self.enable_deref_arg:
out.append('--enable-deref-arg') out.append('--enable-deref-arg')
if self.keep_holes:
out.append('--keep-holes')
return out return out
def cc_opts(self): def cc_opts(self):
@ -309,6 +313,9 @@ def process_args():
"dwarf-assembly, enabling an extra `deref` " "dwarf-assembly, enabling an extra `deref` "
"argument for each lookup function, allowing " "argument for each lookup function, allowing "
"to work on remote address spaces.")) "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', parser.add_argument("-g", "--cc-debug", action='store_true',
help=("Compile the source file with -g for easy " help=("Compile the source file with -g for easy "
"debugging")) "debugging"))
@ -356,17 +363,18 @@ def process_args():
def main(): def main():
args = process_args() args = process_args()
config = Config( config = Config(
args.output, output=args.output,
args.aux, aux=args.aux,
args.no_dft_aux, no_dft_aux=args.no_dft_aux,
args.object, objects=args.object,
args.sw_gen_policy, sw_gen_policy=args.sw_gen_policy,
args.force, force=args.force,
args.use_pc_list, use_pc_list=args.use_pc_list,
args.c_opt_level, c_opt_level=args.c_opt_level,
args.enable_deref_arg, enable_deref_arg=args.enable_deref_arg,
args.cc_debug, keep_holes=args.keep_holes,
args.remote, cc_debug=args.cc_debug,
remote=args.remote,
) )
for obj in args.object: for obj in args.object:

View file

@ -271,6 +271,16 @@ void CodeGenerator::gen_of_reg(const SimpleDwarf::DwRegister& reg,
} }
break; 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: case SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED:
stream << "0"; stream << "0";
throw UnhandledRegister(); throw UnhandledRegister();

View file

@ -2,7 +2,7 @@
using namespace std; using namespace std;
ConseqEquivFilter::ConseqEquivFilter() {} ConseqEquivFilter::ConseqEquivFilter(bool enable): SimpleDwarfFilter(enable) {}
static bool equiv_reg( static bool equiv_reg(
const SimpleDwarf::DwRegister& r1, const SimpleDwarf::DwRegister& r1,

View file

@ -9,7 +9,7 @@
class ConseqEquivFilter: public SimpleDwarfFilter { class ConseqEquivFilter: public SimpleDwarfFilter {
public: public:
ConseqEquivFilter(); ConseqEquivFilter(bool enable=true);
private: private:
SimpleDwarf do_apply(const SimpleDwarf& dw) const; SimpleDwarf do_apply(const SimpleDwarf& dw) const;

21
src/EmptyFdeDeleter.cpp Normal file
View file

@ -0,0 +1,21 @@
#include "EmptyFdeDeleter.hpp"
#include <algorithm>
#include <cstdio>
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;
}

15
src/EmptyFdeDeleter.hpp Normal file
View file

@ -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;
};

View file

@ -15,9 +15,11 @@ void FactoredSwitchCompiler::to_stream(
JumpPointMap jump_points; JumpPointMap jump_points;
gen_binsearch_tree(os, jump_points, sw.switch_var, 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"; << indent() << "/* ===== LABELS ============================== */\n\n";
gen_jump_points_code(os, jump_points); gen_jump_points_code(os, jump_points);
@ -65,7 +67,8 @@ void FactoredSwitchCompiler::gen_binsearch_tree(
FactoredSwitchCompiler::JumpPointMap& jump_map, FactoredSwitchCompiler::JumpPointMap& jump_map,
const std::string& sw_var, const std::string& sw_var,
const FactoredSwitchCompiler::case_iterator_t& begin, 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; size_t iter_delta = end - begin;
if(iter_delta == 0) if(iter_delta == 0)
@ -73,6 +76,19 @@ void FactoredSwitchCompiler::gen_binsearch_tree(
else if(iter_delta == 1) { else if(iter_delta == 1) {
FactorJumpPoint jump_point = get_jump_point( FactorJumpPoint jump_point = get_jump_point(
jump_map, begin->content); 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 os << indent() << "// IP=0x" << hex << begin->low_bound
<< " ... 0x" << begin->high_bound << dec << "\n" << " ... 0x" << begin->high_bound << dec << "\n"
<< indent() << "goto " << jump_point << ";\n"; << indent() << "goto " << jump_point << ";\n";
@ -83,11 +99,15 @@ void FactoredSwitchCompiler::gen_binsearch_tree(
os << indent() << "if(" << sw_var << " < 0x" os << indent() << "if(" << sw_var << " < 0x"
<< hex << mid->low_bound << dec << ") {\n"; << hex << mid->low_bound << dec << ") {\n";
indent_count++; 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--; indent_count--;
os << indent() << "} else {\n"; os << indent() << "} else {\n";
indent_count++; 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--; indent_count--;
os << indent() << "}\n"; os << indent() << "}\n";
} }

View file

@ -24,6 +24,7 @@ class FactoredSwitchCompiler: public AbstractSwitchCompiler {
JumpPointMap; JumpPointMap;
typedef std::vector<SwitchStatement::SwitchCase>::const_iterator typedef std::vector<SwitchStatement::SwitchCase>::const_iterator
case_iterator_t; case_iterator_t;
typedef std::pair<uintptr_t, uintptr_t> loc_range_t;
private: private:
virtual void to_stream(std::ostream& os, const SwitchStatement& sw); virtual void to_stream(std::ostream& os, const SwitchStatement& sw);
@ -39,7 +40,9 @@ class FactoredSwitchCompiler: public AbstractSwitchCompiler {
JumpPointMap& jump_map, JumpPointMap& jump_map,
const std::string& sw_var, const std::string& sw_var,
const case_iterator_t& begin, 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; size_t cur_label_id;

View file

@ -12,6 +12,7 @@ OBJS=\
PcListReader.o \ PcListReader.o \
SimpleDwarfFilter.o \ SimpleDwarfFilter.o \
PcHoleFiller.o \ PcHoleFiller.o \
EmptyFdeDeleter.o \
ConseqEquivFilter.o \ ConseqEquivFilter.o \
SwitchStatement.o \ SwitchStatement.o \
NativeSwitchCompiler.o \ NativeSwitchCompiler.o \

View file

@ -5,7 +5,7 @@
using namespace std; using namespace std;
PcHoleFiller::PcHoleFiller() {} PcHoleFiller::PcHoleFiller(bool enable): SimpleDwarfFilter(enable) {}
SimpleDwarf PcHoleFiller::do_apply(const SimpleDwarf& dw) const { SimpleDwarf PcHoleFiller::do_apply(const SimpleDwarf& dw) const {
SimpleDwarf out(dw); SimpleDwarf out(dw);

View file

@ -8,7 +8,7 @@
class PcHoleFiller: public SimpleDwarfFilter { class PcHoleFiller: public SimpleDwarfFilter {
public: public:
PcHoleFiller(); PcHoleFiller(bool enable=true);
private: private:
SimpleDwarf do_apply(const SimpleDwarf& dw) const; SimpleDwarf do_apply(const SimpleDwarf& dw) const;

View file

@ -1,10 +1,11 @@
#include "SimpleDwarfFilter.hpp" #include "SimpleDwarfFilter.hpp"
SimpleDwarfFilter::SimpleDwarfFilter() SimpleDwarfFilter::SimpleDwarfFilter(bool enable): enable(enable)
{} {}
SimpleDwarf SimpleDwarfFilter::apply(const SimpleDwarf& dw) const { SimpleDwarf SimpleDwarfFilter::apply(const SimpleDwarf& dw) const {
// For convenience of future enhancements if(!enable)
return dw;
return do_apply(dw); return do_apply(dw);
} }

View file

@ -9,7 +9,11 @@
class SimpleDwarfFilter { class SimpleDwarfFilter {
public: 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 /// Applies the filter
SimpleDwarf apply(const SimpleDwarf& dw) const; SimpleDwarf apply(const SimpleDwarf& dw) const;
@ -19,4 +23,6 @@ class SimpleDwarfFilter {
private: private:
virtual SimpleDwarf do_apply(const SimpleDwarf& dw) const = 0; virtual SimpleDwarf do_apply(const SimpleDwarf& dw) const = 0;
bool enable;
}; };

View file

@ -11,6 +11,7 @@
#include "NativeSwitchCompiler.hpp" #include "NativeSwitchCompiler.hpp"
#include "FactoredSwitchCompiler.hpp" #include "FactoredSwitchCompiler.hpp"
#include "PcHoleFiller.hpp" #include "PcHoleFiller.hpp"
#include "EmptyFdeDeleter.hpp"
#include "ConseqEquivFilter.hpp" #include "ConseqEquivFilter.hpp"
#include "settings.hpp" #include "settings.hpp"
@ -65,6 +66,10 @@ MainOptions options_parse(int argc, char** argv) {
else if(option == "--enable-deref-arg") { else if(option == "--enable-deref-arg") {
settings::enable_deref_arg = true; settings::enable_deref_arg = true;
} }
else if(option == "--keep-holes") {
settings::keep_holes = true;
}
} }
if(!seen_switch_gen_policy) { if(!seen_switch_gen_policy) {
@ -84,6 +89,7 @@ MainOptions options_parse(int argc, char** argv) {
<< argv[0] << argv[0]
<< " [--switch-per-func | --global-switch]" << " [--switch-per-func | --global-switch]"
<< " [--enable-deref-arg]" << " [--enable-deref-arg]"
<< " [--keep-holes]"
<< " [--pc-list PC_LIST_FILE] elf_path" << " [--pc-list PC_LIST_FILE] elf_path"
<< endl; << endl;
} }
@ -98,9 +104,10 @@ int main(int argc, char** argv) {
SimpleDwarf parsed_dwarf = DwarfReader(opts.elf_path).read(); SimpleDwarf parsed_dwarf = DwarfReader(opts.elf_path).read();
SimpleDwarf filtered_dwarf = SimpleDwarf filtered_dwarf =
PcHoleFiller()( PcHoleFiller(!settings::keep_holes)(
EmptyFdeDeleter()(
ConseqEquivFilter()( ConseqEquivFilter()(
parsed_dwarf)); parsed_dwarf)));
FactoredSwitchCompiler* sw_compiler = new FactoredSwitchCompiler(1); FactoredSwitchCompiler* sw_compiler = new FactoredSwitchCompiler(1);
CodeGenerator code_gen( CodeGenerator code_gen(

View file

@ -4,4 +4,5 @@ namespace settings {
SwitchGenerationPolicy switch_generation_policy = SGP_SwitchPerFunc; SwitchGenerationPolicy switch_generation_policy = SGP_SwitchPerFunc;
std::string pc_list = ""; std::string pc_list = "";
bool enable_deref_arg = false; bool enable_deref_arg = false;
bool keep_holes = false;
} }

View file

@ -16,4 +16,6 @@ namespace settings {
extern SwitchGenerationPolicy switch_generation_policy; extern SwitchGenerationPolicy switch_generation_policy;
extern std::string pc_list; extern std::string pc_list;
extern bool enable_deref_arg; extern bool enable_deref_arg;
extern bool keep_holes; /**< Keep holes between FDEs. Larger eh_elf files,
but more accurate unwinding. */
} }