Add Alpha linux native debugger (#6447)
* add alpha to rz_types * fix register read * add register write * add breakpoint instruction * fix register sp
This commit is contained in:
parent
fb9b15eac6
commit
25886f4ccf
6 changed files with 436 additions and 0 deletions
|
|
@ -102,6 +102,11 @@ static bool fini(void *u) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool alpha_sw_breakpoint(const RzAsm *a, ut64 addr, const RzAsmOp *original, RzAsmOp *breakpoint) {
|
||||
rz_asm_op_set_buf(breakpoint, (const ut8 *)"\x80\x00\x00\x00", 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
RzAsmPlugin rz_asm_plugin_alpha_cs = {
|
||||
.name = "alpha",
|
||||
.desc = "DEC Alpha Capstone-based disassembler",
|
||||
|
|
@ -112,6 +117,7 @@ RzAsmPlugin rz_asm_plugin_alpha_cs = {
|
|||
.disassemble = &disassemble,
|
||||
.init = &init,
|
||||
.fini = &fini,
|
||||
.sw_breakpoint = &alpha_sw_breakpoint,
|
||||
};
|
||||
|
||||
#ifndef RZ_PLUGIN_INCORE
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@ if has_debugger
|
|||
rz_debug_sources += ['p/native/linux_riscv64.c']
|
||||
elif host_machine.cpu_family() == 'riscv32'
|
||||
rz_debug_sources += ['p/native/linux_riscv32.c']
|
||||
elif host_machine.cpu_family() == 'alpha'
|
||||
rz_debug_sources += ['p/native/linux_alpha.c']
|
||||
else
|
||||
rz_debug_sources += ['p/native/linux_other.c']
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -153,6 +153,11 @@ struct powerpc_regs_t {
|
|||
#include <sys/ucontext.h>
|
||||
typedef ut64 mips64_regs_t[274];
|
||||
#define RZ_DEBUG_REG_T mips64_regs_t
|
||||
|
||||
#elif __alpha__
|
||||
#include <asm/ptrace.h>
|
||||
#define RZ_DEBUG_REG_T struct pt_regs
|
||||
#define RZ_DEBUG_FPREG_T fpreg_t
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
|||
342
librz/debug/p/native/linux_alpha.c
Normal file
342
librz/debug/p/native/linux_alpha.c
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
// SPDX-FileCopyrightText: 2026 well-mannered-goat <takshformal@gmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include "rz_util/rz_log.h"
|
||||
#include <errno.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <linux/elf.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include "linux/linux_debug.h"
|
||||
#include "procfs.h"
|
||||
#include "bt.c"
|
||||
|
||||
#ifdef __WALL
|
||||
#define WAITPID_FLAGS __WALL
|
||||
#else
|
||||
#define WAITPID_FLAGS 0
|
||||
#endif
|
||||
|
||||
#define ALPHA_PTRACE_REG_COUNT 66
|
||||
|
||||
static char *rz_debug_native_reg_profile(RzDebug *dbg) {
|
||||
#include "reg/linux-alpha.h"
|
||||
}
|
||||
|
||||
static bool rz_debug_native_step(RzDebug *dbg) {
|
||||
return linux_step(dbg);
|
||||
}
|
||||
|
||||
static int rz_debug_native_attach(RzDebug *dbg, int pid) {
|
||||
return linux_attach(dbg, pid);
|
||||
}
|
||||
|
||||
static int rz_debug_native_detach(RzDebug *dbg, int pid) {
|
||||
return rz_debug_ptrace(dbg, PTRACE_DETACH, pid, NULL, (rz_ptrace_data_t)(size_t)0);
|
||||
}
|
||||
|
||||
static int rz_debug_native_select(RzDebug *dbg, int pid, int tid) {
|
||||
return linux_select(dbg, pid, tid);
|
||||
}
|
||||
|
||||
static int rz_debug_native_continue_syscall(RzDebug *dbg, int pid, int num) {
|
||||
linux_set_options(dbg, pid);
|
||||
return rz_debug_ptrace(dbg, PTRACE_SYSCALL, pid, 0, 0);
|
||||
}
|
||||
|
||||
static void interrupt_process(RzDebug *dbg) {
|
||||
rz_debug_kill(dbg, dbg->pid, dbg->tid, SIGINT);
|
||||
rz_cons_break_pop();
|
||||
}
|
||||
|
||||
static int rz_debug_native_stop(RzDebug *dbg) {
|
||||
return linux_stop_threads(dbg, dbg->reason.tid);
|
||||
}
|
||||
|
||||
static int rz_debug_native_continue(RzDebug *dbg, int pid, int tid, int sig) {
|
||||
int contsig = dbg->reason.signum;
|
||||
int ret = -1;
|
||||
|
||||
if (sig != -1) {
|
||||
contsig = sig;
|
||||
}
|
||||
/* SIGINT handler for attached processes: dbg.consbreak (disabled by default) */
|
||||
if (dbg->consbreak) {
|
||||
rz_cons_break_push((RzConsBreak)interrupt_process, dbg);
|
||||
}
|
||||
|
||||
if (dbg->continue_all_threads && dbg->n_threads && dbg->threads) {
|
||||
RzDebugPid *th;
|
||||
RzListIter *it;
|
||||
rz_list_foreach (dbg->threads, it, th) {
|
||||
ret = rz_debug_ptrace(dbg, PTRACE_CONT, th->pid, 0, 0);
|
||||
if (ret) {
|
||||
RZ_LOG_ERROR("(%d) is running or dead.\n", th->pid);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = rz_debug_ptrace(dbg, PTRACE_CONT, tid, NULL, (rz_ptrace_data_t)(size_t)contsig);
|
||||
if (ret) {
|
||||
rz_sys_perror("PTRACE_CONT");
|
||||
}
|
||||
}
|
||||
return tid;
|
||||
}
|
||||
|
||||
static RzDebugInfo *rz_debug_native_info(RzDebug *dbg, const char *arg) {
|
||||
return linux_info(dbg, arg);
|
||||
}
|
||||
|
||||
static RzDebugReasonType rz_debug_native_wait(RzDebug *dbg, int pid) {
|
||||
RzDebugReasonType reason = RZ_DEBUG_REASON_UNKNOWN;
|
||||
if (pid < 0) {
|
||||
RZ_LOG_ERROR("rz_debug_native_wait called with pid -1\n");
|
||||
return RZ_DEBUG_REASON_ERROR;
|
||||
}
|
||||
|
||||
reason = linux_dbg_wait(dbg, dbg->tid);
|
||||
dbg->reason.type = reason;
|
||||
return reason;
|
||||
}
|
||||
|
||||
#undef MAXPID
|
||||
#define MAXPID 99999
|
||||
|
||||
static RzList /*<RzDebugPid *>*/ *rz_debug_native_pids(RzDebug *dbg, int pid) {
|
||||
RzList *list = rz_list_new();
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
return linux_pid_list(pid, list);
|
||||
}
|
||||
|
||||
RZ_API RZ_OWN RzList /*<RzDebugPid *>*/ *rz_debug_native_threads(RzDebug *dbg, int pid) {
|
||||
RzList *list = rz_list_new();
|
||||
if (!list) {
|
||||
RZ_LOG_ERROR("Cannot create list\n");
|
||||
return NULL;
|
||||
}
|
||||
return linux_thread_list(dbg, pid, list);
|
||||
}
|
||||
|
||||
RZ_API ut64 rz_debug_get_tls(RZ_NONNULL RzDebug *dbg, int tid) {
|
||||
rz_return_val_if_fail(dbg, 0);
|
||||
return get_linux_tls_val(dbg, tid);
|
||||
}
|
||||
|
||||
static int rz_debug_native_reg_read(RzDebug *dbg, int type, ut8 *buf, int size) {
|
||||
if (size < 1) {
|
||||
return false;
|
||||
}
|
||||
int pid = dbg->tid;
|
||||
switch (type) {
|
||||
case RZ_REG_TYPE_DRX:
|
||||
case RZ_REG_TYPE_MMX:
|
||||
case RZ_REG_TYPE_XMM:
|
||||
case RZ_REG_TYPE_YMM:
|
||||
return false;
|
||||
case RZ_REG_TYPE_SEG:
|
||||
case RZ_REG_TYPE_FLG:
|
||||
case RZ_REG_TYPE_FPU:
|
||||
case RZ_REG_TYPE_GPR: {
|
||||
ut64 regs[ALPHA_PTRACE_REG_COUNT];
|
||||
memset(®s, 0, sizeof(regs));
|
||||
memset(buf, 0, size);
|
||||
|
||||
for (int i = 0; i < ALPHA_PTRACE_REG_COUNT; i++) {
|
||||
errno = 0;
|
||||
long v = rz_debug_ptrace(dbg, PTRACE_PEEKUSER, pid, (void *)i, NULL);
|
||||
|
||||
if (errno) {
|
||||
RZ_LOG_DEBUG("reg[%02d] failed errno=%d\n", i, errno);
|
||||
regs[i] = UT64_MAX;
|
||||
continue;
|
||||
}
|
||||
|
||||
regs[i] = (ut64)v;
|
||||
}
|
||||
size = RZ_MIN(sizeof(regs), size);
|
||||
memcpy(buf, ®s, size);
|
||||
return size;
|
||||
} break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int rz_debug_native_reg_write(RzDebug *dbg, int type, const ut8 *buf, int size) {
|
||||
int pid = dbg->pid;
|
||||
switch (type) {
|
||||
case RZ_REG_TYPE_DRX:
|
||||
return false;
|
||||
case RZ_REG_TYPE_GPR:
|
||||
int ret;
|
||||
for (int i = 0; i < ALPHA_PTRACE_REG_COUNT; i++) {
|
||||
ut64 value = rz_read_at_le64(buf, i * 8);
|
||||
ret = rz_debug_ptrace(dbg, PTRACE_POKEUSER, pid, (void *)i, (void *)value);
|
||||
if (ret < 0) {
|
||||
RZ_LOG_ERROR("Writing to register for value : %lx", value);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
RZ_LOG_DEBUG("TODO: reg_write_non-gpr (%d)\n", type);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static RzDebugMap *rz_debug_native_map_alloc(RzDebug *dbg, ut64 addr, int size, bool thp) {
|
||||
return linux_map_alloc(dbg, addr, size, thp);
|
||||
}
|
||||
|
||||
static int rz_debug_native_map_dealloc(RzDebug *dbg, ut64 addr, int size) {
|
||||
return linux_map_dealloc(dbg, addr, size);
|
||||
}
|
||||
|
||||
static RzList /*<RzDebugMap *>*/ *rz_debug_native_map_get(RzDebug *dbg) {
|
||||
if (dbg->pid == -1) {
|
||||
return NULL;
|
||||
}
|
||||
RzList *map_list = linux_map_get(dbg);
|
||||
if (!map_list) {
|
||||
RZ_LOG_ERROR("Cannot create process map list.\n");
|
||||
return NULL;
|
||||
}
|
||||
return map_list;
|
||||
}
|
||||
|
||||
static RzList /*<RzDebugMap *>*/ *rz_debug_native_modules_get(RzDebug *dbg) {
|
||||
char *lastname = NULL;
|
||||
RzDebugMap *map;
|
||||
RzListIter *iter, *iter2;
|
||||
RzList *list, *last;
|
||||
bool must_delete;
|
||||
if (!(list = rz_debug_native_map_get(dbg))) {
|
||||
return NULL;
|
||||
}
|
||||
if (!(last = rz_list_newf((RzListFree)rz_debug_map_free))) {
|
||||
rz_list_free(list);
|
||||
return NULL;
|
||||
}
|
||||
rz_list_foreach_safe (list, iter, iter2, map) {
|
||||
const char *file = map->file;
|
||||
if (!map->file) {
|
||||
file = map->file = rz_str_dup(map->name);
|
||||
}
|
||||
must_delete = true;
|
||||
if (file && *file == '/') {
|
||||
if (!lastname || strcmp(lastname, file)) {
|
||||
must_delete = false;
|
||||
}
|
||||
}
|
||||
if (must_delete) {
|
||||
rz_list_delete(list, iter);
|
||||
} else {
|
||||
rz_list_append(last, map);
|
||||
free(lastname);
|
||||
lastname = rz_str_dup(file);
|
||||
}
|
||||
}
|
||||
list->free = NULL;
|
||||
free(lastname);
|
||||
rz_list_free(list);
|
||||
return last;
|
||||
}
|
||||
|
||||
static bool rz_debug_native_kill(RzDebug *dbg, int pid, int tid, int sig) {
|
||||
bool ret = false;
|
||||
if (pid == 0) {
|
||||
pid = dbg->pid;
|
||||
}
|
||||
if (sig == SIGKILL && dbg->threads) {
|
||||
rz_list_free(dbg->threads);
|
||||
dbg->threads = NULL;
|
||||
}
|
||||
if ((rz_sys_kill(pid, sig) != -1)) {
|
||||
ret = true;
|
||||
}
|
||||
if (errno == 1) {
|
||||
ret = -true; // EPERM
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rz_debug_native_drx(RzDebug *dbg, int n, ut64 addr, int sz, int rwx, int g, int api_type) {
|
||||
RZ_LOG_ERROR("drx: Unsupported platform\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int rz_debug_native_bp(RzBreakpoint *bp, RzBreakpointItem *b, bool set) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static RzList /*<RzDebugDesc *>*/ *rz_debug_desc_native_list(int pid) {
|
||||
return linux_desc_list(pid);
|
||||
}
|
||||
|
||||
static int rz_debug_native_map_protect(RzDebug *dbg, ut64 addr, int size, int perms) {
|
||||
return linux_map_protect(dbg, addr, size, perms);
|
||||
}
|
||||
|
||||
static int rz_debug_desc_native_open(const char *path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool rz_debug_gcore(RzDebug *dbg, char *path, RzBuffer *dest) {
|
||||
RZ_LOG_ERROR("Unsupported on this platform\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct rz_debug_desc_plugin_t rz_debug_desc_plugin_native = {
|
||||
.open = rz_debug_desc_native_open,
|
||||
.list = rz_debug_desc_native_list,
|
||||
};
|
||||
|
||||
bool rz_debug_native_init(RzDebug *dbg, void **user) {
|
||||
dbg->cur->desc = rz_debug_desc_plugin_native;
|
||||
return true;
|
||||
}
|
||||
|
||||
void rz_debug_native_fini(RzDebug *dbg, void *user) {
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
free(user);
|
||||
}
|
||||
|
||||
RzDebugPlugin rz_debug_plugin_native = {
|
||||
.name = "native",
|
||||
.license = "LGPL3",
|
||||
.bits = RZ_SYS_BITS_64,
|
||||
.arch = "alpha",
|
||||
.canstep = 0,
|
||||
.init = &rz_debug_native_init,
|
||||
.fini = &rz_debug_native_fini,
|
||||
.step = &rz_debug_native_step,
|
||||
.cont = &rz_debug_native_continue,
|
||||
.stop = &rz_debug_native_stop,
|
||||
.contsc = &rz_debug_native_continue_syscall,
|
||||
.attach = &rz_debug_native_attach,
|
||||
.detach = &rz_debug_native_detach,
|
||||
.select = &rz_debug_native_select,
|
||||
.pids = &rz_debug_native_pids,
|
||||
.threads = &rz_debug_native_threads,
|
||||
.wait = &rz_debug_native_wait,
|
||||
.kill = &rz_debug_native_kill,
|
||||
.frames = &rz_debug_native_frames, // rename to backtrace ?
|
||||
.reg_profile = rz_debug_native_reg_profile,
|
||||
.reg_read = rz_debug_native_reg_read,
|
||||
.info = rz_debug_native_info,
|
||||
.reg_write = (void *)&rz_debug_native_reg_write,
|
||||
.map_alloc = rz_debug_native_map_alloc,
|
||||
.map_dealloc = rz_debug_native_map_dealloc,
|
||||
.map_get = rz_debug_native_map_get,
|
||||
.modules_get = rz_debug_native_modules_get,
|
||||
.map_protect = rz_debug_native_map_protect,
|
||||
.breakpoint = rz_debug_native_bp,
|
||||
.drx = rz_debug_native_drx,
|
||||
.gcore = rz_debug_gcore,
|
||||
};
|
||||
77
librz/debug/p/native/reg/linux-alpha.h
Normal file
77
librz/debug/p/native/reg/linux-alpha.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// SPDX-FileCopyrightText: 2026 well-mannered-goat
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
return rz_str_dup(
|
||||
"=PC pc\n"
|
||||
"=SP sp\n"
|
||||
"=BP s6\n"
|
||||
"=A0 a0\n"
|
||||
"=A1 a1\n"
|
||||
"=A2 a2\n"
|
||||
"=R0 v0\n"
|
||||
|
||||
"gpr v0 .64 0 0\n"
|
||||
"gpr t0 .64 8 0\n"
|
||||
"gpr t1 .64 16 0\n"
|
||||
"gpr t2 .64 24 0\n"
|
||||
"gpr t3 .64 32 0\n"
|
||||
"gpr t4 .64 40 0\n"
|
||||
"gpr t5 .64 48 0\n"
|
||||
"gpr t6 .64 56 0\n"
|
||||
"gpr t7 .64 64 0\n"
|
||||
"gpr s0 .64 72 0\n"
|
||||
"gpr s1 .64 80 0\n"
|
||||
"gpr s2 .64 88 0\n"
|
||||
"gpr s3 .64 96 0\n"
|
||||
"gpr s4 .64 104 0\n"
|
||||
"gpr s5 .64 112 0\n"
|
||||
"gpr s6 .64 120 0\n"
|
||||
"gpr a0 .64 128 0\n"
|
||||
"gpr a1 .64 136 0\n"
|
||||
"gpr a2 .64 144 0\n"
|
||||
"gpr a3 .64 152 0\n"
|
||||
"gpr a4 .64 160 0\n"
|
||||
"gpr a5 .64 168 0\n"
|
||||
"gpr t8 .64 176 0\n"
|
||||
"gpr t9 .64 184 0\n"
|
||||
"gpr t10 .64 192 0\n"
|
||||
"gpr t11 .64 200 0\n"
|
||||
"gpr ra .64 208 0\n"
|
||||
"gpr t12 .64 216 0\n"
|
||||
"gpr at .64 224 0\n"
|
||||
"gpr gp .64 232 0\n"
|
||||
"gpr sp .64 240 0\n"
|
||||
"gpr zero .64 248 0\n"
|
||||
"fpu f0 .64 256 0\n"
|
||||
"fpu f1 .64 264 0\n"
|
||||
"fpu f2 .64 272 0\n"
|
||||
"fpu f3 .64 280 0\n"
|
||||
"fpu f4 .64 288 0\n"
|
||||
"fpu f5 .64 296 0\n"
|
||||
"fpu f6 .64 304 0\n"
|
||||
"fpu f7 .64 312 0\n"
|
||||
"fpu f8 .64 320 0\n"
|
||||
"fpu f9 .64 328 0\n"
|
||||
"fpu f10 .64 336 0\n"
|
||||
"fpu f11 .64 344 0\n"
|
||||
"fpu f12 .64 352 0\n"
|
||||
"fpu f13 .64 360 0\n"
|
||||
"fpu f14 .64 368 0\n"
|
||||
"fpu f15 .64 376 0\n"
|
||||
"fpu f16 .64 384 0\n"
|
||||
"fpu f17 .64 392 0\n"
|
||||
"fpu f18 .64 400 0\n"
|
||||
"fpu f19 .64 408 0\n"
|
||||
"fpu f20 .64 416 0\n"
|
||||
"fpu f21 .64 424 0\n"
|
||||
"fpu f22 .64 432 0\n"
|
||||
"fpu f23 .64 440 0\n"
|
||||
"fpu f24 .64 448 0\n"
|
||||
"fpu f25 .64 456 0\n"
|
||||
"fpu f26 .64 464 0\n"
|
||||
"fpu f27 .64 472 0\n"
|
||||
"fpu f28 .64 480 0\n"
|
||||
"fpu f29 .64 488 0\n"
|
||||
"fpu f30 .64 496 0\n"
|
||||
"fpu f31 .64 504 0\n"
|
||||
"gpr pc .64 512 0\n"
|
||||
"gpr unique .64 520 0\n");
|
||||
|
|
@ -289,6 +289,10 @@ extern "C" {
|
|||
#else
|
||||
#define RZ_SYS_BITS (RZ_SYS_BITS_32 | RZ_SYS_BITS_64)
|
||||
#endif
|
||||
#elif __alpha__
|
||||
#define RZ_SYS_ARCH "alpha"
|
||||
#define RZ_SYS_BITS RZ_SYS_BITS_64
|
||||
#define RZ_SYS_ENDIAN RZ_SYS_ENDIAN_LITTLE
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_M_X64) || defined(_M_AMD64)
|
||||
|
|
|
|||
Loading…
Reference in a new issue