14 #include "../procfs.h"
16 #include <sys/syscall.h>
28 #if (__i386__ || __x86_64__) && defined(PTRACE_GETREGSET) && defined(NT_X86_XSTATE)
60 #elif __arm64__ || __aarch64__
68 #elif (__i386__ || __x86_64__)
87 #error "Unsupported Linux CPU"
104 siginfo_t siginfo = { 0 };
105 int ret = rz_debug_ptrace(
dbg, PTRACE_GETSIGINFO, tid, 0, (rz_ptrace_data_t)(
size_t)&siginfo);
108 if (errno ==
ESRCH) {
116 if (siginfo.si_signo > 0) {
130 if (
b &&
b->internal) {
131 char *
p = strstr(
b->data,
"dbg.");
135 if (strstr(
b->data,
"sym.imp.dlopen")) {
181 " code=%d si_pid=%d ret=%d\n",
182 siginfo.si_signo, siginfo.si_errno,
183 (
ut64)(
size_t)siginfo.si_addr, siginfo.si_code, siginfo.si_pid, ret);
191 #undef PT_GETEVENTMSG
192 #define PT_GETEVENTMSG
228 #ifdef PT_GETEVENTMSG
241 #if __powerpc64__ || __arm64__ || __aarch64__ || __x86_64__
247 if (!WIFSTOPPED(
status) || WSTOPSIG(
status) != SIGTRAP) {
256 case PTRACE_EVENT_CLONE:
258 if (rz_debug_ptrace(
dbg, PTRACE_GETEVENTMSG, ptid, 0, (rz_ptrace_data_t)(
size_t)&data) == -1) {
265 if (waitpid((
int)data, &
status, 0) == -1) {
274 eprintf(
"(%d) Created thread %d\n", ptid, (
int)data);
276 case PTRACE_EVENT_VFORK:
277 case PTRACE_EVENT_FORK:
279 if (rz_debug_ptrace(
dbg, PTRACE_GETEVENTMSG, ptid, 0, (rz_ptrace_data_t)(
size_t)&data) == -1) {
291 eprintf(
"(%d) Created process %d\n", ptid, (
int)data);
297 perror(
"PTRACE_DETACH");
301 case PTRACE_EVENT_EXIT:
303 if (rz_debug_ptrace(
dbg, PTRACE_GETEVENTMSG, ptid, 0, (rz_ptrace_data_t)(
size_t)&data) == -1) {
316 eprintf(
"Unknown PTRACE_EVENT encountered: %d\n", pt_evt);
337 if (th->
pid == tid) {
341 siginfo_t siginfo = { 0 };
342 ret = rz_debug_ptrace(
dbg, PTRACE_GETSIGINFO, th->
pid, 0, (rz_ptrace_data_t)(
size_t)&siginfo);
347 #ifdef PT_GETEVENTMSG
349 if (siginfo.si_signo == SIGTRAP) {
351 int pt_evt = siginfo.si_code >> 8;
354 case PTRACE_EVENT_CLONE:
355 case PTRACE_EVENT_VFORK:
356 case PTRACE_EVENT_FORK:
375 perror(
"native-singlestep");
385 traceflags |= PTRACE_O_TRACEFORK;
386 traceflags |= PTRACE_O_TRACEVFORK;
387 traceflags |= PTRACE_O_TRACECLONE;
389 traceflags |= PTRACE_O_TRACEVFORKDONE;
392 traceflags |= PTRACE_O_TRACEEXEC;
395 traceflags |= PTRACE_O_TRACEEXIT;
398 traceflags |= PTRACE_O_TRACESYSGOOD;
402 while (rz_debug_ptrace(
dbg, PTRACE_SETOPTIONS,
pid, 0, (rz_ptrace_data_t)(
size_t)traceflags) == -1) {
415 rz_list_foreach (th_list, it, th) {
418 perror(
"PTRACE_DETACH");
426 perror(
"PTRACE_DETACH");
435 if (th->
pid == tid) {
489 if (dpgid != tpgid) {
532 if (errno ==
EINTR) {
537 }
else if (ret == 0) {
554 eprintf(
"(%d) Process terminated with status %d\n", tid, WEXITSTATUS(
status));
557 eprintf(
"(%d) Child terminated with status %d\n", tid, WEXITSTATUS(
status));
561 }
else if (WIFSIGNALED(
status)) {
564 }
else if (WIFSTOPPED(
status)) {
568 WSTOPSIG(
status) == SIGSTOP) {
578 eprintf(
"can't handle signals\n");
582 }
else if (WIFCONTINUED(
status)) {
583 eprintf(
"child continued...\n");
587 eprintf(
"debugger is dead with status 1\n");
590 eprintf(
"debugger is dead with status 0\n");
596 eprintf(
"returning from wait without knowing why...\n");
609 int pid = *(
int *)pid_o;
611 return (
pid == th->
pid) ? 0 : 1;
616 char info[1024] = { 0 };
642 siginfo_t siginfo = { 0 };
645 ret = rz_debug_ptrace(
dbg, PTRACE_GETSIGINFO, tid, 0,
646 (rz_ptrace_data_t)(
intptr_t)&siginfo);
652 if ((ret = waitpid(tid, &
status, 0)) == -1) {
666 if (th->
pid && th->
pid != except) {
677 siginfo_t sig = { 0 };
687 if (rz_debug_ptrace(
dbg, PTRACE_GETSIGINFO, ptid,
NULL,
688 (rz_ptrace_data_t)&sig) == -1) {
690 perror(
"ptrace (PT_ATTACH)");
697 eprintf(
"Could not stop pid (%d)\n", ptid);
703 eprintf(
"failed set_options on %d\n", ptid);
733 char path[1024] = { 0 };
734 char buf[1024] = { 0 };
739 buf[
sizeof(
buf) - 1] =
'\0';
746 char proc_buff[1024];
753 bool list_alloc =
false;
766 rz_list_foreach (th_list, it, th) {
778 snprintf(proc_buff,
sizeof(proc_buff),
"/proc/%d/cmdline",
rdi->pid);
780 snprintf(proc_buff,
sizeof(proc_buff),
"/proc/%d/stack",
rdi->pid);
794 char *ptr = strstr(
info,
"State:");
796 switch (*(ptr + 7)) {
818 ptr = strstr(
info,
"PPid:");
820 pid_info->
ppid = atoi(ptr + 5);
822 ptr = strstr(
info,
"Uid:");
824 pid_info->
uid = atoi(ptr + 5);
826 ptr = strstr(
info,
"Gid:");
828 pid_info->
gid = atoi(ptr + 5);
842 char path[PATH_MAX],
info[PATH_MAX];
845 dh = opendir(
"/proc");
855 if ((
i = atoi(de->
d_name)) <= 0) {
877 char *ptr,
buf[PATH_MAX];
892 DIR *dh = opendir(
buf);
896 if (!strcmp(de->
d_name,
".") || !strcmp(de->
d_name,
"..")) {
899 int tid = atoi(de->
d_name);
903 ptr = strstr(
info,
"Uid:");
907 ptr = strstr(
info,
"Tgid:");
909 int tgid = atoi(ptr + 5);
952 ptr = strstr(
buf,
"Uid:");
956 ptr = strstr(
buf,
"Tgid:");
958 int tgid = atoi(ptr + 5);
976 #define PRINT_FPU(fpregs) \
977 rz_cons_printf("cwd = 0x%04x ; control ", (fpregs).cwd); \
978 rz_cons_printf("swd = 0x%04x ; status\n", (fpregs).swd); \
979 rz_cons_printf("ftw = 0x%04x ", (fpregs).ftw); \
980 rz_cons_printf("fop = 0x%04x\n", (fpregs).fop); \
981 rz_cons_printf("rip = 0x%016" PFMT64x " ", (ut64)(fpregs).rip); \
982 rz_cons_printf("rdp = 0x%016" PFMT64x "\n", (ut64)(fpregs).rdp); \
983 rz_cons_printf("mxcsr = 0x%08x ", (fpregs).mxcsr); \
984 rz_cons_printf("mxcr_mask = 0x%08x\n", (fpregs).mxcr_mask)
986 #define PRINT_FPU_NOXMM(fpregs) \
987 rz_cons_printf("cwd = 0x%04lx ; control ", (fpregs).cwd); \
988 rz_cons_printf("swd = 0x%04lx ; status\n", (fpregs).swd); \
989 rz_cons_printf("twd = 0x%04lx ", (fpregs).twd); \
990 rz_cons_printf("fip = 0x%04lx \n", (fpregs).fip); \
991 rz_cons_printf("fcs = 0x%04lx ", (fpregs).fcs); \
992 rz_cons_printf("foo = 0x%04lx \n", (fpregs).foo); \
993 rz_cons_printf("fos = 0x%04lx ", (fpregs).fos)
998 struct user_fpregs_struct fpregs = *(
struct user_fpregs_struct *)
f;
1001 for (
i = 0;
i < 8;
i++) {
1004 float *
f = (
float *)&fpregs.st_space;
1010 (
double)*((
double *)&fpregs.st_space[
i * 4]), *
b, (
float)
f[0],
1011 c[0], (
float)
f[1],
c[1]);
1017 for (
i = 0;
i < 16;
i++) {
1021 (
int)
a[2], (
int)
a[3]);
1023 ut64 *st_u64 = (
ut64 *)&fpregs.st_space[
i * 4];
1024 ut8 *st_u8 = (
ut8 *)&fpregs.st_space[
i * 4];
1025 long double *st_ld = (
long double *)&fpregs.st_space[
i * 4];
1028 for (j = 9; j >= 0; j--) {
1042 struct user_fpxregs_struct fpxregs = *(
struct user_fpxregs_struct *)
f;
1053 for (
i = 0;
i < 8;
i++) {
1055 ut64 *
b = (
ut64 *)(&fpxregs.st_space[
i * 4]);
1057 float *
f = (
float *)&fpxregs.st_space;
1062 (
int)
a[1], (
int)
a[2], (
int)
a[3]);
1066 (
double)*((
double *)(&fpxregs.st_space[
i * 4])),
b[0],
1067 f[0],
c[0],
f[1],
c[1]);
1070 struct user_fpregs_struct fpregs = *(
struct user_fpregs_struct *)
f;
1073 for (
i = 0;
i < 8;
i++) {
1075 double *
d = (
double *)
b;
1077 float *
f = (
float *)&fpregs.st_space;
1082 i,
d[0],
b[0],
f[0],
c[0],
f[1],
c[1]);
1086 #warning print_fpu not implemented for this platform
1091 bool showfpu =
false;
1103 #elif __i386__ || __x86_64__
1107 for (
i = 0;
i < 8;
i++) {
1108 if (
i == 4 ||
i == 5) {
1113 if ((
i + 1) *
sizeof(ret) >
size) {
1114 eprintf(
"linux_reg_get: Buffer too small %d\n",
size);
1117 memcpy(
buf + (
i *
sizeof(ret)), &ret,
sizeof(ret));
1120 return sizeof(
a.u_debugreg);
1123 #warning Android X86 does not support DRX
1133 #elif __x86_64__ || __i386__
1135 struct user_fpregs_struct fpregs;
1151 struct user_fpxregs_struct fpxregs;
1190 #warning getfpregs not implemented for this platform
1199 #if (__arm64__ || __aarch64__ || __s390x__) && defined(PTRACE_GETREGSET)
1202 .iov_len =
sizeof(
regs)
1204 ret = rz_debug_ptrace(
dbg, PTRACE_GETREGSET,
pid, 1, &io);
1210 #elif __BSD__ && (__POWERPC__ || __sparc__)
1231 #if HAVE_YMM && __x86_64__ && defined(PTRACE_GETREGSET)
1232 ut32 ymm_space[128];
1233 struct _xstate xstate;
1235 iov.iov_base = &xstate;
1236 iov.iov_len =
sizeof(
struct _xstate);
1243 for (ri = 0; ri < 16; ri++) {
1244 for (rj = 0; rj < 4; rj++) {
1246 ymm_space[ri * 8 + rj] = ((
struct _libc_fpstate *)&xstate.fpstate)->_xmm[ri].element[rj];
1248 ymm_space[ri * 8 + rj] = xstate.fpstate._xmm[ri].element[rj];
1251 for (rj = 0; rj < 4; rj++) {
1252 ymm_space[ri * 8 + (rj + 4)] = xstate.ymmh.ymmh_space[ri * 4 + rj];
1269 #if !__ANDROID__ && (__i386__ || __x86_64__)
1272 for (
i = 0;
i < 8;
i++) {
1273 if (
i == 4 ||
i == 5) {
1277 (
void *)
rz_offsetof(
struct user, u_debugreg[
i]), (rz_ptrace_data_t)
val[
i])) {
1278 eprintf(
"ptrace error for dr %d\n",
i);
1288 #if __arm64__ || __aarch64__ || __s390x__
1290 .iov_base = (
void *)
buf,
1293 int ret = rz_debug_ptrace(
dbg, PTRACE_SETREGSET,
pid, (
void *)(
size_t)
NT_PRSTATUS, (rz_ptrace_data_t)(
size_t)&io);
1294 #elif __POWERPC__ || __sparc__
1311 #if __i386__ || __x86_64__
1313 return (ret != 0) ?
false :
true;
1330 if (!(
dd = opendir(
path))) {
1340 if (de->
d_name[0] ==
'.') {
1344 len2 = strlen(de->
d_name);
1345 if (
len + len2 + 1 >=
sizeof(
file)) {
1356 buf[
sizeof(
buf) - 1] = 0;
1359 type = st.st_mode & S_IFIFO ?
'P' :
1361 st.st_mode & S_IFSOCK ?
'S'
1364 st.st_mode & S_IFCHR ?
'C'
1367 if (lstat(
path, &st) != -1) {
1368 if (st.st_mode & S_IRUSR) {
1371 if (st.st_mode & S_IWUSR) {
RzBinInfo * info(RzBinFile *bf)
RZ_API RZ_BORROW RzBreakpointItem * rz_bp_get_ending_at(RZ_NONNULL RzBreakpoint *bp, ut64 addr)
Get the breakpoint b that fulfills b->addr + b-> size == addr After hitting a (usually software) brea...
RZ_API int rz_bp_get_index_at(RzBreakpoint *bp, ut64 addr)
RZ_API int rz_bp_restore(RzBreakpoint *bp, bool set)
RZ_API void * rz_cons_sleep_begin(void)
RZ_API void rz_cons_break_pop(void)
RZ_API void rz_cons_break_push(RzConsBreak cb, void *user)
RZ_API int rz_cons_printf(const char *format,...)
RZ_API bool rz_cons_is_breaked(void)
RZ_API void rz_cons_sleep_end(void *user)
RZ_API bool rz_cons_context_is_main(void)
static static fork const void static count static fd const char const char static newpath const char static path const char path
static static sync static getppid static getegid const char static filename char static len readlink
RZ_API RzDebugDesc * rz_debug_desc_new(int fd, char *path, int perm, int type, int off)
RZ_API void rz_debug_desc_free(RzDebugDesc *p)
RZ_API bool rz_debug_map_sync(RzDebug *dbg)
RZ_API ut64 rz_debug_reg_get(RzDebug *dbg, const char *name)
RZ_API int rz_debug_reg_sync(RzDebug *dbg, int type, int write)
RZ_API const KEY_TYPE bool * found
return memset(p, 0, total)
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
RZ_API int rz_debug_drx_unset(RzDebug *dbg, int idx)
RZ_API void rz_debug_bp_update(RzDebug *dbg)
RZ_API bool rz_debug_select(RzDebug *dbg, int pid, int tid)
static void list(RzEgg *egg)
RZ_API RZ_BORROW RzListIter * rz_list_find(RZ_NONNULL const RzList *list, const void *p, RZ_NONNULL RzListComparator cmp)
Returns RzListIter element which matches via the RzListComparator.
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
RZ_API void rz_list_delete(RZ_NONNULL RzList *list, RZ_NONNULL RzListIter *iter)
Removes an entry in the list by using the RzListIter pointer.
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc pid
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
static const char struct stat static buf struct stat static buf static vhangup int struct rusage static rusage struct sysinfo static info unsigned static __unused struct utsname static buf const char static size const char static name getpgid
static static fork const void static count static fd const char static mode const char static pathname const char static path const char static dev const char static group static getpid static getuid void void static data static pause const char static mode static sync const char const char static newpath const char static pathname unsigned long static filedes void static end_data_segment static handler static getegid char static len static pgid const char static path static newfd static getpgrp static euid const sigset_t static mask const char static len const gid_t static list const char const char static newpath const char static library readdir
static const char struct stat static buf struct stat static buf static vhangup int status
char * linux_reg_profile(RzDebug *dbg)
int linux_handle_signals(RzDebug *dbg, int tid)
int linux_attach(RzDebug *dbg, int pid)
RzDebugPid * fill_pid_info(const char *info, const char *path, int tid)
static bool linux_kill_thread(int tid, int signo)
long rz_debug_ptrace_get_x86_xstate(RzDebug *dbg, pid_t pid, struct iovec *iov)
static void linux_remove_fork_bps(RzDebug *dbg)
RzList * linux_pid_list(int pid, RzList *list)
static void linux_dbg_wait_break(RzDebug *dbg)
static bool linux_stop_thread(RzDebug *dbg, int tid)
int match_pid(const void *pid_o, const void *th_o)
#define PRINT_FPU(fpregs)
bool linux_attach_new_process(RzDebug *dbg, int pid)
bool linux_stop_threads(RzDebug *dbg, int except)
int linux_reg_read(RzDebug *dbg, int type, ut8 *buf, int size)
static char * read_link(int pid, const char *file)
static void linux_dbg_wait_break_main(RzDebug *dbg)
RzDebugReasonType linux_dbg_wait(RzDebug *dbg, int pid)
#define PRINT_FPU_NOXMM(fpregs)
static RzList * get_pid_thread_list(RzDebug *dbg, int main_pid)
static void linux_detach_all(RzDebug *dbg)
RzList * linux_thread_list(RzDebug *dbg, int pid, RzList *list)
bool linux_set_options(RzDebug *dbg, int pid)
RzList * linux_desc_list(int pid)
static bool linux_attach_single_pid(RzDebug *dbg, int ptid)
static void print_fpu(void *f)
RzDebugInfo * linux_info(RzDebug *dbg, const char *arg)
static RzDebugReasonType linux_handle_new_task(RzDebug *dbg, int tid)
static void linux_remove_thread(RzDebug *dbg, int pid)
int linux_step(RzDebug *dbg)
int linux_reg_write(RzDebug *dbg, int type, const ut8 *buf, int size)
bool linux_select(RzDebug *dbg, int pid, int tid)
static void linux_add_new_thread(RzDebug *dbg, int tid)
RzDebugReasonType linux_ptrace_event(RzDebug *dbg, int pid, int status, bool dowait)
RZ_API RzDebugPid * rz_debug_pid_free(RzDebugPid *pid)
RZ_API RzDebugPid * rz_debug_pid_new(const char *path, int pid, int uid, char status, ut64 pc)
int procfs_pid_slurp(int pid, char *prop, char *out, size_t len)
RZ_API const char * rz_reg_get_name(RzReg *reg, int role)
@ RZ_DEBUG_REASON_NEW_TID
@ RZ_DEBUG_REASON_UNKNOWN
@ RZ_DEBUG_REASON_BREAKPOINT
@ RZ_DEBUG_REASON_USERSUSP
@ RZ_DEBUG_REASON_NEW_LIB
@ RZ_DEBUG_REASON_EXIT_LIB
@ RZ_DEBUG_REASON_SEGFAULT
@ RZ_DEBUG_REASON_NEW_PID
@ RZ_DEBUG_REASON_EXIT_PID
@ RZ_DEBUG_REASON_EXIT_TID
RZ_API bool rz_file_is_directory(const char *str)
RZ_API RZ_OWN char * rz_file_slurp(const char *str, RZ_NULLABLE size_t *usz)
void(* RzListFree)(void *ptr)
#define RZ_LOG_ERROR(fmtstr,...)
RZ_API char * rz_str_appendf(char *ptr, const char *fmt,...) RZ_PRINTF_CHECK(2
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case sensitive)
#define rz_strf(buf,...)
Convenience macro for local temporary strings.
#define rz_offsetof(type, member)
static struct sockaddr static addrlen static backlog const void static flags void flags
bool continue_all_threads
bool nt_x86_xstate_supported
Track whether X86_FEATURE_XSAVE feature is supported on current kernel.
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static const z80_opcode dd[]