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:
parent
b3c5b647b5
commit
310a348bce
16 changed files with 121 additions and 26 deletions
|
@ -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:
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
21
src/EmptyFdeDeleter.cpp
Normal 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
15
src/EmptyFdeDeleter.hpp
Normal 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;
|
||||||
|
};
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
11
src/main.cpp
11
src/main.cpp
|
@ -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(
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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. */
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue