Refactor switch generation
This commit is contained in:
parent
cd9ecafb4f
commit
6fef1c5444
8 changed files with 265 additions and 106 deletions
|
@ -17,11 +17,35 @@ static const char* PRELUDE =
|
||||||
"\n"
|
"\n"
|
||||||
;
|
;
|
||||||
|
|
||||||
|
struct UnwFlags {
|
||||||
|
UnwFlags():
|
||||||
|
error(false), rip(false), rsp(false), rbp(false) {}
|
||||||
|
|
||||||
|
bool error, rip, rsp, rbp;
|
||||||
|
|
||||||
|
uint8_t to_uint8() const {
|
||||||
|
uint8_t out = 0;
|
||||||
|
if(rip)
|
||||||
|
out |= (1 << UNWF_RIP);
|
||||||
|
if(rsp)
|
||||||
|
out |= (1 << UNWF_RSP);
|
||||||
|
if(rbp)
|
||||||
|
out |= (1 << UNWF_RBP);
|
||||||
|
if(error)
|
||||||
|
out |= (1 << UNWF_ERROR);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
CodeGenerator::CodeGenerator(
|
CodeGenerator::CodeGenerator(
|
||||||
const SimpleDwarf& dwarf,
|
const SimpleDwarf& dwarf,
|
||||||
std::ostream& os,
|
std::ostream& os,
|
||||||
NamingScheme naming_scheme):
|
NamingScheme naming_scheme,
|
||||||
dwarf(dwarf), os(os), pc_list(nullptr), naming_scheme(naming_scheme)
|
AbstractSwitchCompilerFactory* factory) :
|
||||||
|
dwarf(dwarf), os(os), pc_list(nullptr),
|
||||||
|
naming_scheme(naming_scheme), switch_factory(factory)
|
||||||
{
|
{
|
||||||
if(!settings::pc_list.empty()) {
|
if(!settings::pc_list.empty()) {
|
||||||
pc_list = make_unique<PcListReader>(settings::pc_list);
|
pc_list = make_unique<PcListReader>(settings::pc_list);
|
||||||
|
@ -33,6 +57,41 @@ void CodeGenerator::generate() {
|
||||||
gen_of_dwarf();
|
gen_of_dwarf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SwitchStatement CodeGenerator::gen_fresh_switch() const {
|
||||||
|
SwitchStatement out;
|
||||||
|
out.switch_var = "pc";
|
||||||
|
ostringstream default_oss;
|
||||||
|
UnwFlags flags;
|
||||||
|
flags.error = true;
|
||||||
|
default_oss
|
||||||
|
<< "out_ctx.flags = " << (int) flags.to_uint8() << "u;\n"
|
||||||
|
<< "return out_ctx;\n";
|
||||||
|
out.default_case = default_oss.str();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::switch_append_fde(
|
||||||
|
SwitchStatement& sw,
|
||||||
|
const SimpleDwarf::Fde& fde) const
|
||||||
|
{
|
||||||
|
for(size_t fde_row_id=0; fde_row_id < fde.rows.size(); ++fde_row_id)
|
||||||
|
{
|
||||||
|
SwitchStatement::SwitchCase sw_case;
|
||||||
|
|
||||||
|
uintptr_t up_bound = fde.end_ip - 1;
|
||||||
|
if(fde_row_id != fde.rows.size() - 1)
|
||||||
|
up_bound = fde.rows[fde_row_id + 1].ip - 1;
|
||||||
|
sw_case.low_bound = fde.rows[fde_row_id].ip;
|
||||||
|
sw_case.high_bound = up_bound;
|
||||||
|
|
||||||
|
ostringstream case_oss;
|
||||||
|
gen_of_row_content(fde.rows[fde_row_id], case_oss);
|
||||||
|
sw_case.code = case_oss.str();
|
||||||
|
|
||||||
|
sw.cases.push_back(sw_case);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CodeGenerator::gen_of_dwarf() {
|
void CodeGenerator::gen_of_dwarf() {
|
||||||
os << CONTEXT_STRUCT_STR << '\n'
|
os << CONTEXT_STRUCT_STR << '\n'
|
||||||
<< PRELUDE << '\n' << endl;
|
<< PRELUDE << '\n' << endl;
|
||||||
|
@ -60,9 +119,11 @@ void CodeGenerator::gen_of_dwarf() {
|
||||||
case settings::SGP_GlobalSwitch:
|
case settings::SGP_GlobalSwitch:
|
||||||
{
|
{
|
||||||
gen_unwind_func_header("_eh_elf");
|
gen_unwind_func_header("_eh_elf");
|
||||||
for(const auto& fde: dwarf.fde_list) {
|
SwitchStatement sw_stmt = gen_fresh_switch();
|
||||||
gen_switchpart_of_fde(fde);
|
for(const auto& fde: dwarf.fde_list)
|
||||||
}
|
switch_append_fde(sw_stmt, fde);
|
||||||
|
auto sw_compiler = (*switch_factory)(sw_stmt);
|
||||||
|
(*sw_compiler)(os);
|
||||||
gen_unwind_func_footer();
|
gen_unwind_func_footer();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -77,70 +138,30 @@ void CodeGenerator::gen_unwind_func_header(const std::string& name) {
|
||||||
os << "unwind_context_t "
|
os << "unwind_context_t "
|
||||||
<< name
|
<< name
|
||||||
<< "(unwind_context_t ctx, uintptr_t pc" << deref_arg << ") {\n"
|
<< "(unwind_context_t ctx, uintptr_t pc" << deref_arg << ") {\n"
|
||||||
<< "\tunwind_context_t out_ctx;\n"
|
<< "\tunwind_context_t out_ctx;" << endl;
|
||||||
<< "\tswitch(pc) {" << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UnwFlags {
|
|
||||||
UnwFlags():
|
|
||||||
error(false), rip(false), rsp(false), rbp(false) {}
|
|
||||||
|
|
||||||
bool error, rip, rsp, rbp;
|
|
||||||
|
|
||||||
uint8_t to_uint8() const {
|
|
||||||
uint8_t out = 0;
|
|
||||||
if(rip)
|
|
||||||
out |= (1 << UNWF_RIP);
|
|
||||||
if(rsp)
|
|
||||||
out |= (1 << UNWF_RSP);
|
|
||||||
if(rbp)
|
|
||||||
out |= (1 << UNWF_RBP);
|
|
||||||
if(error)
|
|
||||||
out |= (1 << UNWF_ERROR);
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void CodeGenerator::gen_unwind_func_footer() {
|
void CodeGenerator::gen_unwind_func_footer() {
|
||||||
UnwFlags flags;
|
os << "}" << endl;
|
||||||
flags.error = true;
|
|
||||||
os << "\t\tdefault:\n"
|
|
||||||
<< "\t\t\tout_ctx.flags = " << (int) flags.to_uint8() << "u;\n"
|
|
||||||
<< "\t\t\treturn out_ctx;\n"
|
|
||||||
<< "\t}\n"
|
|
||||||
<< "}" << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenerator::gen_function_of_fde(const SimpleDwarf::Fde& fde) {
|
void CodeGenerator::gen_function_of_fde(const SimpleDwarf::Fde& fde) {
|
||||||
gen_unwind_func_header(naming_scheme(fde));
|
gen_unwind_func_header(naming_scheme(fde));
|
||||||
|
|
||||||
gen_switchpart_of_fde(fde);
|
SwitchStatement sw_stmt = gen_fresh_switch();
|
||||||
|
switch_append_fde(sw_stmt, fde);
|
||||||
|
auto sw_compiler = (*switch_factory)(sw_stmt);
|
||||||
|
(*sw_compiler)(os);
|
||||||
|
|
||||||
gen_unwind_func_footer();
|
gen_unwind_func_footer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenerator::gen_switchpart_of_fde(const SimpleDwarf::Fde& fde) {
|
void CodeGenerator::gen_of_row_content(
|
||||||
os << "\t\t/********** FDE: 0x" << std::hex << fde.fde_offset
|
|
||||||
<< ", PC = 0x" << fde.beg_ip << std::dec << " */" << std::endl;
|
|
||||||
for(size_t fde_row_id=0; fde_row_id < fde.rows.size(); ++fde_row_id)
|
|
||||||
{
|
|
||||||
uintptr_t up_bound = fde.end_ip - 1;
|
|
||||||
if(fde_row_id != fde.rows.size() - 1)
|
|
||||||
up_bound = fde.rows[fde_row_id + 1].ip - 1;
|
|
||||||
|
|
||||||
gen_of_row(fde.rows[fde_row_id], up_bound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenerator::gen_of_row(
|
|
||||||
const SimpleDwarf::DwRow& row,
|
const SimpleDwarf::DwRow& row,
|
||||||
uintptr_t row_end)
|
std::ostream& stream) const
|
||||||
{
|
{
|
||||||
gen_case(row.ip, row_end);
|
|
||||||
UnwFlags flags;
|
UnwFlags flags;
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if(!check_reg_valid(row.ra)) {
|
if(!check_reg_valid(row.ra)) {
|
||||||
// RA might be undefined (last frame), but if it is defined and we
|
// RA might be undefined (last frame), but if it is defined and we
|
||||||
|
@ -151,9 +172,9 @@ void CodeGenerator::gen_of_row(
|
||||||
|
|
||||||
if(check_reg_valid(row.cfa)) {
|
if(check_reg_valid(row.cfa)) {
|
||||||
flags.rsp = true;
|
flags.rsp = true;
|
||||||
os << "\t\t\t" << "out_ctx.rsp = ";
|
stream << "out_ctx.rsp = ";
|
||||||
gen_of_reg(row.cfa);
|
gen_of_reg(row.cfa, stream);
|
||||||
os << ';' << endl;
|
stream << ';' << endl;
|
||||||
}
|
}
|
||||||
else { // rsp is required (CFA)
|
else { // rsp is required (CFA)
|
||||||
flags.error = true;
|
flags.error = true;
|
||||||
|
@ -162,53 +183,28 @@ void CodeGenerator::gen_of_row(
|
||||||
|
|
||||||
if(check_reg_defined(row.rbp)) {
|
if(check_reg_defined(row.rbp)) {
|
||||||
flags.rbp = true;
|
flags.rbp = true;
|
||||||
os << "\t\t\t" << "out_ctx.rbp = ";
|
stream << "out_ctx.rbp = ";
|
||||||
gen_of_reg(row.rbp);
|
gen_of_reg(row.rbp, stream);
|
||||||
os << ';' << endl;
|
stream << ';' << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(check_reg_defined(row.ra)) {
|
if(check_reg_defined(row.ra)) {
|
||||||
flags.rip = true;
|
flags.rip = true;
|
||||||
os << "\t\t\t" << "out_ctx.rip = ";
|
stream << "out_ctx.rip = ";
|
||||||
gen_of_reg(row.ra);
|
gen_of_reg(row.ra, stream);
|
||||||
os << ';' << endl;
|
stream << ';' << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch(const UnhandledRegister& exn) {
|
} catch(const UnhandledRegister& exn) {
|
||||||
// This should not happen, since we check_reg_*, but heh.
|
// This should not happen, since we check_reg_*, but heh.
|
||||||
flags.error = true;
|
flags.error = true;
|
||||||
os << ";\n";
|
stream << ";\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
write_flags:
|
write_flags:
|
||||||
os << "\t\t\tout_ctx.flags = " << (int)flags.to_uint8() << "u;" << endl;
|
stream << "out_ctx.flags = " << (int)flags.to_uint8() << "u;" << endl;
|
||||||
|
|
||||||
os << "\t\t\treturn " << "out_ctx" << ";" << endl;
|
stream << "return " << "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);
|
|
||||||
|
|
||||||
if(first_it == pc_list->get_list().end())
|
|
||||||
throw CodeGenerator::InvalidPcList();
|
|
||||||
|
|
||||||
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) {
|
static const char* ctx_of_dw_name(SimpleDwarf::MachineRegister reg) {
|
||||||
|
@ -225,7 +221,9 @@ static const char* ctx_of_dw_name(SimpleDwarf::MachineRegister reg) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CodeGenerator::check_reg_defined(const SimpleDwarf::DwRegister& reg) {
|
bool CodeGenerator::check_reg_defined(
|
||||||
|
const SimpleDwarf::DwRegister& reg) const
|
||||||
|
{
|
||||||
switch(reg.type) {
|
switch(reg.type) {
|
||||||
case SimpleDwarf::DwRegister::REG_UNDEFINED:
|
case SimpleDwarf::DwRegister::REG_UNDEFINED:
|
||||||
case SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED:
|
case SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED:
|
||||||
|
@ -234,11 +232,13 @@ bool CodeGenerator::check_reg_defined(const SimpleDwarf::DwRegister& reg) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool CodeGenerator::check_reg_valid(const SimpleDwarf::DwRegister& reg) {
|
bool CodeGenerator::check_reg_valid(const SimpleDwarf::DwRegister& reg) const {
|
||||||
return reg.type != SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED;
|
return reg.type != SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenerator::gen_of_reg(const SimpleDwarf::DwRegister& reg) {
|
void CodeGenerator::gen_of_reg(const SimpleDwarf::DwRegister& reg,
|
||||||
|
ostream& stream) const
|
||||||
|
{
|
||||||
switch(reg.type) {
|
switch(reg.type) {
|
||||||
case SimpleDwarf::DwRegister::REG_UNDEFINED:
|
case SimpleDwarf::DwRegister::REG_UNDEFINED:
|
||||||
// This function is not supposed to be called on an undefined
|
// This function is not supposed to be called on an undefined
|
||||||
|
@ -246,24 +246,24 @@ void CodeGenerator::gen_of_reg(const SimpleDwarf::DwRegister& reg) {
|
||||||
throw UnhandledRegister();
|
throw UnhandledRegister();
|
||||||
break;
|
break;
|
||||||
case SimpleDwarf::DwRegister::REG_REGISTER:
|
case SimpleDwarf::DwRegister::REG_REGISTER:
|
||||||
os << ctx_of_dw_name(reg.reg)
|
stream << ctx_of_dw_name(reg.reg)
|
||||||
<< " + (" << reg.offset << ")";
|
<< " + (" << reg.offset << ")";
|
||||||
break;
|
break;
|
||||||
case SimpleDwarf::DwRegister::REG_CFA_OFFSET: {
|
case SimpleDwarf::DwRegister::REG_CFA_OFFSET: {
|
||||||
if(settings::enable_deref_arg) {
|
if(settings::enable_deref_arg) {
|
||||||
os << "deref(out_ctx.rsp + ("
|
stream << "deref(out_ctx.rsp + ("
|
||||||
<< reg.offset
|
<< reg.offset
|
||||||
<< "))";
|
<< "))";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
os << "*((uintptr_t*)(out_ctx.rsp + ("
|
stream << "*((uintptr_t*)(out_ctx.rsp + ("
|
||||||
<< reg.offset
|
<< reg.offset
|
||||||
<< ")))";
|
<< ")))";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED:
|
case SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED:
|
||||||
os << "0";
|
stream << "0";
|
||||||
throw UnhandledRegister();
|
throw UnhandledRegister();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "SimpleDwarf.hpp"
|
#include "SimpleDwarf.hpp"
|
||||||
#include "PcListReader.hpp"
|
#include "PcListReader.hpp"
|
||||||
|
#include "SwitchStatement.hpp"
|
||||||
|
|
||||||
class CodeGenerator {
|
class CodeGenerator {
|
||||||
public:
|
public:
|
||||||
|
@ -23,7 +24,8 @@ class CodeGenerator {
|
||||||
/** Create a CodeGenerator to generate code for the given dwarf, on the
|
/** Create a CodeGenerator to generate code for the given dwarf, on the
|
||||||
* given std::ostream object (eg. cout). */
|
* given std::ostream object (eg. cout). */
|
||||||
CodeGenerator(const SimpleDwarf& dwarf, std::ostream& os,
|
CodeGenerator(const SimpleDwarf& dwarf, std::ostream& os,
|
||||||
NamingScheme naming_scheme);
|
NamingScheme naming_scheme,
|
||||||
|
AbstractSwitchCompilerFactory* factory);
|
||||||
|
|
||||||
/// Actually generate the code on the given stream
|
/// Actually generate the code on the given stream
|
||||||
void generate();
|
void generate();
|
||||||
|
@ -34,22 +36,26 @@ class CodeGenerator {
|
||||||
uintptr_t beg, end;
|
uintptr_t beg, end;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
SwitchStatement gen_fresh_switch() const;
|
||||||
|
void switch_append_fde(
|
||||||
|
SwitchStatement& sw,
|
||||||
|
const SimpleDwarf::Fde& fde) const;
|
||||||
void gen_of_dwarf();
|
void gen_of_dwarf();
|
||||||
void gen_unwind_func_header(const std::string& name);
|
void gen_unwind_func_header(const std::string& name);
|
||||||
void gen_unwind_func_footer();
|
void gen_unwind_func_footer();
|
||||||
void gen_function_of_fde(const SimpleDwarf::Fde& fde);
|
void gen_function_of_fde(const SimpleDwarf::Fde& fde);
|
||||||
void gen_switchpart_of_fde(const SimpleDwarf::Fde& fde);
|
void gen_of_row_content(
|
||||||
void gen_of_row(
|
|
||||||
const SimpleDwarf::DwRow& row,
|
const SimpleDwarf::DwRow& row,
|
||||||
uintptr_t row_end);
|
std::ostream& stream) const;
|
||||||
void gen_case(uintptr_t low_bound, uintptr_t high_bound);
|
|
||||||
void gen_of_reg(
|
void gen_of_reg(
|
||||||
const SimpleDwarf::DwRegister& reg);
|
const SimpleDwarf::DwRegister& reg,
|
||||||
|
std::ostream& stream) const;
|
||||||
|
|
||||||
void gen_lookup(const std::vector<LookupEntry>& entries);
|
void gen_lookup(const std::vector<LookupEntry>& entries);
|
||||||
|
|
||||||
bool check_reg_defined(const SimpleDwarf::DwRegister& reg);
|
bool check_reg_defined(const SimpleDwarf::DwRegister& reg) const;
|
||||||
bool check_reg_valid(const SimpleDwarf::DwRegister& reg);
|
bool check_reg_valid(const SimpleDwarf::DwRegister& reg) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SimpleDwarf dwarf;
|
SimpleDwarf dwarf;
|
||||||
|
@ -57,4 +63,6 @@ class CodeGenerator {
|
||||||
std::unique_ptr<PcListReader> pc_list;
|
std::unique_ptr<PcListReader> pc_list;
|
||||||
|
|
||||||
NamingScheme naming_scheme;
|
NamingScheme naming_scheme;
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractSwitchCompilerFactory> switch_factory;
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,8 @@ OBJS=\
|
||||||
SimpleDwarfFilter.o \
|
SimpleDwarfFilter.o \
|
||||||
PcHoleFiller.o \
|
PcHoleFiller.o \
|
||||||
ConseqEquivFilter.o \
|
ConseqEquivFilter.o \
|
||||||
|
SwitchStatement.o \
|
||||||
|
NativeSwitchCompiler.o \
|
||||||
settings.o \
|
settings.o \
|
||||||
main.o
|
main.o
|
||||||
|
|
||||||
|
|
29
src/NativeSwitchCompiler.cpp
Normal file
29
src/NativeSwitchCompiler.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include "NativeSwitchCompiler.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
NativeSwitchCompiler::NativeSwitchCompiler(
|
||||||
|
const SwitchStatement& sw, int indent):
|
||||||
|
AbstractSwitchCompiler(sw, indent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void NativeSwitchCompiler::to_stream(ostream& os) {
|
||||||
|
os << indent() << "switch(" << sw.switch_var << ") {\n";
|
||||||
|
indent_count++;
|
||||||
|
|
||||||
|
for(const auto& cur_case: sw.cases) {
|
||||||
|
os << indent() << "case 0x"
|
||||||
|
<< hex << cur_case.low_bound << " ... 0x" << cur_case.high_bound
|
||||||
|
<< dec << ":\n";
|
||||||
|
indent_count++;
|
||||||
|
os << indent_str(cur_case.code);
|
||||||
|
indent_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
os << indent() << "default:\n";
|
||||||
|
indent_count++;
|
||||||
|
os << indent_str(sw.default_case);
|
||||||
|
indent_count--;
|
||||||
|
os << indent() << "}\n";
|
||||||
|
indent_count--;
|
||||||
|
}
|
10
src/NativeSwitchCompiler.hpp
Normal file
10
src/NativeSwitchCompiler.hpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/** Compiles a SwitchStatement to a native C switch */
|
||||||
|
|
||||||
|
#include "SwitchStatement.hpp"
|
||||||
|
|
||||||
|
class NativeSwitchCompiler: public AbstractSwitchCompiler {
|
||||||
|
public:
|
||||||
|
NativeSwitchCompiler(const SwitchStatement& sw, int indent=0);
|
||||||
|
private:
|
||||||
|
virtual void to_stream(std::ostream& os);
|
||||||
|
};
|
49
src/SwitchStatement.cpp
Normal file
49
src/SwitchStatement.cpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#include "SwitchStatement.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
AbstractSwitchCompiler::AbstractSwitchCompiler(
|
||||||
|
const SwitchStatement& sw,
|
||||||
|
int indent)
|
||||||
|
: sw(sw), indent_count(indent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractSwitchCompiler::operator()(ostream& os) {
|
||||||
|
to_stream(os);
|
||||||
|
}
|
||||||
|
|
||||||
|
string AbstractSwitchCompiler::operator()() {
|
||||||
|
ostringstream os;
|
||||||
|
(*this)(os);
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AbstractSwitchCompiler::indent_str(const std::string& str) {
|
||||||
|
ostringstream out;
|
||||||
|
|
||||||
|
int last_find = -1;
|
||||||
|
size_t find_pos;
|
||||||
|
while((find_pos = str.find('\n', last_find + 1)) != string::npos) {
|
||||||
|
out << indent()
|
||||||
|
<< str.substr(last_find + 1, find_pos - last_find); // includes \n
|
||||||
|
last_find = find_pos;
|
||||||
|
}
|
||||||
|
if(last_find + 1 < (int)str.size()) {
|
||||||
|
out << indent()
|
||||||
|
<< str.substr(last_find + 1)
|
||||||
|
<< '\n';
|
||||||
|
}
|
||||||
|
return out.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AbstractSwitchCompiler::indent() const {
|
||||||
|
return string(indent_count, '\t');
|
||||||
|
}
|
||||||
|
std::string AbstractSwitchCompiler::endcl() const {
|
||||||
|
return string("\n") + indent();
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractSwitchCompilerFactory::AbstractSwitchCompilerFactory() {}
|
58
src/SwitchStatement.hpp
Normal file
58
src/SwitchStatement.hpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/** Contains an abstract switch statement, which can be turned to C code later
|
||||||
|
* on. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <ostream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct SwitchStatement {
|
||||||
|
struct SwitchCase {
|
||||||
|
uintptr_t low_bound, high_bound;
|
||||||
|
std::string code;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string switch_var;
|
||||||
|
std::string default_case;
|
||||||
|
std::vector<SwitchCase> cases;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AbstractSwitchCompiler {
|
||||||
|
public:
|
||||||
|
AbstractSwitchCompiler(const SwitchStatement& sw,
|
||||||
|
int indent=0);
|
||||||
|
void operator()(std::ostream& os);
|
||||||
|
std::string operator()();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void to_stream(std::ostream& os) = 0;
|
||||||
|
std::string indent_str(const std::string& str) ;
|
||||||
|
std::string indent() const;
|
||||||
|
std::string endcl() const;
|
||||||
|
|
||||||
|
|
||||||
|
SwitchStatement sw;
|
||||||
|
int indent_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AbstractSwitchCompilerFactory {
|
||||||
|
public:
|
||||||
|
AbstractSwitchCompilerFactory();
|
||||||
|
virtual std::shared_ptr<AbstractSwitchCompiler> operator()(
|
||||||
|
const SwitchStatement& sw,
|
||||||
|
int indent=0) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Compiler>
|
||||||
|
class SwitchCompilerFactory : public AbstractSwitchCompilerFactory {
|
||||||
|
public:
|
||||||
|
virtual std::shared_ptr<AbstractSwitchCompiler> operator()(
|
||||||
|
const SwitchStatement& sw,
|
||||||
|
int indent=0)
|
||||||
|
{
|
||||||
|
return std::shared_ptr<AbstractSwitchCompiler>(
|
||||||
|
new Compiler(sw, indent));
|
||||||
|
}
|
||||||
|
};
|
|
@ -7,6 +7,8 @@
|
||||||
#include "SimpleDwarf.hpp"
|
#include "SimpleDwarf.hpp"
|
||||||
#include "DwarfReader.hpp"
|
#include "DwarfReader.hpp"
|
||||||
#include "CodeGenerator.hpp"
|
#include "CodeGenerator.hpp"
|
||||||
|
#include "SwitchStatement.hpp"
|
||||||
|
#include "NativeSwitchCompiler.hpp"
|
||||||
#include "PcHoleFiller.hpp"
|
#include "PcHoleFiller.hpp"
|
||||||
#include "ConseqEquivFilter.hpp"
|
#include "ConseqEquivFilter.hpp"
|
||||||
|
|
||||||
|
@ -106,7 +108,8 @@ int main(int argc, char** argv) {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << "_fde_" << fde.beg_ip;
|
ss << "_fde_" << fde.beg_ip;
|
||||||
return ss.str();
|
return ss.str();
|
||||||
});
|
},
|
||||||
|
new SwitchCompilerFactory<NativeSwitchCompiler>());
|
||||||
code_gen.generate();
|
code_gen.generate();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue