diff --git a/shared/context_struct.h b/shared/context_struct.h index ae6ffeb..692b911 100644 --- a/shared/context_struct.h +++ b/shared/context_struct.h @@ -1,6 +1,15 @@ #include +typedef enum { + UNWF_RIP=0, + UNWF_RSP=1, + UNWF_RBP=2, + + UNWF_ERROR=7 +} unwind_flags_t; + typedef struct { + uint8_t flags; uintptr_t rip, rsp, rbp; } unwind_context_t; diff --git a/src/CodeGenerator.cpp b/src/CodeGenerator.cpp index f5b165c..a55a4c0 100644 --- a/src/CodeGenerator.cpp +++ b/src/CodeGenerator.cpp @@ -1,6 +1,7 @@ #include "CodeGenerator.hpp" #include "gen_context_struct.hpp" #include "settings.hpp" +#include "../shared/context_struct.h" #include #include @@ -28,16 +29,6 @@ CodeGenerator::CodeGenerator( } } -static std::string undefined_register() { - static std::string val = ""; - if(val.empty()) { - std::ostringstream oss; - oss << std::numeric_limits::max() << "ull"; - val = oss.str(); - } - return val; -} - void CodeGenerator::generate() { gen_of_dwarf(); } @@ -90,12 +81,33 @@ void CodeGenerator::gen_unwind_func_header(const std::string& name) { << "\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() { + UnwFlags flags; + flags.error = true; os << "\t\tdefault:\n" - << "\t\t\tout_ctx.rsp = " << undefined_register() << ";\n" - << "\t\t\tout_ctx.rbp = " << undefined_register() << ";\n" - << "\t\t\tout_ctx.rip = " << undefined_register() << ";\n" - << "\t\t\treturn out_ctx;" + << "\t\t\tout_ctx.flags = " << (int) flags.to_uint8() << "u;\n" + << "\t\t\treturn out_ctx;\n" << "\t}\n" << "}" << endl; } @@ -126,26 +138,51 @@ void CodeGenerator::gen_of_row( uintptr_t row_end) { gen_case(row.ip, row_end); + UnwFlags flags; + try { - os << "\t\t\t" << "out_ctx.rsp = "; - gen_of_reg(row.cfa); - os << ';' << endl; + if(!check_reg_valid(row.ra)) { + // RA might be undefined (last frame), but if it is defined and we + // don't implement it (eg. EXPR), it is an error + flags.error = true; + goto write_flags; + } - os << "\t\t\t" << "out_ctx.rbp = "; - gen_of_reg(row.rbp); - os << ';' << endl; + if(check_reg_valid(row.cfa)) { + flags.rsp = true; + os << "\t\t\t" << "out_ctx.rsp = "; + gen_of_reg(row.cfa); + os << ';' << endl; + } + else { // rsp is required (CFA) + flags.error = true; + goto write_flags; + } + + if(check_reg_defined(row.rbp)) { + flags.rbp = true; + os << "\t\t\t" << "out_ctx.rbp = "; + gen_of_reg(row.rbp); + os << ';' << endl; + } + + if(check_reg_defined(row.ra)) { + flags.rip = true; + os << "\t\t\t" << "out_ctx.rip = "; + gen_of_reg(row.ra); + os << ';' << endl; + } - os << "\t\t\t" << "out_ctx.rip = "; - gen_of_reg(row.ra); - os << ';' << endl; } catch(const UnhandledRegister& exn) { - os << ";\n" - << "\t\t\tout_ctx.rip = " << undefined_register() << ";\n" - << "\t\t\tout_ctx.rsp = " << undefined_register() << ";\n" - << "\t\t\tout_ctx.rbp = " << undefined_register() << ";\n"; + // This should not happen, since we check_reg_*, but heh. + flags.error = true; + os << ";\n"; } +write_flags: + os << "\t\t\tout_ctx.flags = " << (int)flags.to_uint8() << "u;" << endl; + os << "\t\t\treturn " << "out_ctx" << ";" << endl; } @@ -188,10 +225,25 @@ static const char* ctx_of_dw_name(SimpleDwarf::MachineRegister reg) { return ""; } +bool CodeGenerator::check_reg_defined(const SimpleDwarf::DwRegister& reg) { + switch(reg.type) { + case SimpleDwarf::DwRegister::REG_UNDEFINED: + case SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED: + return false; + default: + return true; + } +} +bool CodeGenerator::check_reg_valid(const SimpleDwarf::DwRegister& reg) { + return reg.type != SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED; +} + void CodeGenerator::gen_of_reg(const SimpleDwarf::DwRegister& reg) { switch(reg.type) { case SimpleDwarf::DwRegister::REG_UNDEFINED: - os << undefined_register(); + // This function is not supposed to be called on an undefined + // register + throw UnhandledRegister(); break; case SimpleDwarf::DwRegister::REG_REGISTER: os << ctx_of_dw_name(reg.reg) diff --git a/src/CodeGenerator.hpp b/src/CodeGenerator.hpp index 7669459..a559f9c 100644 --- a/src/CodeGenerator.hpp +++ b/src/CodeGenerator.hpp @@ -48,6 +48,9 @@ class CodeGenerator { void gen_lookup(const std::vector& entries); + bool check_reg_defined(const SimpleDwarf::DwRegister& reg); + bool check_reg_valid(const SimpleDwarf::DwRegister& reg); + private: SimpleDwarf dwarf; std::ostream& os;