Rizin
unix-like reverse engineering framework and cli tools
linux_debug.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2009-2019 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_userconf.h>
5 
6 #include <rz_debug.h>
7 #include <rz_reg.h>
8 #include <rz_lib.h>
9 #include <rz_analysis.h>
10 #include <signal.h>
11 #include <sys/uio.h>
12 #include <errno.h>
13 #include "linux_debug.h"
14 #include "../procfs.h"
15 
16 #include <sys/syscall.h>
17 #include <unistd.h>
18 #include <elf.h>
19 
20 #include "linux_ptrace.h"
21 
22 #ifdef __GLIBC__
23 #define HAVE_YMM 1
24 #else
25 #define HAVE_YMM 0
26 #endif
27 
28 #if (__i386__ || __x86_64__) && defined(PTRACE_GETREGSET) && defined(NT_X86_XSTATE)
31  return -1;
32  }
33 
34  long res = rz_debug_ptrace(dbg, PTRACE_GETREGSET, pid, (void *)NT_X86_XSTATE, iov);
35  if (res == -1) {
36  if (errno == ENODEV) {
37  // Ignore ENODEV error because it means the kernel does not support
38  // NT_X86_XSTATE.
40  rz_sys_perror("PTRACE_GETREGSET/NT_X86_XSTATE");
41  return -1;
42  }
43 
44  rz_sys_perror("rz_debug_ptrace_get_x86_xstate");
45  return -1;
46  }
47  return res;
48 }
49 #else
51  return -1;
52 }
53 #endif
54 
56 #if __arm__
57 #include "reg/linux-arm.h"
58 #elif __riscv
59 #include "reg/linux-riscv64.h"
60 #elif __arm64__ || __aarch64__
61 #include "reg/linux-arm64.h"
62 #elif __mips__
63  if ((dbg->bits & RZ_SYS_BITS_32) && (dbg->bp->endian == 1)) {
64 #include "reg/linux-mips.h"
65  } else {
66 #include "reg/linux-mips64.h"
67  }
68 #elif (__i386__ || __x86_64__)
69  if (dbg->bits & RZ_SYS_BITS_32) {
70 #if __x86_64__
71 #include "reg/linux-x64-32.h"
72 #else
73 #include "reg/linux-x86.h"
74 #endif
75  } else {
76 #include "reg/linux-x64.h"
77  }
78 #elif __powerpc__
79  if (dbg->bits & RZ_SYS_BITS_32) {
80 #include "reg/linux-ppc.h"
81  } else {
82 #include "reg/linux-ppc64.h"
83  }
84 #elif __s390x__
85 #include "reg/linux-s390x.h"
86 #else
87 #error "Unsupported Linux CPU"
88  return NULL;
89 #endif
90 }
91 
92 static void linux_detach_all(RzDebug *dbg);
93 static char *read_link(int pid, const char *file);
94 static bool linux_attach_single_pid(RzDebug *dbg, int ptid);
95 static void linux_remove_thread(RzDebug *dbg, int pid);
96 static void linux_add_new_thread(RzDebug *dbg, int tid);
97 static bool linux_stop_thread(RzDebug *dbg, int tid);
98 static bool linux_kill_thread(int tid, int signo);
100 static void linux_dbg_wait_break(RzDebug *dbg);
102 
104  siginfo_t siginfo = { 0 };
105  int ret = rz_debug_ptrace(dbg, PTRACE_GETSIGINFO, tid, 0, (rz_ptrace_data_t)(size_t)&siginfo);
106  if (ret == -1) {
107  /* ESRCH means the process already went away :-/ */
108  if (errno == ESRCH) {
110  return true;
111  }
112  rz_sys_perror("ptrace GETSIGINFO");
113  return false;
114  }
115 
116  if (siginfo.si_signo > 0) {
117  // siginfo_t newsiginfo = {0};
118  // ptrace (PTRACE_SETSIGINFO, dbg->pid, 0, &siginfo);
120  dbg->reason.signum = siginfo.si_signo;
121  dbg->stopaddr = (ut64)(size_t)siginfo.si_addr;
122  // dbg->errno = siginfo.si_errno;
123  // siginfo.si_code -> HWBKPT, USER, KERNEL or WHAT
124  // TODO: DO MORE RDEBUGREASON HERE
125  switch (dbg->reason.signum) {
126  case SIGTRAP: {
127  if (dbg->glob_libs || dbg->glob_unlibs) {
128  ut64 pc_addr = rz_debug_reg_get(dbg, "PC");
130  if (b && b->internal) {
131  char *p = strstr(b->data, "dbg.");
132  if (p) {
133  if (rz_str_startswith(p, "dbg.libs")) {
134  const char *name;
135  if (strstr(b->data, "sym.imp.dlopen")) {
137  } else {
139  }
140  b->data = rz_str_appendf(b->data, ";ps@r:%s", name);
142  break;
143  } else if (rz_str_startswith(p, "dbg.unlibs")) {
145  break;
146  }
147  }
148  }
149  }
152  if (siginfo.si_code == TRAP_TRACE) {
154  } else {
155  dbg->reason.bp_addr = (ut64)(size_t)siginfo.si_addr;
157  // Switch to the thread that hit the breakpoint
158  rz_debug_select(dbg, dbg->pid, tid);
159  dbg->tid = tid;
160  }
161  }
162  } break;
163  case SIGINT:
165  break;
166  case SIGABRT: // 6 / SIGIOT // SIGABRT
168  break;
169  case SIGSEGV:
171  break;
172  case SIGCHLD:
174  break;
175  default:
176  break;
177  }
178  if (dbg->reason.signum != SIGTRAP &&
179  (dbg->reason.signum != SIGINT || !rz_cons_is_breaked())) {
180  eprintf("[+] SIGNAL %d errno=%d addr=0x%08" PFMT64x
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);
184  }
185  return true;
186  }
187  return false;
188 }
189 
190 #if __ANDROID__
191 #undef PT_GETEVENTMSG
192 #define PT_GETEVENTMSG
193 #endif
194 
195 // Used to remove breakpoints before detaching from a fork, without it the child
196 // will die upon hitting a breakpoint while not being traced
198  RzListIter *iter;
200  int prev_pid = dbg->pid;
201  int prev_tid = dbg->tid;
202 
203  // Set dbg tid to the new child temporarily
204  dbg->pid = dbg->forked_pid;
205  dbg->tid = dbg->forked_pid;
207 
208  // Unset all hw breakpoints in the child process
210  rz_list_foreach (dbg->bp->bps, iter, b) {
212  }
214 
215  // Unset software breakpoints in the child process
217  rz_bp_restore(dbg->bp, false);
218 
219  // Return to the parent
220  dbg->pid = prev_pid;
221  dbg->tid = prev_tid;
223 
224  // Restore sw breakpoints in the parent
225  rz_bp_restore(dbg->bp, true);
226 }
227 
228 #ifdef PT_GETEVENTMSG
229 /*
230  * @brief Handle PTRACE_EVENT_* when receiving SIGTRAP
231  *
232  * @param dowait Do waitpid to consume any signal in the newly created task
233  * @return RzDebugReasonType,
234  * - RZ_DEBUG_REASON_UNKNOWN if the ptrace_event cannot be handled,
235  * - RZ_DEBUG_REASON_ERROR if a ptrace command failed.
236  *
237  * NOTE: This API was added in Linux 2.5.46
238  */
239 RzDebugReasonType linux_ptrace_event(RzDebug *dbg, int ptid, int status, bool dowait) {
240  ut32 pt_evt;
241 #if __powerpc64__ || __arm64__ || __aarch64__ || __x86_64__
242  ut64 data;
243 #else
244  ut32 data;
245 #endif
246  /* we only handle stops with SIGTRAP here */
247  if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) {
249  }
250 
251  pt_evt = status >> 16;
252  switch (pt_evt) {
253  case 0:
254  /* NOTE: this case is handled by linux_handle_signals */
255  break;
256  case PTRACE_EVENT_CLONE:
257  // Get the tid of the new thread
258  if (rz_debug_ptrace(dbg, PTRACE_GETEVENTMSG, ptid, 0, (rz_ptrace_data_t)(size_t)&data) == -1) {
259  rz_sys_perror("ptrace GETEVENTMSG");
260  return RZ_DEBUG_REASON_ERROR;
261  }
262  if (dowait) {
263  // The new child has a pending SIGSTOP. We can't affect it until it
264  // hits the SIGSTOP, but we're already attached. */
265  if (waitpid((int)data, &status, 0) == -1) {
266  perror("waitpid");
267  }
268  }
269 
270  linux_add_new_thread(dbg, (int)data);
271  if (dbg->trace_clone) {
272  rz_debug_select(dbg, dbg->pid, (int)data);
273  }
274  eprintf("(%d) Created thread %d\n", ptid, (int)data);
276  case PTRACE_EVENT_VFORK:
277  case PTRACE_EVENT_FORK:
278  // Get the pid of the new process
279  if (rz_debug_ptrace(dbg, PTRACE_GETEVENTMSG, ptid, 0, (rz_ptrace_data_t)(size_t)&data) == -1) {
280  rz_sys_perror("ptrace GETEVENTMSG");
281  return RZ_DEBUG_REASON_ERROR;
282  }
283  dbg->forked_pid = data;
284  if (dowait) {
285  // The new child has a pending SIGSTOP. We can't affect it until it
286  // hits the SIGSTOP, but we're already attached. */
287  if (waitpid(dbg->forked_pid, &status, 0) == -1) {
288  perror("waitpid");
289  }
290  }
291  eprintf("(%d) Created process %d\n", ptid, (int)data);
292  if (!dbg->trace_forks) {
293  // We need to do this even if the new process will be detached since the
294  // breakpoints are inherited from the parent
296  if (rz_debug_ptrace(dbg, PTRACE_DETACH, dbg->forked_pid, NULL, (rz_ptrace_data_t)(size_t)NULL) == -1) {
297  perror("PTRACE_DETACH");
298  }
299  }
301  case PTRACE_EVENT_EXIT:
302  // Get the exit status of the exiting task
303  if (rz_debug_ptrace(dbg, PTRACE_GETEVENTMSG, ptid, 0, (rz_ptrace_data_t)(size_t)&data) == -1) {
304  rz_sys_perror("ptrace GETEVENTMSG");
305  return RZ_DEBUG_REASON_ERROR;
306  }
307  // TODO: Check other processes exit if dbg->trace_forks is on
308  if (ptid != dbg->pid) {
309  eprintf("(%d) Thread exited with status=0x%" PFMT64x "\n", ptid, (ut64)data);
311  } else {
312  eprintf("(%d) Process exited with status=0x%" PFMT64x "\n", ptid, (ut64)data);
314  }
315  default:
316  eprintf("Unknown PTRACE_EVENT encountered: %d\n", pt_evt);
317  break;
318  }
320 }
321 #endif
322 
323 /*
324  * @brief Search for the parent of the newly created task and
325  * handle the pending SIGTRAP with PTRACE_EVENT_*
326  *
327  * @param tid, TID of the new task
328  * @return RzDebugReasonType, Debug reason
329  */
331  int ret, status;
332  if (dbg->threads) {
333  RzDebugPid *th;
334  RzListIter *it;
335  // Search for SIGTRAP with PTRACE_EVENT_* in other threads.
336  rz_list_foreach (dbg->threads, it, th) {
337  if (th->pid == tid) {
338  continue;
339  }
340  // Retrieve the signal without consuming it with PTRACE_GETSIGINFO
341  siginfo_t siginfo = { 0 };
342  ret = rz_debug_ptrace(dbg, PTRACE_GETSIGINFO, th->pid, 0, (rz_ptrace_data_t)(size_t)&siginfo);
343  // Skip if PTRACE_GETSIGINFO fails when the thread is running.
344  if (ret == -1) {
345  continue;
346  }
347 #ifdef PT_GETEVENTMSG
348  // NOTE: This API was added in Linux 2.5.46
349  if (siginfo.si_signo == SIGTRAP) {
350  // si_code = (SIGTRAP | PTRACE_EVENT_* << 8)
351  int pt_evt = siginfo.si_code >> 8;
352  // Handle PTRACE_EVENT_* that creates a new task (fork/clone)
353  switch (pt_evt) {
354  case PTRACE_EVENT_CLONE:
355  case PTRACE_EVENT_VFORK:
356  case PTRACE_EVENT_FORK:
357  ret = waitpid(th->pid, &status, 0);
358  return linux_ptrace_event(dbg, ret, status, false);
359  default:
360  break;
361  }
362  }
363 #endif
364  }
365  }
367 }
368 
370  int ret = false;
371  int pid = dbg->tid;
372  ret = rz_debug_ptrace(dbg, PTRACE_SINGLESTEP, pid, 0, 0);
373  // XXX(jjd): why?? //linux_handle_signals (dbg);
374  if (ret == -1) {
375  perror("native-singlestep");
376  ret = false;
377  } else {
378  ret = true;
379  }
380  return ret;
381 }
382 
384  int traceflags = 0;
385  traceflags |= PTRACE_O_TRACEFORK;
386  traceflags |= PTRACE_O_TRACEVFORK;
387  traceflags |= PTRACE_O_TRACECLONE;
388  if (dbg->trace_forks) {
389  traceflags |= PTRACE_O_TRACEVFORKDONE;
390  }
391  if (dbg->trace_execs) {
392  traceflags |= PTRACE_O_TRACEEXEC;
393  }
394  if (dbg->trace_aftersyscall) {
395  traceflags |= PTRACE_O_TRACEEXIT;
396  }
397  /* SIGTRAP | 0x80 on signal handler .. not supported on all archs */
398  traceflags |= PTRACE_O_TRACESYSGOOD;
399 
400  // PTRACE_SETOPTIONS can fail because of the asynchronous nature of ptrace
401  // If the target is traced, the loop will always end with success
402  while (rz_debug_ptrace(dbg, PTRACE_SETOPTIONS, pid, 0, (rz_ptrace_data_t)(size_t)traceflags) == -1) {
403  void *bed = rz_cons_sleep_begin();
404  usleep(1000);
405  rz_cons_sleep_end(bed);
406  }
407  return true;
408 }
409 
410 static void linux_detach_all(RzDebug *dbg) {
411  RzList *th_list = dbg->threads;
412  if (th_list) {
413  RzDebugPid *th;
414  RzListIter *it;
415  rz_list_foreach (th_list, it, th) {
416  if (th->pid != dbg->main_pid) {
417  if (rz_debug_ptrace(dbg, PTRACE_DETACH, th->pid, NULL, (rz_ptrace_data_t)(size_t)NULL) == -1) {
418  perror("PTRACE_DETACH");
419  }
420  }
421  }
422  }
423 
424  // Detaching from main proc
425  if (rz_debug_ptrace(dbg, PTRACE_DETACH, dbg->main_pid, NULL, (rz_ptrace_data_t)(size_t)NULL) == -1) {
426  perror("PTRACE_DETACH");
427  }
428 }
429 
430 static void linux_remove_thread(RzDebug *dbg, int tid) {
431  if (dbg->threads) {
432  RzDebugPid *th;
433  RzListIter *it;
434  rz_list_foreach (dbg->threads, it, th) {
435  if (th->pid == tid) {
436  rz_list_delete(dbg->threads, it);
437  dbg->n_threads--;
438  break;
439  }
440  }
441  }
442 }
443 
444 bool linux_select(RzDebug *dbg, int pid, int tid) {
445  if (dbg->pid != -1 && dbg->pid != pid) {
447  }
448  return linux_attach(dbg, tid);
449 }
450 
453  if (dbg->threads) {
455  dbg->threads = NULL;
456  }
457 
458  if (!linux_attach(dbg, pid)) {
459  return false;
460  }
461 
462  // Call select to syncrhonize the thread's data.
463  dbg->pid = pid;
464  dbg->tid = pid;
466 
467  return true;
468 }
469 
471  // Get the debugger and debuggee process group ID
472  pid_t dpgid = getpgid(0);
473  if (dpgid == -1) {
474  rz_sys_perror("getpgid");
475  return;
476  }
477  pid_t tpgid = getpgid(dbg->pid);
478  if (tpgid == -1) {
479  rz_sys_perror("getpgid");
480  return;
481  }
482 
483  // If the debuggee process is created by the debugger, do nothing because
484  // SIGINT is already sent to both the debugger and debuggee in the same
485  // process group.
486 
487  // If the debuggee is attached by the debugger, send SIGINT to the debuggee
488  // in another process group.
489  if (dpgid != tpgid) {
490  if (!linux_kill_thread(dbg->pid, SIGINT)) {
491  eprintf("Could not interrupt pid (%d)\n", dbg->pid);
492  }
493  }
494 }
495 
497  if (!linux_kill_thread(dbg->pid, SIGINT)) {
498  eprintf("Could not interrupt pid (%d)\n", dbg->pid);
499  }
500 }
501 
504  int tid = 0;
505  int status, flags = __WALL;
506  int ret = -1;
507 
508  if (pid == -1) {
509  flags |= WNOHANG;
510  }
511 
512  for (;;) {
513  // In the main context, SIGINT is propagated to the debuggee if it is
514  // in the same process group. Otherwise, the task is running in
515  // background and SIGINT will not be propagated to the debuggee.
516  if (rz_cons_context_is_main()) {
518  } else {
520  }
521  void *bed = rz_cons_sleep_begin();
522  if (dbg->continue_all_threads) {
523  ret = waitpid(-1, &status, flags);
524  } else {
525  ret = waitpid(pid, &status, flags);
526  }
527  rz_cons_sleep_end(bed);
529 
530  if (ret < 0) {
531  // Continue when interrupted by user;
532  if (errno == EINTR) {
533  continue;
534  }
535  perror("waitpid");
536  break;
537  } else if (ret == 0) {
538  // Unset WNOHANG to call next waitpid in blocking mode.
539  flags &= ~WNOHANG;
540  } else {
541  tid = ret;
542 
543  // Handle SIGTRAP with PTRACE_EVENT_*
544  reason = linux_ptrace_event(dbg, tid, status, true);
545  if (reason != RZ_DEBUG_REASON_UNKNOWN) {
546  break;
547  }
548 
549  if (WIFEXITED(status)) {
550  if (tid == dbg->main_pid) {
552  dbg->threads = NULL;
553  reason = RZ_DEBUG_REASON_DEAD;
554  eprintf("(%d) Process terminated with status %d\n", tid, WEXITSTATUS(status));
555  break;
556  } else {
557  eprintf("(%d) Child terminated with status %d\n", tid, WEXITSTATUS(status));
558  linux_remove_thread(dbg, tid);
559  continue;
560  }
561  } else if (WIFSIGNALED(status)) {
562  eprintf("child received signal %d\n", WTERMSIG(status));
563  reason = RZ_DEBUG_REASON_SIGNAL;
564  } else if (WIFSTOPPED(status)) {
565  // If tid is not in the thread list and stopped by SIGSTOP,
566  // handle it as a new task.
567  if (!rz_list_find(dbg->threads, &tid, &match_pid) &&
568  WSTOPSIG(status) == SIGSTOP) {
569  reason = linux_handle_new_task(dbg, tid);
570  if (reason != RZ_DEBUG_REASON_UNKNOWN) {
571  break;
572  }
573  }
574 
575  if (linux_handle_signals(dbg, tid)) {
576  reason = dbg->reason.type;
577  } else {
578  eprintf("can't handle signals\n");
579  return RZ_DEBUG_REASON_ERROR;
580  }
581 #ifdef WIFCONTINUED
582  } else if (WIFCONTINUED(status)) {
583  eprintf("child continued...\n");
584  reason = RZ_DEBUG_REASON_NONE;
585 #endif
586  } else if (status == 1) {
587  eprintf("debugger is dead with status 1\n");
588  reason = RZ_DEBUG_REASON_DEAD;
589  } else if (status == 0) {
590  eprintf("debugger is dead with status 0\n");
591  reason = RZ_DEBUG_REASON_DEAD;
592  } else {
593  if (ret != tid) {
594  reason = RZ_DEBUG_REASON_NEW_PID;
595  } else {
596  eprintf("returning from wait without knowing why...\n");
597  }
598  }
599  if (reason != RZ_DEBUG_REASON_UNKNOWN) {
600  break;
601  }
602  }
603  }
604  dbg->reason.tid = tid;
605  return reason;
606 }
607 
608 int match_pid(const void *pid_o, const void *th_o) {
609  int pid = *(int *)pid_o;
610  RzDebugPid *th = (RzDebugPid *)th_o;
611  return (pid == th->pid) ? 0 : 1;
612 }
613 
614 static void linux_add_new_thread(RzDebug *dbg, int tid) {
615  int uid = getuid(); // XXX
616  char info[1024] = { 0 };
617  RzDebugPid *tid_info;
618 
619  if (!procfs_pid_slurp(tid, "status", info, sizeof(info))) {
620  tid_info = fill_pid_info(info, NULL, tid);
621  } else {
622  tid_info = rz_debug_pid_new("new_path", tid, uid, 's', 0);
623  }
624  linux_set_options(dbg, tid);
625  rz_list_append(dbg->threads, tid_info);
626  dbg->n_threads++;
627 }
628 
629 static bool linux_kill_thread(int tid, int signo) {
630  int ret = syscall(__NR_tkill, tid, signo);
631 
632  if (ret == -1) {
633  perror("tkill");
634  return false;
635  }
636 
637  return true;
638 }
639 
640 static bool linux_stop_thread(RzDebug *dbg, int tid) {
641  int status, ret;
642  siginfo_t siginfo = { 0 };
643 
644  // Return if the thread is already stopped
645  ret = rz_debug_ptrace(dbg, PTRACE_GETSIGINFO, tid, 0,
646  (rz_ptrace_data_t)(intptr_t)&siginfo);
647  if (ret == 0) {
648  return true;
649  }
650 
651  if (linux_kill_thread(tid, SIGSTOP)) {
652  if ((ret = waitpid(tid, &status, 0)) == -1) {
653  perror("waitpid");
654  }
655  return ret == tid;
656  }
657  return false;
658 }
659 
660 bool linux_stop_threads(RzDebug *dbg, int except) {
661  bool ret = true;
662  if (dbg->threads) {
663  RzDebugPid *th;
664  RzListIter *it;
665  rz_list_foreach (dbg->threads, it, th) {
666  if (th->pid && th->pid != except) {
667  if (!linux_stop_thread(dbg, th->pid)) {
668  ret = false;
669  }
670  }
671  }
672  }
673  return ret;
674 }
675 
676 static bool linux_attach_single_pid(RzDebug *dbg, int ptid) {
677  siginfo_t sig = { 0 };
678 
679  if (ptid < 0) {
680  return false;
681  }
682 
683  // Safely check if the PID has already been attached to avoid printing errors.
684  // Attaching to a process that has already been started with PTRACE_TRACEME.
685  // sets errno to "Operation not permitted" which may be misleading.
686  // GETSIGINFO can be called multiple times and would fail without attachment.
687  if (rz_debug_ptrace(dbg, PTRACE_GETSIGINFO, ptid, NULL,
688  (rz_ptrace_data_t)&sig) == -1) {
689  if (rz_debug_ptrace(dbg, PTRACE_ATTACH, ptid, NULL, NULL) == -1) {
690  perror("ptrace (PT_ATTACH)");
691  return false;
692  }
693 
694  // Make sure SIGSTOP is delivered and wait for it since we can't affect the pid
695  // until it hits SIGSTOP.
696  if (!linux_stop_thread(dbg, ptid)) {
697  eprintf("Could not stop pid (%d)\n", ptid);
698  return false;
699  }
700  }
701 
702  if (!linux_set_options(dbg, ptid)) {
703  eprintf("failed set_options on %d\n", ptid);
704  return false;
705  }
706  return true;
707 }
708 
709 static RzList *get_pid_thread_list(RzDebug *dbg, int main_pid) {
710  RzList *list = rz_list_new();
711  if (list) {
712  list = linux_thread_list(dbg, main_pid, list);
713  dbg->main_pid = main_pid;
714  }
715  return list;
716 }
717 
719  // First time we run: We try to attach to all "possible" threads and to the main pid
720  if (!dbg->threads) {
722  } else {
723  // This means we did a first run, so we probably attached to all possible threads already.
724  // So check if the requested thread is being traced already. If not, attach it
725  if (!rz_list_find(dbg->threads, &pid, &match_pid)) {
727  }
728  }
729  return pid;
730 }
731 
732 static char *read_link(int pid, const char *file) {
733  char path[1024] = { 0 };
734  char buf[1024] = { 0 };
735 
736  snprintf(path, sizeof(path), "/proc/%d/%s", pid, file);
737  int ret = readlink(path, buf, sizeof(buf));
738  if (ret > 0) {
739  buf[sizeof(buf) - 1] = '\0';
740  return strdup(buf);
741  }
742  return NULL;
743 }
744 
746  char proc_buff[1024];
748  if (!rdi) {
749  return NULL;
750  }
751 
752  RzList *th_list;
753  bool list_alloc = false;
754  if (dbg->threads) {
755  th_list = dbg->threads;
756  } else {
757  th_list = rz_list_new();
758  list_alloc = true;
759  if (th_list) {
760  th_list = linux_thread_list(dbg, dbg->pid, th_list);
761  }
762  }
763  RzDebugPid *th;
764  RzListIter *it;
765  bool found = false;
766  rz_list_foreach (th_list, it, th) {
767  if (th->pid == dbg->pid) {
768  found = true;
769  break;
770  }
771  }
772  rdi->pid = dbg->pid;
773  rdi->tid = dbg->tid;
774  rdi->uid = found ? th->uid : -1;
775  rdi->gid = found ? th->gid : -1;
776  rdi->cwd = read_link(rdi->pid, "cwd");
777  rdi->exe = read_link(rdi->pid, "exe");
778  snprintf(proc_buff, sizeof(proc_buff), "/proc/%d/cmdline", rdi->pid);
779  rdi->cmdline = rz_file_slurp(proc_buff, NULL);
780  snprintf(proc_buff, sizeof(proc_buff), "/proc/%d/stack", rdi->pid);
781  rdi->kernel_stack = rz_file_slurp(proc_buff, NULL);
782  rdi->status = found ? th->status : RZ_DBG_PROC_STOP;
783  if (list_alloc) {
784  rz_list_free(th_list);
785  }
786  return rdi;
787 }
788 
789 RzDebugPid *fill_pid_info(const char *info, const char *path, int tid) {
790  RzDebugPid *pid_info = RZ_NEW0(RzDebugPid);
791  if (!pid_info) {
792  return NULL;
793  }
794  char *ptr = strstr(info, "State:");
795  if (ptr) {
796  switch (*(ptr + 7)) {
797  case 'R':
798  pid_info->status = RZ_DBG_PROC_RUN;
799  break;
800  case 'S':
801  pid_info->status = RZ_DBG_PROC_SLEEP;
802  break;
803  case 'T':
804  case 't':
805  pid_info->status = RZ_DBG_PROC_STOP;
806  break;
807  case 'Z':
808  pid_info->status = RZ_DBG_PROC_ZOMBIE;
809  break;
810  case 'X':
811  pid_info->status = RZ_DBG_PROC_DEAD;
812  break;
813  default:
814  pid_info->status = RZ_DBG_PROC_SLEEP;
815  break;
816  }
817  }
818  ptr = strstr(info, "PPid:");
819  if (ptr) {
820  pid_info->ppid = atoi(ptr + 5);
821  }
822  ptr = strstr(info, "Uid:");
823  if (ptr) {
824  pid_info->uid = atoi(ptr + 5);
825  }
826  ptr = strstr(info, "Gid:");
827  if (ptr) {
828  pid_info->gid = atoi(ptr + 5);
829  }
830 
831  pid_info->pid = tid;
832  pid_info->path = path ? strdup(path) : NULL;
833  pid_info->runnable = true;
834  pid_info->pc = 0;
835  return pid_info;
836 }
837 
840  DIR *dh = NULL;
841  struct dirent *de = NULL;
842  char path[PATH_MAX], info[PATH_MAX];
843  int i = -1;
844  RzDebugPid *pid_info = NULL;
845  dh = opendir("/proc");
846  if (!dh) {
847  rz_sys_perror("opendir /proc");
849  return NULL;
850  }
851  while ((de = readdir(dh))) {
852  path[0] = 0;
853  info[0] = 0;
854  // For each existing pid file
855  if ((i = atoi(de->d_name)) <= 0) {
856  continue;
857  }
858 
859  procfs_pid_slurp(i, "cmdline", path, sizeof(path));
860  if (!procfs_pid_slurp(i, "status", info, sizeof(info))) {
861  // Get information about pid (status, pc, etc.)
862  pid_info = fill_pid_info(info, path, i);
863  } else {
864  pid_info = rz_debug_pid_new(path, i, 0, RZ_DBG_PROC_STOP, 0);
865  }
866  // Unless pid 0 is requested, only add the requested pid and it's child processes
867  if (0 == pid || i == pid || pid_info->ppid == pid) {
868  rz_list_append(list, pid_info);
869  }
870  }
871  closedir(dh);
872  return list;
873 }
874 
876  int i = 0, thid = 0;
877  char *ptr, buf[PATH_MAX];
878  RzDebugPid *pid_info = NULL;
879  ut64 pc = 0;
880  int prev_tid = dbg->tid;
881 
882  if (!pid) {
884  return NULL;
885  }
886 
888  /* if this process has a task directory, use that */
889  snprintf(buf, sizeof(buf), "/proc/%d/task", pid);
890  if (rz_file_is_directory(buf)) {
891  struct dirent *de;
892  DIR *dh = opendir(buf);
893  // Update the process' memory maps to set correct paths
895  while ((de = readdir(dh))) {
896  if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
897  continue;
898  }
899  int tid = atoi(de->d_name);
900  char info[PATH_MAX];
901  int uid = 0;
902  if (!procfs_pid_slurp(tid, "status", info, sizeof(info))) {
903  ptr = strstr(info, "Uid:");
904  if (ptr) {
905  uid = atoi(ptr + 4);
906  }
907  ptr = strstr(info, "Tgid:");
908  if (ptr) {
909  int tgid = atoi(ptr + 5);
910  if (tgid != pid) {
911  /* Ignore threads that aren't in the pid's thread group */
912  continue;
913  }
914  }
915  }
916 
917  // Switch to the currently inspected thread to get it's program counter
918  if (dbg->tid != tid) {
920  dbg->tid = tid;
921  }
922 
924  pc = rz_debug_reg_get(dbg, "PC");
925 
926  if (!procfs_pid_slurp(tid, "status", info, sizeof(info))) {
927  // Get information about pid (status, pc, etc.)
928  pid_info = fill_pid_info(info, NULL, tid);
929  pid_info->pc = pc;
930  } else {
931  pid_info = rz_debug_pid_new(NULL, tid, uid, 's', pc);
932  }
933  rz_list_append(list, pid_info);
934  dbg->n_threads++;
935  }
936  closedir(dh);
937  // Return to the original thread
938  linux_attach_single_pid(dbg, prev_tid);
939  dbg->tid = prev_tid;
941  } else {
942  /* Some linux configurations might hide threads from /proc, use this workaround instead */
943 #undef MAXPID
944 #define MAXPID 99999
945  /* otherwise, brute force the pids */
946  for (i = pid; i < MAXPID; i++) { // XXX
947  if (procfs_pid_slurp(i, "status", buf, sizeof(buf)) == -1) {
948  continue;
949  }
950  int uid = 0;
951  /* look for a thread group id */
952  ptr = strstr(buf, "Uid:");
953  if (ptr) {
954  uid = atoi(ptr + 4);
955  }
956  ptr = strstr(buf, "Tgid:");
957  if (ptr) {
958  int tgid = atoi(ptr + 5);
959 
960  /* if it is not in our thread group, we don't want it */
961  if (tgid != pid) {
962  continue;
963  }
964 
965  if (procfs_pid_slurp(i, "comm", buf, sizeof(buf)) == -1) {
966  /* fall back to auto-id */
967  snprintf(buf, sizeof(buf), "thread_%d", thid++);
968  }
969  rz_list_append(list, rz_debug_pid_new(buf, i, uid, 's', 0));
970  }
971  }
972  }
973  return list;
974 }
975 
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)
985 
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)
994 
995 static void print_fpu(void *f) {
996 #if __x86_64__
997  int i, j;
998  struct user_fpregs_struct fpregs = *(struct user_fpregs_struct *)f;
999 #if __ANDROID__
1000  PRINT_FPU(fpregs);
1001  for (i = 0; i < 8; i++) {
1002  ut64 *b = (ut64 *)&fpregs.st_space[i * 4];
1003  ut32 *c = (ut32 *)&fpregs.st_space;
1004  float *f = (float *)&fpregs.st_space;
1005  c = c + (i * 4);
1006  f = f + (i * 4);
1007  rz_cons_printf("st%d =%0.3lg (0x%016" PFMT64x ") | %0.3f (%08x) | "
1008  "%0.3f (%08x) \n",
1009  i,
1010  (double)*((double *)&fpregs.st_space[i * 4]), *b, (float)f[0],
1011  c[0], (float)f[1], c[1]);
1012  }
1013 #else
1014  rz_cons_printf("---- x86-64 ----\n");
1015  PRINT_FPU(fpregs);
1016  rz_cons_printf("size = 0x%08x\n", (ut32)sizeof(fpregs));
1017  for (i = 0; i < 16; i++) {
1018  ut32 *a = (ut32 *)&fpregs.xmm_space;
1019  a = a + (i * 4);
1020  rz_cons_printf("xmm%d = %08x %08x %08x %08x ", i, (int)a[0], (int)a[1],
1021  (int)a[2], (int)a[3]);
1022  if (i < 8) {
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];
1026  rz_cons_printf("mm%d = 0x%016" PFMT64x " | st%d = ", i, *st_u64, i);
1027  // print as hex TBYTE - always little endian
1028  for (j = 9; j >= 0; j--) {
1029  rz_cons_printf("%02x", st_u8[j]);
1030  }
1031  // Using %Lf and %Le even though we do not show the extra precision to avoid another cast
1032  // %f with (double)*st_ld would also work
1033  rz_cons_printf(" %Le %Lf\n", *st_ld, *st_ld);
1034  } else {
1035  rz_cons_printf("\n");
1036  }
1037  }
1038 #endif // __ANDROID__
1039 #elif __i386__
1040  int i;
1041 #if __ANDROID__
1042  struct user_fpxregs_struct fpxregs = *(struct user_fpxregs_struct *)f;
1043  rz_cons_printf("---- x86-32 ----\n");
1044  rz_cons_printf("cwd = 0x%04x ; control ", fpxregs.cwd);
1045  rz_cons_printf("swd = 0x%04x ; status\n", fpxregs.swd);
1046  rz_cons_printf("twd = 0x%04x ", fpxregs.twd);
1047  rz_cons_printf("fop = 0x%04x\n", fpxregs.fop);
1048  rz_cons_printf("fip = 0x%08x\n", (ut32)fpxregs.fip);
1049  rz_cons_printf("fcs = 0x%08x\n", (ut32)fpxregs.fcs);
1050  rz_cons_printf("foo = 0x%08x\n", (ut32)fpxregs.foo);
1051  rz_cons_printf("fos = 0x%08x\n", (ut32)fpxregs.fos);
1052  rz_cons_printf("mxcsr = 0x%08x\n", (ut32)fpxregs.mxcsr);
1053  for (i = 0; i < 8; i++) {
1054  ut32 *a = (ut32 *)(&fpxregs.xmm_space);
1055  ut64 *b = (ut64 *)(&fpxregs.st_space[i * 4]);
1056  ut32 *c = (ut32 *)&fpxregs.st_space;
1057  float *f = (float *)&fpxregs.st_space;
1058  a = a + (i * 4);
1059  c = c + (i * 4);
1060  f = f + (i * 4);
1061  rz_cons_printf("xmm%d = %08x %08x %08x %08x ", i, (int)a[0],
1062  (int)a[1], (int)a[2], (int)a[3]);
1063  rz_cons_printf("st%d = %0.3lg (0x%016" PFMT64x ") | %0.3f (0x%08x) | "
1064  "%0.3f (0x%08x)\n",
1065  i,
1066  (double)*((double *)(&fpxregs.st_space[i * 4])), b[0],
1067  f[0], c[0], f[1], c[1]);
1068  }
1069 #else
1070  struct user_fpregs_struct fpregs = *(struct user_fpregs_struct *)f;
1071  rz_cons_printf("---- x86-32-noxmm ----\n");
1072  PRINT_FPU_NOXMM(fpregs);
1073  for (i = 0; i < 8; i++) {
1074  ut64 *b = (ut64 *)(&fpregs.st_space[i * 4]);
1075  double *d = (double *)b;
1076  ut32 *c = (ut32 *)&fpregs.st_space;
1077  float *f = (float *)&fpregs.st_space;
1078  c = c + (i * 4);
1079  f = f + (i * 4);
1080  rz_cons_printf("st%d = %0.3lg (0x%016" PFMT64x ") | %0.3f (0x%08x) | "
1081  "%0.3f (0x%08x)\n",
1082  i, d[0], b[0], f[0], c[0], f[1], c[1]);
1083  }
1084 #endif
1085 #else
1086 #warning print_fpu not implemented for this platform
1087 #endif
1088 }
1089 
1091  bool showfpu = false;
1092  int pid = dbg->tid;
1093  int ret = 0;
1094  if (type < -1) {
1095  showfpu = true;
1096  type = -type;
1097  }
1098  switch (type) {
1099  case RZ_REG_TYPE_DRX:
1100 #if __POWERPC__
1101  // no drx for powerpc
1102  return false;
1103 #elif __i386__ || __x86_64__
1104 #if !__ANDROID__
1105  {
1106  int i;
1107  for (i = 0; i < 8; i++) { // DR0-DR7
1108  if (i == 4 || i == 5) {
1109  continue;
1110  }
1111  long ret = rz_debug_ptrace(dbg, PTRACE_PEEKUSER, pid,
1112  (void *)rz_offsetof(struct user, u_debugreg[i]), 0);
1113  if ((i + 1) * sizeof(ret) > size) {
1114  eprintf("linux_reg_get: Buffer too small %d\n", size);
1115  break;
1116  }
1117  memcpy(buf + (i * sizeof(ret)), &ret, sizeof(ret));
1118  }
1119  struct user a;
1120  return sizeof(a.u_debugreg);
1121  }
1122 #else
1123 #warning Android X86 does not support DRX
1124 #endif
1125 #endif
1126  return true;
1127  break;
1128  case RZ_REG_TYPE_FPU:
1129  case RZ_REG_TYPE_MMX:
1130  case RZ_REG_TYPE_XMM:
1131 #if __POWERPC__
1132  return false;
1133 #elif __x86_64__ || __i386__
1134  {
1135  struct user_fpregs_struct fpregs;
1136  if (type == RZ_REG_TYPE_FPU) {
1137 #if __x86_64__
1138  ret = rz_debug_ptrace(dbg, PTRACE_GETFPREGS, pid, NULL, &fpregs);
1139  if (ret != 0) {
1140  rz_sys_perror("PTRACE_GETFPREGS");
1141  return false;
1142  }
1143  if (showfpu) {
1144  print_fpu((void *)&fpregs);
1145  }
1146  size = RZ_MIN(sizeof(fpregs), size);
1147  memcpy(buf, &fpregs, size);
1148  return size;
1149 #elif __i386__
1150 #if !__ANDROID__
1151  struct user_fpxregs_struct fpxregs;
1152  ret = rz_debug_ptrace(dbg, PTRACE_GETFPXREGS, pid, NULL, &fpxregs);
1153  if (ret == 0) {
1154  if (showfpu) {
1155  print_fpu((void *)&fpxregs);
1156  }
1157  size = RZ_MIN(sizeof(fpxregs), size);
1158  memcpy(buf, &fpxregs, size);
1159  return size;
1160  } else {
1161  ret = rz_debug_ptrace(dbg, PTRACE_GETFPREGS, pid, NULL, &fpregs);
1162  if (showfpu) {
1163  print_fpu((void *)&fpregs);
1164  }
1165  if (ret != 0) {
1166  rz_sys_perror("PTRACE_GETFPREGS");
1167  return false;
1168  }
1169  size = RZ_MIN(sizeof(fpregs), size);
1170  memcpy(buf, &fpregs, size);
1171  return size;
1172  }
1173 #else
1174  ret = rz_debug_ptrace(dbg, PTRACE_GETFPREGS, pid, NULL, &fpregs);
1175  if (showfpu) {
1176  print_fpu((void *)&fpregs);
1177  }
1178  if (ret != 0) {
1179  rz_sys_perror("PTRACE_GETFPREGS");
1180  return false;
1181  }
1182  size = RZ_MIN(sizeof(fpregs), size);
1183  memcpy(buf, &fpregs, size);
1184  return size;
1185 #endif // !__ANDROID__
1186 #endif // __i386__
1187  }
1188  }
1189 #else
1190 #warning getfpregs not implemented for this platform
1191 #endif
1192  break;
1193  case RZ_REG_TYPE_SEG:
1194  case RZ_REG_TYPE_FLG:
1195  case RZ_REG_TYPE_GPR: {
1197  memset(&regs, 0, sizeof(regs));
1198  memset(buf, 0, size);
1199 #if (__arm64__ || __aarch64__ || __s390x__) && defined(PTRACE_GETREGSET)
1200  struct iovec io = {
1201  .iov_base = &regs,
1202  .iov_len = sizeof(regs)
1203  };
1204  ret = rz_debug_ptrace(dbg, PTRACE_GETREGSET, pid, 1, &io);
1205  // ret = ptrace (PTRACE_GETREGSET, pid, (void*)(size_t)(NT_PRSTATUS), NULL); // &io);
1206  if (ret != 0) {
1207  rz_sys_perror("PTRACE_GETREGSET");
1208  return false;
1209  }
1210 #elif __BSD__ && (__POWERPC__ || __sparc__)
1211  ret = rz_debug_ptrace(dbg, PTRACE_GETREGS, pid, &regs, NULL);
1212 #else
1213  /* linux -{arm/mips/riscv/x86/x86_64} */
1214  ret = rz_debug_ptrace(dbg, PTRACE_GETREGS, pid, NULL, &regs);
1215 #endif
1216  /*
1217  * if perror here says 'no such process' and the
1218  * process exists still.. is because there's a missing call
1219  * to 'wait'. and the process is not yet available to accept
1220  * more ptrace queries.
1221  */
1222  if (ret != 0) {
1223  rz_sys_perror("PTRACE_GETREGS");
1224  return false;
1225  }
1226  size = RZ_MIN(sizeof(regs), size);
1227  memcpy(buf, &regs, size);
1228  return size;
1229  } break;
1230  case RZ_REG_TYPE_YMM: {
1231 #if HAVE_YMM && __x86_64__ && defined(PTRACE_GETREGSET)
1232  ut32 ymm_space[128]; // full ymm registers
1233  struct _xstate xstate;
1234  struct iovec iov;
1235  iov.iov_base = &xstate;
1236  iov.iov_len = sizeof(struct _xstate);
1238  if (ret == -1) {
1239  return false;
1240  }
1241  // stitch together xstate.fpstate._xmm and xstate.ymmh assuming LE
1242  int ri, rj;
1243  for (ri = 0; ri < 16; ri++) {
1244  for (rj = 0; rj < 4; rj++) {
1245 #ifdef __ANDROID__
1246  ymm_space[ri * 8 + rj] = ((struct _libc_fpstate *)&xstate.fpstate)->_xmm[ri].element[rj];
1247 #else
1248  ymm_space[ri * 8 + rj] = xstate.fpstate._xmm[ri].element[rj];
1249 #endif
1250  }
1251  for (rj = 0; rj < 4; rj++) {
1252  ymm_space[ri * 8 + (rj + 4)] = xstate.ymmh.ymmh_space[ri * 4 + rj];
1253  }
1254  }
1255  size = RZ_MIN(sizeof(ymm_space), size);
1256  memcpy(buf, &ymm_space, size);
1257  return size;
1258 #endif
1259  return false;
1260  } break;
1261  }
1262  return false;
1263 }
1264 
1265 int linux_reg_write(RzDebug *dbg, int type, const ut8 *buf, int size) {
1266  int pid = dbg->tid;
1267 
1268  if (type == RZ_REG_TYPE_DRX) {
1269 #if !__ANDROID__ && (__i386__ || __x86_64__)
1270  int i;
1271  long *val = (long *)buf;
1272  for (i = 0; i < 8; i++) { // DR0-DR7
1273  if (i == 4 || i == 5) {
1274  continue;
1275  }
1276  if (rz_debug_ptrace(dbg, PTRACE_POKEUSER, pid,
1277  (void *)rz_offsetof(struct user, u_debugreg[i]), (rz_ptrace_data_t)val[i])) {
1278  eprintf("ptrace error for dr %d\n", i);
1279  rz_sys_perror("ptrace POKEUSER");
1280  }
1281  }
1282  return sizeof(RZ_DEBUG_REG_T);
1283 #else
1284  return false;
1285 #endif
1286  }
1287  if (type == RZ_REG_TYPE_GPR) {
1288 #if __arm64__ || __aarch64__ || __s390x__
1289  struct iovec io = {
1290  .iov_base = (void *)buf,
1291  .iov_len = sizeof(RZ_DEBUG_REG_T)
1292  };
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__
1295  int ret = rz_debug_ptrace(dbg, PTRACE_SETREGS, pid, buf, NULL);
1296 #else
1297  int ret = rz_debug_ptrace(dbg, PTRACE_SETREGS, pid, 0, (void *)buf);
1298 #endif
1299 #if DEAD_CODE
1300  if (size > sizeof(RZ_DEBUG_REG_T)) {
1301  size = sizeof(RZ_DEBUG_REG_T);
1302  }
1303 #endif
1304  if (ret == -1) {
1305  rz_sys_perror("reg_write");
1306  return false;
1307  }
1308  return true;
1309  }
1310  if (type == RZ_REG_TYPE_FPU) {
1311 #if __i386__ || __x86_64__
1312  int ret = rz_debug_ptrace(dbg, PTRACE_SETFPREGS, pid, 0, (void *)buf);
1313  return (ret != 0) ? false : true;
1314 #endif
1315  }
1316  return false;
1317 }
1318 
1320  RzList *ret = NULL;
1321  char path[512], file[512], buf[512];
1322  struct dirent *de;
1323  RzDebugDesc *desc;
1324  int type, perm;
1325  int len, len2;
1326  struct stat st;
1327  DIR *dd = NULL;
1328 
1329  rz_strf(path, "/proc/%i/fd/", pid);
1330  if (!(dd = opendir(path))) {
1331  rz_sys_perror("opendir /proc/x/fd");
1332  return NULL;
1333  }
1335  if (!ret) {
1336  closedir(dd);
1337  return NULL;
1338  }
1339  while ((de = (struct dirent *)readdir(dd))) {
1340  if (de->d_name[0] == '.') {
1341  continue;
1342  }
1343  len = strlen(path);
1344  len2 = strlen(de->d_name);
1345  if (len + len2 + 1 >= sizeof(file)) {
1346  RZ_LOG_ERROR("Filename is too long.\n");
1347  goto fail;
1348  }
1349  memcpy(file, path, len);
1350  memcpy(file + len, de->d_name, len2 + 1);
1351  buf[0] = 0;
1352  if (readlink(file, buf, sizeof(buf) - 1) == -1) {
1353  RZ_LOG_ERROR("readlink %s failed.\n", file);
1354  goto fail;
1355  }
1356  buf[sizeof(buf) - 1] = 0;
1357  type = perm = 0;
1358  if (stat(file, &st) != -1) {
1359  type = st.st_mode & S_IFIFO ? 'P' :
1360 #ifdef S_IFSOCK
1361  st.st_mode & S_IFSOCK ? 'S'
1362  :
1363 #endif
1364  st.st_mode & S_IFCHR ? 'C'
1365  : '-';
1366  }
1367  if (lstat(path, &st) != -1) {
1368  if (st.st_mode & S_IRUSR) {
1369  perm |= RZ_PERM_R;
1370  }
1371  if (st.st_mode & S_IWUSR) {
1372  perm |= RZ_PERM_W;
1373  }
1374  }
1375  // TODO: Offset
1376  desc = rz_debug_desc_new(atoi(de->d_name), buf, perm, type, 0);
1377  if (!desc) {
1378  break;
1379  }
1380  rz_list_append(ret, desc);
1381  }
1382  closedir(dd);
1383  return ret;
1384 
1385 fail:
1386  rz_list_free(ret);
1387  closedir(dd);
1388  return NULL;
1389 }
size_t len
Definition: 6502dis.c:15
static char * regs[]
Definition: analysis_sh.c:203
lzma_index ** i
Definition: index.h:629
ut16 val
Definition: armass64_const.h:6
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
const char * desc
Definition: bin_vsf.c:19
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...
Definition: bp.c:119
RZ_API int rz_bp_get_index_at(RzBreakpoint *bp, ut64 addr)
Definition: bp.c:354
RZ_API int rz_bp_restore(RzBreakpoint *bp, bool set)
Definition: bp_io.c:28
#define RZ_DEBUG_REG_T
Definition: bsd_debug.h:8
RZ_API void * rz_cons_sleep_begin(void)
Definition: cons.c:443
RZ_API void rz_cons_break_pop(void)
Definition: cons.c:361
RZ_API void rz_cons_break_push(RzConsBreak cb, void *user)
Definition: cons.c:357
RZ_API int rz_cons_printf(const char *format,...)
Definition: cons.c:1202
RZ_API bool rz_cons_is_breaked(void)
Definition: cons.c:373
RZ_API void rz_cons_sleep_end(void *user)
Definition: cons.c:450
RZ_API bool rz_cons_context_is_main(void)
Definition: cons.c:913
#define NULL
Definition: cris-opc.c:27
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
static static sync static getppid static getegid const char static filename char static len readlink
Definition: sflib.h:65
RZ_API RzDebugDesc * rz_debug_desc_new(int fd, char *path, int perm, int type, int off)
Definition: ddesc.c:8
RZ_API void rz_debug_desc_free(RzDebugDesc *p)
Definition: ddesc.c:20
#define false
uint32_t ut32
RzDebug * dbg
Definition: desil.c:30
RZ_API bool rz_debug_map_sync(RzDebug *dbg)
Definition: dmap.c:33
RZ_API ut64 rz_debug_reg_get(RzDebug *dbg, const char *name)
Definition: dreg.c:99
RZ_API int rz_debug_reg_sync(RzDebug *dbg, int type, int write)
Definition: dreg.c:9
#define NT_X86_XSTATE
Definition: glibc_elf.h:773
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
void * p
Definition: libc.cpp:67
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
#define NT_PRSTATUS
Definition: common.h:393
RZ_API int rz_debug_drx_unset(RzDebug *dbg, int idx)
Definition: debug.c:1675
RZ_API void rz_debug_bp_update(RzDebug *dbg)
Definition: debug.c:39
RZ_API bool rz_debug_select(RzDebug *dbg, int pid, int tid)
Definition: debug.c:595
static void list(RzEgg *egg)
Definition: rz-gg.c:52
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.
Definition: list.c:620
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
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.
Definition: list.c:162
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
static stat
Definition: sflib.h:131
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
Definition: sflib.h:64
#define __NR_tkill
Definition: sfsysnr.h:284
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
Definition: sflib.h:163
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
Definition: sflib.h:120
static const char struct stat static buf struct stat static buf static vhangup int status
Definition: sflib.h:145
char * linux_reg_profile(RzDebug *dbg)
Definition: linux_debug.c:55
int linux_handle_signals(RzDebug *dbg, int tid)
Definition: linux_debug.c:103
int linux_attach(RzDebug *dbg, int pid)
Definition: linux_debug.c:718
RzDebugPid * fill_pid_info(const char *info, const char *path, int tid)
Definition: linux_debug.c:789
static bool linux_kill_thread(int tid, int signo)
Definition: linux_debug.c:629
long rz_debug_ptrace_get_x86_xstate(RzDebug *dbg, pid_t pid, struct iovec *iov)
Definition: linux_debug.c:50
static void linux_remove_fork_bps(RzDebug *dbg)
Definition: linux_debug.c:197
RzList * linux_pid_list(int pid, RzList *list)
Definition: linux_debug.c:838
static void linux_dbg_wait_break(RzDebug *dbg)
Definition: linux_debug.c:496
static bool linux_stop_thread(RzDebug *dbg, int tid)
Definition: linux_debug.c:640
int match_pid(const void *pid_o, const void *th_o)
Definition: linux_debug.c:608
#define PRINT_FPU(fpregs)
Definition: linux_debug.c:976
bool linux_attach_new_process(RzDebug *dbg, int pid)
Definition: linux_debug.c:451
bool linux_stop_threads(RzDebug *dbg, int except)
Definition: linux_debug.c:660
int linux_reg_read(RzDebug *dbg, int type, ut8 *buf, int size)
Definition: linux_debug.c:1090
static char * read_link(int pid, const char *file)
Definition: linux_debug.c:732
static void linux_dbg_wait_break_main(RzDebug *dbg)
Definition: linux_debug.c:470
RzDebugReasonType linux_dbg_wait(RzDebug *dbg, int pid)
Definition: linux_debug.c:502
#define PRINT_FPU_NOXMM(fpregs)
Definition: linux_debug.c:986
#define MAXPID
static RzList * get_pid_thread_list(RzDebug *dbg, int main_pid)
Definition: linux_debug.c:709
static void linux_detach_all(RzDebug *dbg)
Definition: linux_debug.c:410
RzList * linux_thread_list(RzDebug *dbg, int pid, RzList *list)
Definition: linux_debug.c:875
bool linux_set_options(RzDebug *dbg, int pid)
Definition: linux_debug.c:383
RzList * linux_desc_list(int pid)
Definition: linux_debug.c:1319
static bool linux_attach_single_pid(RzDebug *dbg, int ptid)
Definition: linux_debug.c:676
static void print_fpu(void *f)
Definition: linux_debug.c:995
RzDebugInfo * linux_info(RzDebug *dbg, const char *arg)
Definition: linux_debug.c:745
static RzDebugReasonType linux_handle_new_task(RzDebug *dbg, int tid)
Definition: linux_debug.c:330
static void linux_remove_thread(RzDebug *dbg, int pid)
Definition: linux_debug.c:430
int linux_step(RzDebug *dbg)
Definition: linux_debug.c:369
int linux_reg_write(RzDebug *dbg, int type, const ut8 *buf, int size)
Definition: linux_debug.c:1265
bool linux_select(RzDebug *dbg, int pid, int tid)
Definition: linux_debug.c:444
static void linux_add_new_thread(RzDebug *dbg, int tid)
Definition: linux_debug.c:614
#define TRAP_TRACE
Definition: linux_debug.h:154
RzDebugReasonType linux_ptrace_event(RzDebug *dbg, int pid, int status, bool dowait)
int type
Definition: mipsasm.c:17
const char * name
Definition: op.c:541
RZ_API RzDebugPid * rz_debug_pid_free(RzDebugPid *pid)
Definition: pid.c:20
RZ_API RzDebugPid * rz_debug_pid_new(const char *path, int pid, int uid, char status, ut64 pc)
Definition: pid.c:6
int procfs_pid_slurp(int pid, char *prop, char *out, size_t len)
Definition: procfs.c:7
RZ_API const char * rz_reg_get_name(RzReg *reg, int role)
Definition: reg.c:147
#define eprintf(x, y...)
Definition: rlcc.c:7
RzDebugReasonType
Definition: rz_debug.h:89
@ RZ_DEBUG_REASON_NEW_TID
Definition: rz_debug.h:106
@ RZ_DEBUG_REASON_DEAD
Definition: rz_debug.h:90
@ RZ_DEBUG_REASON_STEP
Definition: rz_debug.h:98
@ RZ_DEBUG_REASON_UNKNOWN
Definition: rz_debug.h:103
@ RZ_DEBUG_REASON_BREAKPOINT
Definition: rz_debug.h:94
@ RZ_DEBUG_REASON_USERSUSP
Definition: rz_debug.h:115
@ RZ_DEBUG_REASON_ABORT
Definition: rz_debug.h:99
@ RZ_DEBUG_REASON_ERROR
Definition: rz_debug.h:104
@ RZ_DEBUG_REASON_NEW_LIB
Definition: rz_debug.h:107
@ RZ_DEBUG_REASON_EXIT_LIB
Definition: rz_debug.h:110
@ RZ_DEBUG_REASON_SEGFAULT
Definition: rz_debug.h:93
@ RZ_DEBUG_REASON_NONE
Definition: rz_debug.h:91
@ RZ_DEBUG_REASON_NEW_PID
Definition: rz_debug.h:105
@ RZ_DEBUG_REASON_EXIT_PID
Definition: rz_debug.h:108
@ RZ_DEBUG_REASON_EXIT_TID
Definition: rz_debug.h:109
@ RZ_DEBUG_REASON_SIGNAL
Definition: rz_debug.h:92
@ RZ_DBG_PROC_RUN
Definition: rz_debug.h:61
@ RZ_DBG_PROC_STOP
Definition: rz_debug.h:60
@ RZ_DBG_PROC_ZOMBIE
Definition: rz_debug.h:63
@ RZ_DBG_PROC_DEAD
Definition: rz_debug.h:64
@ RZ_DBG_PROC_SLEEP
Definition: rz_debug.h:62
RZ_API bool rz_file_is_directory(const char *str)
Definition: file.c:167
RZ_API RZ_OWN char * rz_file_slurp(const char *str, RZ_NULLABLE size_t *usz)
Definition: file.c:454
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
@ RZ_REG_TYPE_SEG
Definition: rz_reg.h:28
@ RZ_REG_TYPE_MMX
Definition: rz_reg.h:24
@ RZ_REG_TYPE_GPR
Definition: rz_reg.h:21
@ RZ_REG_TYPE_YMM
Definition: rz_reg.h:26
@ RZ_REG_TYPE_FLG
Definition: rz_reg.h:27
@ RZ_REG_TYPE_FPU
Definition: rz_reg.h:23
@ RZ_REG_TYPE_DRX
Definition: rz_reg.h:22
@ RZ_REG_TYPE_XMM
Definition: rz_reg.h:25
@ RZ_REG_NAME_A1
Definition: rz_reg.h:50
@ RZ_REG_NAME_A0
Definition: rz_reg.h:49
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)
Definition: str.c:3286
#define rz_strf(buf,...)
Convenience macro for local temporary strings.
Definition: rz_str.h:59
@ RZ_SYS_BITS_32
Definition: rz_sys.h:20
#define rz_sys_perror(x)
Definition: rz_types.h:336
#define RZ_PERM_R
Definition: rz_types.h:93
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_PERM_W
Definition: rz_types.h:94
#define rz_offsetof(type, member)
Definition: rz_types.h:360
#define PFMT64x
Definition: rz_types.h:393
#define RZ_MIN(x, y)
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
#define ESRCH
Definition: sftypes.h:113
#define EINTR
Definition: sftypes.h:114
int pid_t
Definition: sftypes.h:38
#define ENODEV
Definition: sftypes.h:129
@ PTRACE_POKEUSER
Definition: sftypes.h:580
@ PTRACE_SETFPREGS
Definition: sftypes.h:613
@ PTRACE_SETREGS
Definition: sftypes.h:603
@ PTRACE_SINGLESTEP
Definition: sftypes.h:593
@ PTRACE_GETREGS
Definition: sftypes.h:598
@ PTRACE_ATTACH
Definition: sftypes.h:617
@ PTRACE_GETFPREGS
Definition: sftypes.h:608
@ PTRACE_GETFPXREGS
Definition: sftypes.h:626
@ PTRACE_PEEKUSER
Definition: sftypes.h:568
@ PTRACE_DETACH
Definition: sftypes.h:621
#define d(i)
Definition: sha256.c:44
#define b(i)
Definition: sha256.c:42
#define f(i)
Definition: sha256.c:46
#define c(i)
Definition: sha256.c:43
#define a(i)
Definition: sha256.c:41
_W64 signed int intptr_t
Definition: sftypes.h:48
char d_name[256]
Definition: sftypes.h:52
Definition: gzappend.c:170
Definition: sftypes.h:73
Definition: z80asm.h:102
int endian
Definition: rz_bp.h:82
RzList * bps
Definition: rz_bp.h:93
char * path
Definition: rz_debug.h:414
RzList * threads
Definition: rz_debug.h:251
int forked_pid
Definition: rz_debug.h:249
int trace_execs
Definition: rz_debug.h:264
bool continue_all_threads
Definition: rz_debug.h:272
ut64 stopaddr
Definition: rz_debug.h:278
int trace_clone
Definition: rz_debug.h:266
RzDebugReason reason
Definition: rz_debug.h:276
char * glob_unlibs
Definition: rz_debug.h:270
char * glob_libs
Definition: rz_debug.h:269
int n_threads
Definition: rz_debug.h:250
RzReg * reg
Definition: rz_debug.h:286
int bits
Definition: rz_debug.h:243
bool nt_x86_xstate_supported
Track whether X86_FEATURE_XSAVE feature is supported on current kernel.
Definition: rz_debug.h:323
int trace_aftersyscall
Definition: rz_debug.h:265
int trace_forks
Definition: rz_debug.h:263
int main_pid
Definition: rz_debug.h:246
RzBreakpoint * bp
Definition: rz_debug.h:288
Definition: sftypes.h:80
static uv_buf_t iov
Definition: main.c:15
const char * syscall
Definition: internal.h:270
#define fail(test)
Definition: tests.h:29
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static const z80_opcode dd[]
Definition: z80_tab.h:844