diff --git a/generate_eh_elf.py b/generate_eh_elf.py index 27838e1..a3d5504 100755 --- a/generate_eh_elf.py +++ b/generate_eh_elf.py @@ -148,6 +148,11 @@ def process_args(): help=("Force re-generation of the output files, even " "when those files are newer than the target " "ELF.")) + parser.add_argument('--enable-deref-arg', action='store_true', + help=("Pass the `--enable-deref-arg` to " + "dwarf-assembly, enabling an extra `deref` " + "argument for each lookup function, allowing " + "to work on remote address spaces.")) # c_opt_level opt_level_grp = parser.add_mutually_exclusive_group() opt_level_grp.add_argument('-O0', action='store_const', const='-O0', @@ -197,6 +202,8 @@ def main(): for opt in DW_ASSEMBLY_OPTS: if opt in args and args_dict[opt] is not None: dwarf_assembly_opts.append(DW_ASSEMBLY_OPTS[opt]) + if args.enable_deref_arg: + dwarf_assembly_opts.append('--enable-deref-arg') for obj in args.object: args.gen_func(obj, args, dwarf_assembly_opts) diff --git a/shared/context_struct.h b/shared/context_struct.h index a5d4d8a..41a49e8 100644 --- a/shared/context_struct.h +++ b/shared/context_struct.h @@ -5,3 +5,5 @@ typedef struct { } unwind_context_t; typedef unwind_context_t (*_fde_func_t)(unwind_context_t, uintptr_t); + +typedef uintptr_t (*deref_func_t)(uintptr_t); diff --git a/src/CodeGenerator.cpp b/src/CodeGenerator.cpp index 3fd43e1..1e7e600 100644 --- a/src/CodeGenerator.cpp +++ b/src/CodeGenerator.cpp @@ -65,9 +65,13 @@ void CodeGenerator::gen_of_dwarf() { } void CodeGenerator::gen_unwind_func_header(const std::string& name) { + string deref_arg; + if(settings::enable_deref_arg) + deref_arg = ", deref_func_t deref"; + os << "unwind_context_t " << name - << "(unwind_context_t ctx, uintptr_t pc) {\n" + << "(unwind_context_t ctx, uintptr_t pc" << deref_arg << ") {\n" << "\tunwind_context_t out_ctx;\n" << "\tswitch(pc) {" << endl; } @@ -168,11 +172,19 @@ void CodeGenerator::gen_of_reg(const SimpleDwarf::DwRegister& reg) { os << ctx_of_dw_name(reg.reg) << " + (" << reg.offset << ")"; break; - case SimpleDwarf::DwRegister::REG_CFA_OFFSET: - os << "*((uintptr_t*)(out_ctx.rsp + (" - << reg.offset - << ")))"; + case SimpleDwarf::DwRegister::REG_CFA_OFFSET: { + if(settings::enable_deref_arg) { + os << "deref(out_ctx.rsp + (" + << reg.offset + << "))"; + } + else { + os << "*((uintptr_t*)(out_ctx.rsp + (" + << reg.offset + << ")))"; + } break; + } case SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED: os << "0; assert(0)"; break; diff --git a/src/README.md b/src/README.md index df1e81e..501c653 100644 --- a/src/README.md +++ b/src/README.md @@ -23,3 +23,20 @@ a list of all PCs in the ELF. The file contains one 8-bytes chunk per PC, which is the PC in little endian. `--pc-list PC_LIST_FILE_PATH` + +### Dereferencing function + +The lookup functions can also take an additional argument, a pointer to a +function of prototype + +```C + uintptr_t deref(uintptr_t address) +``` + +that will, in spirit, contain a `return *((uintptr_t*)address);`. + +This argument can be used to work on remote address spaces instead of local +address spaces, eg. to work with `libunwind`. + +To enable the presence of this argument, you must pass the option +`--enable-deref-arg` diff --git a/src/main.cpp b/src/main.cpp index 81adc8e..b41e06e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -56,6 +56,10 @@ MainOptions options_parse(int argc, char** argv) { settings::pc_list = argv[option_pos]; } } + + else if(option == "--enable-deref-arg") { + settings::enable_deref_arg = true; + } } if(!seen_switch_gen_policy) { diff --git a/src/settings.cpp b/src/settings.cpp index 97b1661..fb37711 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -3,4 +3,5 @@ namespace settings { SwitchGenerationPolicy switch_generation_policy = SGP_SwitchPerFunc; std::string pc_list = ""; + bool enable_deref_arg = false; } diff --git a/src/settings.hpp b/src/settings.hpp index 1c9e9f1..4ec239e 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -15,4 +15,5 @@ namespace settings { extern SwitchGenerationPolicy switch_generation_policy; extern std::string pc_list; + extern bool enable_deref_arg; }