Skip to content

Commit

Permalink
Add support for Windows on ARM (#1502)
Browse files Browse the repository at this point in the history
* Support building for Windows on ARM

* Fix usage of reserved function name on ARM
* Fix architecture dependent `CONTEXT` fields access

* Fixes for debugging on Windows on ARM

* Fix breakpoint behavior on windows on ARM
* Fix register profile when debugging
* Remove `drx` error message if not supported
* Add support for hardware breakpoints
* Disable support for hardware single-stepping

* Fix Windows Message breakpoints on ARM

* Fix software single-stepping on return instruction on ARM

* Consider link register as destination for return instructions

* Fix setting debug bits to 16

* Rename `r12` to `ip` for windows arm register profile

* Remove debug bits hardcoding on windows

* Add 32bit registers to Windows ARM64 register profile

* Fix software step breakpoint alignment when entering thumb mode

* Define `RZ_TEST_ARCH` for `arm` and `arm64`

* Use `StackWalk64` API for backtracing on Windows

* Fix software single-stepping ARM in thumb mode

* Sync `asm.bits` with debugger

* Cleanup windows_debug.c

* Add SPDX for cross-arm64-windows.txt

* Add floating point control register flags

* Fix Windows Arm register profile alignment

* Keep `drx` warning
  • Loading branch information
GustavoLCR authored and thestr4ng3r committed Nov 24, 2021
1 parent cc17da7 commit fb09cb1
Show file tree
Hide file tree
Showing 21 changed files with 815 additions and 282 deletions.
4 changes: 4 additions & 0 deletions binrz/rz-test/rz_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
#define RZ_TEST_ARCH "x86"
#elif __x86_64__
#define RZ_TEST_ARCH "x64"
#elif __arm__
#define RZ_TEST_ARCH "arm"
#elif __arm64__
#define RZ_TEST_ARCH "arm64"
#else
#define RZ_TEST_ARCH "unknown"
#endif
Expand Down
12 changes: 4 additions & 8 deletions librz/core/cconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -696,14 +696,6 @@ static bool cb_asmbits(void *user, void *data) {
bool load_from_debug = rz_config_get_b(core->config, "cfg.debug");
if (load_from_debug) {
if (core->dbg->cur && core->dbg->cur->reg_profile) {
// XXX. that should depend on the plugin, not the host os
#if __WINDOWS__
#if !defined(_WIN64)
core->dbg->bits = RZ_SYS_BITS_32;
#else
core->dbg->bits = RZ_SYS_BITS_64;
#endif
#endif
char *rp = core->dbg->cur->reg_profile(core->dbg);
rz_reg_set_profile_string(core->dbg->reg, rp);
rz_reg_set_profile_string(core->analysis->reg, rp);
Expand Down Expand Up @@ -3383,7 +3375,11 @@ RZ_API int rz_core_config_init(RzCore *core) {

SETCB("dbg.bpinmaps", "true", &cb_dbg_bpinmaps, "Activate breakpoints only if they are inside a valid map");
SETCB("dbg.forks", "false", &cb_dbg_forks, "Stop execution if fork() is done (see dbg.threads)");
#if __WINDOWS__
n = NODECB("dbg.btalgo", "default", &cb_dbg_btalgo);
#else
n = NODECB("dbg.btalgo", "fuzzy", &cb_dbg_btalgo);
#endif
SETDESC(n, "Select backtrace algorithm");
SETOPTIONS(n, "default", "fuzzy", "analysis", "trace", NULL);
SETCB("dbg.threads", "false", &cb_stopthreads, "Stop all threads when debugger breaks (see dbg.forks)");
Expand Down
19 changes: 19 additions & 0 deletions librz/core/cdebug.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,25 @@ RZ_API void rz_core_debug_ri(RzCore *core, RzReg *reg, int mode) {
ht_up_free(db);
}

RZ_IPI void rz_core_debug_sync_bits(RzCore *core) {
if (rz_config_get_b(core->config, "cfg.debug")) {
switch (core->dbg->bits) {
case RZ_SYS_BITS_8:
rz_config_set_i(core->config, "asm.bits", 8);
break;
case RZ_SYS_BITS_16:
rz_config_set_i(core->config, "asm.bits", 16);
break;
case RZ_SYS_BITS_32:
rz_config_set_i(core->config, "asm.bits", 32);
break;
case RZ_SYS_BITS_64:
rz_config_set_i(core->config, "asm.bits", 64);
break;
}
}
}

RZ_IPI void rz_core_debug_single_step_in(RzCore *core) {
if (rz_config_get_b(core->config, "cfg.debug")) {
if (core->print->cur_enabled) {
Expand Down
1 change: 1 addition & 0 deletions librz/core/cmd/cmd_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,7 @@ RZ_IPI void rz_core_dbg_follow_seek_register(RzCore *core) {
if ((pc < core->offset) || (pc > (core->offset + follow))) {
rz_core_seek_to_register(core, "PC", false);
}
rz_core_debug_sync_bits(core);
}
}

Expand Down
1 change: 1 addition & 0 deletions librz/core/core_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ RZ_IPI bool rz_core_debug_reg_set(RzCore *core, const char *regname, ut64 val, c
RZ_IPI bool rz_core_debug_reg_list(RzCore *core, int type, int size, bool skip_covered, PJ *pj, int rad, const char *use_color);
RZ_IPI void rz_core_debug_regs2flags(RzCore *core);
RZ_IPI void rz_core_regs2flags(RzCore *core);
RZ_IPI void rz_core_debug_sync_bits(RzCore *core);
RZ_IPI void rz_core_debug_single_step_in(RzCore *core);
RZ_IPI void rz_core_debug_single_step_over(RzCore *core);
RZ_IPI void rz_core_debug_breakpoint_toggle(RzCore *core, ut64 addr);
Expand Down
1 change: 1 addition & 0 deletions librz/core/tui/visual.c
Original file line number Diff line number Diff line change
Expand Up @@ -3363,6 +3363,7 @@ RZ_API void rz_core_visual_title(RzCore *core, int color) {
} else if (follow < 0) {
rz_core_seek(core, curpc + follow, true);
}
rz_core_debug_sync_bits(core);
oldpc = curpc;
}
}
Expand Down
27 changes: 23 additions & 4 deletions librz/debug/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,11 @@ RZ_API int rz_debug_stop(RzDebug *dbg) {
RZ_API bool rz_debug_set_arch(RzDebug *dbg, const char *arch, int bits) {
if (arch && dbg && dbg->cur) {
switch (bits) {
case 16:
if (dbg->cur->bits & RZ_SYS_BITS_16) {
dbg->bits = RZ_SYS_BITS_16;
}
break;
case 27:
if (dbg->cur->bits == 27) {
dbg->bits = 27;
Expand Down Expand Up @@ -798,6 +803,9 @@ RZ_API int rz_debug_step_soft(RzDebug *dbg) {
return false;
}

const bool has_lr_reg = rz_reg_get_name(dbg->reg, RZ_REG_NAME_LR);
const bool arch_ret_is_pop = !strcmp(dbg->arch, "arm") && dbg->bits <= RZ_SYS_BITS_32;

pc = rz_debug_reg_get(dbg, dbg->reg->name[RZ_REG_NAME_PC]);
sp = rz_debug_reg_get(dbg, dbg->reg->name[RZ_REG_NAME_SP]);

Expand All @@ -815,8 +823,15 @@ RZ_API int rz_debug_step_soft(RzDebug *dbg) {
}
switch (op.type) {
case RZ_ANALYSIS_OP_TYPE_RET:
dbg->iob.read_at(dbg->iob.io, sp, (ut8 *)&sp_top, 8);
next[0] = (dbg->bits == RZ_SYS_BITS_32) ? sp_top.r32[0] : sp_top.r64;
if (arch_ret_is_pop && op.stackop == RZ_ANALYSIS_STACK_INC) {
dbg->iob.read_at(dbg->iob.io, sp - op.stackptr - 4, (ut8 *)&sp_top, 4);
next[0] = sp_top.r32[0];
} else if (has_lr_reg) {
next[0] = rz_debug_reg_get(dbg, dbg->reg->name[RZ_REG_NAME_LR]);
} else {
dbg->iob.read_at(dbg->iob.io, sp, (ut8 *)&sp_top, 8);
next[0] = (dbg->bits <= RZ_SYS_BITS_32) ? sp_top.r32[0] : sp_top.r64;
}
br = 1;
break;
case RZ_ANALYSIS_OP_TYPE_CJMP:
Expand All @@ -842,7 +857,7 @@ RZ_API int rz_debug_step_soft(RzDebug *dbg) {
if (!dbg->iob.read_at(dbg->iob.io, r, (ut8 *)&memval, 8)) {
next[0] = op.addr + op.size;
} else {
next[0] = (dbg->bits == RZ_SYS_BITS_32) ? memval.r32[0] : memval.r64;
next[0] = (dbg->bits <= RZ_SYS_BITS_32) ? memval.r32[0] : memval.r64;
}
br = 1;
break;
Expand All @@ -857,7 +872,7 @@ RZ_API int rz_debug_step_soft(RzDebug *dbg) {
if (!dbg->iob.read_at(dbg->iob.io, r * op.scale + op.disp, (ut8 *)&memval, 8)) {
next[0] = op.addr + op.size;
} else {
next[0] = (dbg->bits == RZ_SYS_BITS_32) ? memval.r32[0] : memval.r64;
next[0] = (dbg->bits <= RZ_SYS_BITS_32) ? memval.r32[0] : memval.r64;
}
br = 1;
break;
Expand All @@ -867,7 +882,11 @@ RZ_API int rz_debug_step_soft(RzDebug *dbg) {
break;
}

const int align = rz_analysis_archinfo(dbg->analysis, RZ_ANALYSIS_ARCHINFO_ALIGN);
for (i = 0; i < br; i++) {
if (align > 1) {
next[i] = next[i] - (next[i] % align);
}
RzBreakpointItem *bpi = rz_bp_add_sw(dbg->bp, next[i], dbg->bpsize, RZ_BP_PROT_EXEC);
if (bpi) {
bpi->swstep = true;
Expand Down
15 changes: 13 additions & 2 deletions librz/debug/p/debug_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,10 @@ static int rz_debug_native_step(RzDebug *dbg) {
return false;
}
return true;
#else // linux
#elif __linux__
return linux_step(dbg);
#endif
return 0;
}

// return thread id
Expand Down Expand Up @@ -1305,7 +1306,7 @@ static int rz_debug_native_drx(RzDebug *dbg, int n, ut64 addr, int sz, int rwx,
#else
eprintf("drx: Unsupported platform\n");
#endif
return false;
return -1;
}

#if __linux__
Expand Down Expand Up @@ -1434,6 +1435,10 @@ static int rz_debug_native_bp(RzBreakpoint *bp, RzBreakpointItem *b, bool set) {
return set
? arm64_hwbp_add(dbg, bp, b)
: arm64_hwbp_del(dbg, bp, b);
#elif __WINDOWS__
return set
? w32_hwbp_arm_add(dbg, bp, b)
: w32_hwbp_arm_del(dbg, bp, b);
#elif __arm__ && __linux__
return set
? arm32_hwbp_add(dbg, bp, b)
Expand Down Expand Up @@ -1602,7 +1607,11 @@ RzDebugPlugin rz_debug_plugin_native = {
#elif __aarch64__ || __arm64__
.bits = RZ_SYS_BITS_16 | RZ_SYS_BITS_32 | RZ_SYS_BITS_64,
.arch = "arm",
#if __WINDOWS__
.canstep = 0,
#else
.canstep = 1,
#endif
#elif __arm__
.bits = RZ_SYS_BITS_16 | RZ_SYS_BITS_32 | RZ_SYS_BITS_64,
.arch = "arm",
Expand Down Expand Up @@ -1656,7 +1665,9 @@ RzDebugPlugin rz_debug_plugin_native = {
.modules_get = rz_debug_native_modules_get,
.map_protect = rz_debug_native_map_protect,
.breakpoint = rz_debug_native_bp,
#if __i386__ || __x86_64__
.drx = rz_debug_native_drx,
#endif
.gcore = rz_debug_gcore,
};

Expand Down
14 changes: 7 additions & 7 deletions librz/debug/p/debug_windbg.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ typedef struct { // Keep in sync with io_windbg.c
PDEBUG_ADVANCED3 dbgAdvanced;
} DbgEngContext;

static bool __is_target_kernel(DbgEngContext *idbg) {
static bool is_target_kernel(DbgEngContext *idbg) {
ULONG Class, Qualifier;
if (SUCCEEDED(ITHISCALL(dbgCtrl, GetDebuggeeType, &Class, &Qualifier))) {
if (Class == DEBUG_CLASS_KERNEL) {
Expand Down Expand Up @@ -81,7 +81,7 @@ static int windbg_select(RzDebug *dbg, int pid, int tid) {
rz_return_val_if_fail(idbg && idbg->initialized, 0);
ULONG process_id = pid;
ULONG thread_id = tid;
if (!__is_target_kernel(idbg)) {
if (!is_target_kernel(idbg)) {
ITHISCALL(dbgSysObj, GetProcessIdBySystemId, pid, &process_id);
ITHISCALL(dbgSysObj, GetThreadIdBySystemId, tid, &thread_id);
}
Expand Down Expand Up @@ -136,10 +136,10 @@ static int windbg_stop(RzDebug *dbg) {

static bool do_break = false;

static void __break(void *user) {
static void break_debugger(void *user) {
RzDebug *dbg = (RzDebug *)user;
DbgEngContext *idbg = dbg->plugin_data;
if (__is_target_kernel(idbg)) {
if (is_target_kernel(idbg)) {
windbg_stop(dbg);
}
do_break = true;
Expand All @@ -149,8 +149,8 @@ static int windbg_wait(RzDebug *dbg, int pid) {
DbgEngContext *idbg = dbg->plugin_data;
rz_return_val_if_fail(idbg && idbg->initialized, 0);
ULONG Type, ProcessId, ThreadId;
rz_cons_break_push(__break, dbg);
const ULONG timeout = __is_target_kernel(idbg) ? INFINITE : TIMEOUT;
rz_cons_break_push(break_debugger, dbg);
const ULONG timeout = is_target_kernel(idbg) ? INFINITE : TIMEOUT;
HRESULT hr;
while ((hr = ITHISCALL(dbgCtrl, WaitForEvent, DEBUG_WAIT_DEFAULT, timeout)) == S_FALSE) {
if (do_break) {
Expand All @@ -165,7 +165,7 @@ static int windbg_wait(RzDebug *dbg, int pid) {
return RZ_DEBUG_REASON_DEAD;
}
ITHISCALL(dbgCtrl, GetLastEventInformation, &Type, &ProcessId, &ThreadId, NULL, 0, NULL, NULL, 0, NULL);
if (!__is_target_kernel(idbg)) {
if (!is_target_kernel(idbg)) {
ITHISCALL(dbgSysObj, GetCurrentProcessSystemId, (PULONG)&dbg->pid);
ITHISCALL(dbgSysObj, GetCurrentThreadSystemId, (PULONG)&dbg->tid);
} else {
Expand Down
18 changes: 15 additions & 3 deletions librz/debug/p/native/bt.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

#include <rz_analysis.h>

#if __WINDOWS__
#include "bt/windows-all.c"
#endif
#include "bt/generic-x86.c"
#include "bt/generic-x64.c"
#include "bt/fuzzy-all.c"
Expand Down Expand Up @@ -46,19 +49,28 @@ static RzList *rz_debug_native_frames(RzDebug *dbg, ut64 at) {
if (!strcmp(dbg->btalgo, "fuzzy")) {
cb = backtrace_fuzzy;
} else if (!strcmp(dbg->btalgo, "analysis")) {
if (dbg->bits == RZ_SYS_BITS_64) {
cb = backtrace_x86_64_analysis;
if (!strcmp(dbg->arch, "x86")) {
if (dbg->bits == RZ_SYS_BITS_64) {
cb = backtrace_x86_64_analysis;
} else {
cb = backtrace_x86_32_analysis;
}
} else {
cb = backtrace_x86_32_analysis;
eprintf("Analysis backtrace not available for current architecture (%s)\n", dbg->arch);
return NULL;
}
}
}
if (!cb) {
#if __WINDOWS__
cb = backtrace_windows;
#else
if (dbg->bits == RZ_SYS_BITS_64) {
cb = backtrace_x86_64;
} else {
cb = backtrace_x86_32;
}
#endif
}

RzList *list;
Expand Down
Loading

0 comments on commit fb09cb1

Please sign in to comment.