librz/debug: add NetBSD debug tests and fix errors (#5208)

* Fix netbsd-x86_64 register profile
* Fix native_wait in netbsd.c
* Fix netbsd attach to show error
* Add netbsd-x64 debug tests
This commit is contained in:
well-mannered-goat 2025-06-19 21:52:33 +05:30 committed by GitHub
parent 9f17373515
commit 7117ba75ea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 242 additions and 39 deletions

View file

@ -14,6 +14,8 @@
#define RZ_TEST_OS "darwin"
#elif __WINDOWS__
#define RZ_TEST_OS "windows"
#elif __NetBSD__
#define RZ_TEST_OS "netbsd"
#else
#define RZ_TEST_OS "unknown"
#endif

View file

@ -723,7 +723,6 @@ RZ_API RzDebugReasonType rz_debug_wait(RzDebug *dbg, RzBreakpointItem **bp) {
rz_debug_stop(dbg);
}
#endif
/* propagate errors from the plugin */
if (reason == RZ_DEBUG_REASON_ERROR) {
return RZ_DEBUG_REASON_ERROR;

View file

@ -641,10 +641,8 @@ static int get_rz_status(int stat) {
return RZ_DBG_PROC_DEAD;
}
}
#endif
RzList *bsd_thread_list(RzDebug *dbg, int pid, RzList *list) {
#if __KFBSD__
static RzList *kfbsd_thread_list(RzDebug *dbg, int pid, RzList *list) {
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, pid };
struct kinfo_proc *kp;
size_t len = 0;
@ -666,19 +664,93 @@ RzList *bsd_thread_list(RzDebug *dbg, int pid, RzList *list) {
max = len / sizeof(*kp);
for (i = 0; i < max; i++) {
RzDebugPid *pid_info;
int pid_stat;
int pid_stat = get_rz_status(kp[i].ki_stat);
pid_stat = get_rz_status(kp[i].ki_stat);
pid_info = rz_debug_pid_new(kp[i].ki_comm, kp[i].ki_tid,
RzDebugPid *pid_info = rz_debug_pid_new(kp[i].ki_comm, kp[i].ki_tid,
kp[i].ki_uid, pid_stat, (ut64)kp[i].ki_wchan);
rz_list_append(list, pid_info);
}
free(kp);
return list;
}
#endif
#if __NetBSD__
static int get_rz_status(int stat) {
switch (stat) {
case LSRUN:
case LSONPROC:
case LSIDL:
return RZ_DBG_PROC_RUN;
case LSSTOP:
return RZ_DBG_PROC_STOP;
case LSZOMB:
return RZ_DBG_PROC_ZOMBIE;
case LSSLEEP:
return RZ_DBG_PROC_SLEEP;
case LSSUSPENDED:
return RZ_DBG_PROC_STOP;
default:
return RZ_DBG_PROC_DEAD;
}
}
static RzList *netbsd_thread_list(RzDebug *dbg, int pid, RzList *list) {
int mib[6] = { CTL_KERN, KERN_PROC2, KERN_PROC_PID, pid, sizeof(struct kinfo_proc2), 0 };
struct kinfo_proc2 *kp;
size_t len = 0;
size_t max;
int i = 0;
if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
rz_list_free(list);
return NULL;
}
len += sizeof(*kp) + len / 10;
kp = malloc(len);
if (!kp) {
rz_list_free(list);
return NULL;
}
mib[5] = len / sizeof(struct kinfo_proc2);
if (sysctl(mib, 6, kp, &len, NULL, 0) == -1) {
free(kp);
rz_list_free(list);
return NULL;
}
max = len / sizeof(*kp);
for (i = 0; i < max; i++) {
int pid_stat = get_rz_status(kp[i].p_stat);
RzDebugPid *pid_info = rz_debug_pid_new(kp[i].p_comm, kp[i].p_pid,
kp[i].p_uid, pid_stat, (ut64)kp[i].p_wchan);
if (pid_info) {
rz_list_append(list, pid_info);
}
}
free(kp);
return list;
}
#endif
RzList *bsd_thread_list(RzDebug *dbg, int pid, RzList *list) {
#if __KFBSD__
RzList *thread_list = kfbsd_thread_list(dbg, pid, list);
return thread_list;
#elif __NetBSD__
RzList *thread_list = netbsd_thread_list(dbg, pid, list);
return thread_list;
#else
eprintf("bsd_thread_list unsupported on this platform\n");
RZ_LOG_ERROR("bsd_thread_list unsupported on this platform\n");
rz_list_free(list);
return NULL;
#endif

View file

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2009-2019 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_util/rz_log.h>
#include <errno.h>
#if !defined(__HAIKU__) && !defined(__sun)
#include <sys/ptrace.h>
@ -40,11 +41,35 @@ static bool rz_debug_native_step(RzDebug *dbg) {
return true;
}
int match_pid(const void *pid_o, const void *th_o, void *user) {
int pid = *(int *)pid_o;
RzDebugPid *th = (RzDebugPid *)th_o;
return (pid == th->pid) ? 0 : 1;
}
static RZ_OWN RzList /*<RzDebugPid *>*/ *get_pid_thread_list(RZ_NONNULL RzDebug *dbg, int main_pid) {
rz_return_val_if_fail(dbg, NULL);
RzList *list = rz_list_new();
if (!list) {
RZ_LOG_ERROR("Cannot create thread list\n");
return NULL;
}
list = bsd_thread_list(dbg, main_pid, list);
dbg->main_pid = main_pid;
return list;
}
static int rz_debug_native_attach(RzDebug *dbg, int pid) {
int ret = ptrace(PTRACE_ATTACH, pid, 0, 0);
if (ret != -1) {
eprintf("Trying to attach to %d\n", pid);
perror("ptrace (PT_ATTACH)");
if (!dbg->threads) {
dbg->threads = get_pid_thread_list(dbg, pid);
return pid;
}
if (!rz_list_find(dbg->threads, &pid, &match_pid, NULL)) {
int ret = ptrace(PTRACE_ATTACH, pid, 0, 0);
if (ret == -1) {
RZ_LOG_ERROR("Trying to attach to %d\n", pid);
perror("ptrace (PT_ATTACH)");
}
}
return pid;
}
@ -77,17 +102,14 @@ static RzDebugReasonType rz_debug_native_wait(RzDebug *dbg, int pid) {
RzDebugReasonType reason = RZ_DEBUG_REASON_UNKNOWN;
if (pid == -1) {
eprintf("ERROR: rz_debug_native_wait called with pid -1\n");
RZ_LOG_ERROR("rz_debug_native_wait called with pid -1\n");
return RZ_DEBUG_REASON_ERROR;
}
int status = -1;
#ifdef WAIT_ON_ALL_CHILDREN
int ret = waitpid(-1, &status, WAITPID_FLAGS);
#else
int ret = waitpid(-1, &status, 0);
if (ret != -1) {
reason = RZ_DEBUG_REASON_TRAP;
}
#else
int ret = waitpid(pid, &status, 0);
#endif
if (ret == -1) {
rz_sys_perror("waitpid");
@ -101,17 +123,16 @@ static RzDebugReasonType rz_debug_native_wait(RzDebug *dbg, int pid) {
/* we don't know what to do yet, let's try harder to figure it out. */
if (reason == RZ_DEBUG_REASON_UNKNOWN) {
if (WIFEXITED(status)) {
eprintf("child exited with status %d\n", WEXITSTATUS(status));
if (dbg->pid == pid) {
RZ_LOG_WARN("(%d) Process exited with status=0x%x\n", pid, WEXITSTATUS(status));
} else {
RZ_LOG_WARN("(%d) Thread exited with status=0x%x\n", pid, WEXITSTATUS(status));
}
reason = RZ_DEBUG_REASON_DEAD;
} else if (WIFSIGNALED(status)) {
eprintf("child received signal %d\n", WTERMSIG(status));
reason = RZ_DEBUG_REASON_SIGNAL;
} else if (WIFSTOPPED(status)) {
if (WSTOPSIG(status) != SIGTRAP &&
WSTOPSIG(status) != SIGSTOP) {
eprintf("Child stopped with signal %d\n", WSTOPSIG(status));
}
/* the ptrace documentation says GETSIGINFO is only necessary for
* differentiating the various stops.
*

View file

@ -11,7 +11,6 @@ return rz_str_dup(
"=A3 rcx\n"
"=A4 r8\n"
"=A5 r9\n"
"# no profile defined for x86-64\n"
"gpr rdi .64 0 0\n"
"gpr edi .32 0 0\n"
"gpr di .16 0 0\n"
@ -72,21 +71,23 @@ return rz_str_dup(
"gpr eax .32 112 0\n"
"gpr ax .16 112 0\n"
"gpr al .8 112 0\n"
"gpr rsp .64 120 0\n"
"gpr esp .32 120 0\n"
"gpr sp .16 120 0\n"
"gpr spl .8 120 0\n"
"gpr rip .64 128 0\n"
"gpr rflags .64 136 0 c1p.a.zstido.n.rv\n"
"seg cs .64 144 0\n"
"seg ss .64 152 0\n"
"seg ds .64 160 0\n"
"seg es .64 168 0\n"
"seg fs .64 176 0\n"
"seg gs .64 184 0\n"
"seg gs .64 120 0\n"
"seg fs .64 128 0\n"
"seg es .64 136 0\n"
"seg ds .64 144 0\n"
"gpr trapno .64 152 0\n"
"gpr err .64 160 0\n"
"gpr rip .64 168 0\n"
"seg cs .64 176 0\n"
"gpr rflags .64 184 0 c1p.a.zstido.n.rv\n"
"gpr rsp .64 192 0\n"
"gpr esp .32 192 0\n"
"gpr sp .16 192 0\n"
"gpr spl .8 192 0\n"
"seg ss .64 200 0\n"
"drx dr0 .32 0 0\n"
"drx dr1 .32 4 0\n"
"drx dr2 .32 8 0\n"
"drx dr3 .32 12 0\n"
"drx dr6 .32 24 0\n"
"drx dr7 .32 28 0\n");
"drx dr7 .32 28 0\n");

View file

@ -0,0 +1,108 @@
NAME=dcu + read
FILE=bins/elf/netbsd-hello-x64
ARGS=-d
CMDS=<<EOF
dcu main
pi 5
dc
EOF
EXPECT=<<EOF
push rbp
mov rbp, rsp
mov edi, str.Hello_World
call sym.imp.puts
mov eax, 0x00
Hello World
EOF
RUN
NAME=maps
FILE=bins/elf/netbsd-hello-x64
ARGS=-d
CMDS=<<EOF
dm~hello~[3-9]
dc
EOF
EXPECT=<<EOF
- usr 4K s r-x 1581273 /home/build/rizin-testbins/elf/netbsd-hello-x64
Hello World
EOF
RUN
NAME=step and check pc
FILE=bins/elf/netbsd-calculate-x64
ARGS=-d
CMDS=<<EOF
dcu main
5 ds
dr rip
ds
dr rip
dc
EOF
EXPECT=<<EOF
rip = 0x0000000000400984
rip = 0x0000000000400988
Result = 42
EOF
RUN
NAME=write gpr
FILE=bins/elf/netbsd-calculate-x64
ARGS=-d
CMDS=<<EOF
db @ main + 64
dc
dr rax
dr rax = 1337
dr rax
dc
EOF
EXPECT=<<EOF
rax = 0x0000000000000028
rax = 0x0000000000000539
Result = 1339
EOF
RUN
NAME=Signal handling
FILE=bins/elf/netbsd-calculate-x64
ARGS=-d
CMDS=<<EOF
dkl~SIGTERM
dko 15 skip
dkl~SIGTERM
dko 15 reset
dkl~SIGTERM
dk 15
dc
EOF
EXPECT=<<EOF
15 SIGTERM
15 SIGTERM skip
15 SIGTERM
[+] signal 15 aka SIGTERM received 0
EOF
RUN
NAME=Step and Step over
FILE=bins/elf/netbsd_basic_test-x64
ARGS=-d
CMDS=<<EOF
db @ main + 73
dc
ds 3
dr rax
dr rdx
dso
dr rax
dr rdx
dc
EOF
EXPECT=<<EOF
rax = 0x0000000000000034
rdx = 0x00000000000000c8
rax = 0x00000000000000fc
rdx = 0x0000000000000034
EOF
RUN