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,
|
||||
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:
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
ConseqEquivFilter::ConseqEquivFilter() {}
|
||||
ConseqEquivFilter::ConseqEquivFilter(bool enable): SimpleDwarfFilter(enable) {}
|
||||
|
||||
static bool equiv_reg(
|
||||
const SimpleDwarf::DwRegister& r1,
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
class ConseqEquivFilter: public SimpleDwarfFilter {
|
||||
public:
|
||||
ConseqEquivFilter();
|
||||
ConseqEquivFilter(bool enable=true);
|
||||
|
||||
private:
|
||||
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;
|
||||
|
||||
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";
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ class FactoredSwitchCompiler: public AbstractSwitchCompiler {
|
|||
JumpPointMap;
|
||||
typedef std::vector<SwitchStatement::SwitchCase>::const_iterator
|
||||
case_iterator_t;
|
||||
typedef std::pair<uintptr_t, uintptr_t> 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;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ OBJS=\
|
|||
PcListReader.o \
|
||||
SimpleDwarfFilter.o \
|
||||
PcHoleFiller.o \
|
||||
EmptyFdeDeleter.o \
|
||||
ConseqEquivFilter.o \
|
||||
SwitchStatement.o \
|
||||
NativeSwitchCompiler.o \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
class PcHoleFiller: public SimpleDwarfFilter {
|
||||
public:
|
||||
PcHoleFiller();
|
||||
PcHoleFiller(bool enable=true);
|
||||
|
||||
private:
|
||||
SimpleDwarf do_apply(const SimpleDwarf& dw) const;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
11
src/main.cpp
11
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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue