Use flags in context structures

This commit is contained in:
Théophile Bastian 2018-06-22 09:12:32 +02:00
parent b6ae4b2115
commit cd9ecafb4f
3 changed files with 92 additions and 28 deletions

View file

@ -1,6 +1,15 @@
#include <stdint.h> #include <stdint.h>
typedef enum {
UNWF_RIP=0,
UNWF_RSP=1,
UNWF_RBP=2,
UNWF_ERROR=7
} unwind_flags_t;
typedef struct { typedef struct {
uint8_t flags;
uintptr_t rip, rsp, rbp; uintptr_t rip, rsp, rbp;
} unwind_context_t; } unwind_context_t;

View file

@ -1,6 +1,7 @@
#include "CodeGenerator.hpp" #include "CodeGenerator.hpp"
#include "gen_context_struct.hpp" #include "gen_context_struct.hpp"
#include "settings.hpp" #include "settings.hpp"
#include "../shared/context_struct.h"
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
@ -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<uintptr_t>::max() << "ull";
val = oss.str();
}
return val;
}
void CodeGenerator::generate() { void CodeGenerator::generate() {
gen_of_dwarf(); gen_of_dwarf();
} }
@ -90,12 +81,33 @@ void CodeGenerator::gen_unwind_func_header(const std::string& name) {
<< "\tswitch(pc) {" << 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;
flags.error = true;
os << "\t\tdefault:\n" os << "\t\tdefault:\n"
<< "\t\t\tout_ctx.rsp = " << undefined_register() << ";\n" << "\t\t\tout_ctx.flags = " << (int) flags.to_uint8() << "u;\n"
<< "\t\t\tout_ctx.rbp = " << undefined_register() << ";\n" << "\t\t\treturn out_ctx;\n"
<< "\t\t\tout_ctx.rip = " << undefined_register() << ";\n"
<< "\t\t\treturn out_ctx;"
<< "\t}\n" << "\t}\n"
<< "}" << endl; << "}" << endl;
} }
@ -126,26 +138,51 @@ void CodeGenerator::gen_of_row(
uintptr_t row_end) uintptr_t row_end)
{ {
gen_case(row.ip, row_end); gen_case(row.ip, row_end);
UnwFlags flags;
try { try {
os << "\t\t\t" << "out_ctx.rsp = "; if(!check_reg_valid(row.ra)) {
gen_of_reg(row.cfa); // RA might be undefined (last frame), but if it is defined and we
os << ';' << endl; // don't implement it (eg. EXPR), it is an error
flags.error = true;
goto write_flags;
}
os << "\t\t\t" << "out_ctx.rbp = "; if(check_reg_valid(row.cfa)) {
gen_of_reg(row.rbp); flags.rsp = true;
os << ';' << endl; 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) { } catch(const UnhandledRegister& exn) {
os << ";\n" // This should not happen, since we check_reg_*, but heh.
<< "\t\t\tout_ctx.rip = " << undefined_register() << ";\n" flags.error = true;
<< "\t\t\tout_ctx.rsp = " << undefined_register() << ";\n" os << ";\n";
<< "\t\t\tout_ctx.rbp = " << undefined_register() << ";\n";
} }
write_flags:
os << "\t\t\tout_ctx.flags = " << (int)flags.to_uint8() << "u;" << endl;
os << "\t\t\treturn " << "out_ctx" << ";" << endl; os << "\t\t\treturn " << "out_ctx" << ";" << endl;
} }
@ -188,10 +225,25 @@ static const char* ctx_of_dw_name(SimpleDwarf::MachineRegister reg) {
return ""; 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) { void CodeGenerator::gen_of_reg(const SimpleDwarf::DwRegister& reg) {
switch(reg.type) { switch(reg.type) {
case SimpleDwarf::DwRegister::REG_UNDEFINED: case SimpleDwarf::DwRegister::REG_UNDEFINED:
os << undefined_register(); // This function is not supposed to be called on an undefined
// register
throw UnhandledRegister();
break; break;
case SimpleDwarf::DwRegister::REG_REGISTER: case SimpleDwarf::DwRegister::REG_REGISTER:
os << ctx_of_dw_name(reg.reg) os << ctx_of_dw_name(reg.reg)

View file

@ -48,6 +48,9 @@ class CodeGenerator {
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_valid(const SimpleDwarf::DwRegister& reg);
private: private:
SimpleDwarf dwarf; SimpleDwarf dwarf;
std::ostream& os; std::ostream& os;