1 /* Copyright 2007, Red Hat Inc. */
11 #include <sys/ptrace.h>
12 #include <sys/types.h>
17 #include <thread_db.h>
19 #include <elfutils/libdwfl.h>
22 #include <linux/ptrace.h>
23 #include <asm/prctl.h>
25 #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
27 static __attribute__((__noreturn__)) void crash (void)
35 fputs (">>> CRASH START\n", stderr);
37 count = backtrace (array, ARRAY_SIZE (array));
38 backtrace_symbols_fd (array, count, STDERR_FILENO);
40 snprintf (command, sizeof (command), "echo -e \"bt\\nquit\""
41 " >/tmp/debugger.%d; gdb --batch -nx --command=/tmp/debugger.%d"
42 " /proc/%d/exe %d </dev/null;rm -f /tmp/debugger.%d",
43 (int) getpid(), (int) getpid(), (int) getpid(), (int) getpid(),
46 fputs (">>> CRASH FINISH\n", stderr);
56 static Dwfl *get_dwfl (struct ps_prochandle *proc_handle)
58 static char *debuginfo_path;
60 static const Dwfl_Callbacks proc_callbacks =
62 .find_debuginfo = dwfl_standard_find_debuginfo,
63 .debuginfo_path = &debuginfo_path,
65 .find_elf = dwfl_linux_proc_find_elf,
68 if (proc_handle->dwfl == NULL)
70 proc_handle->dwfl = dwfl_begin (&proc_callbacks);
71 assert (proc_handle->dwfl != NULL);
74 if (dwfl_linux_proc_report (proc_handle->dwfl, proc_handle->pid) != 0
75 || dwfl_report_end (proc_handle->dwfl, NULL, NULL) != 0)
77 fprintf (stderr, "dwfl reporting: %m\n");
78 dwfl_end (proc_handle->dwfl);
79 proc_handle->dwfl = NULL;
83 return proc_handle->dwfl;
86 /* Functions in this interface return one of these status codes. */
89 PS_OK, /* Generic "call succeeded". */
90 PS_ERR, /* Generic error. */
91 PS_BADPID, /* Bad process handle. */
92 PS_BADLID, /* Bad LWP identifier. */
93 PS_BADADDR, /* Bad address. */
94 PS_NOSYM, /* Could not find given symbol. */
95 PS_NOFREGS /* FPU register set not available for given LWP. */
98 ps_err_e ps_pdread (struct ps_prochandle *proc_handle, psaddr_t addr,
99 void *buffer, size_t length)
101 pid_t pid = proc_handle->pid;
105 if (pid == getpid ())
107 memcpy (buffer, addr, length);
111 if (ptrace (PTRACE_ATTACH, pid, NULL, NULL) != 0)
113 if (waitpid (pid, NULL, 0) != pid)
116 snprintf (filename, sizeof (filename), "/proc/%ld/mem", (long) pid);
117 fd = open (filename, O_RDONLY);
119 if (lseek64 (fd, (off64_t) addr, SEEK_SET) != (off64_t) addr)
121 if (read (fd, buffer, length) != length)
123 fprintf (stderr, "read() error @0x%lx length %lu: %m\n",
124 (unsigned long) addr, (unsigned long) length);
130 if (ptrace (PTRACE_DETACH, pid, NULL, NULL) != 0)
136 ps_err_e ps_pdwrite (struct ps_prochandle *proc_handle, psaddr_t addr,
137 const void *buffer, size_t length)
142 ps_err_e ps_lgetregs (struct ps_prochandle *proc_handle, lwpid_t lwp,
148 ps_err_e ps_lsetregs (struct ps_prochandle *proc_handle, lwpid_t lwp,
149 const prgregset_t regs)
154 ps_err_e ps_lgetfpregs (struct ps_prochandle *proc_handle, lwpid_t lwp,
155 prfpregset_t *fpregs)
160 ps_err_e ps_lsetfpregs (struct ps_prochandle *proc_handle, lwpid_t lwp,
161 const prfpregset_t *fpregs)
166 /* Return the PID of the process. */
167 pid_t ps_getpid (struct ps_prochandle *proc_handle)
169 return proc_handle->pid;
172 struct getmodules_callback_arg
174 const char *sym_name;
179 static int getmodules_callback (Dwfl_Module *module,
180 void **module_userdata_pointer,
181 const char *module_name,
182 Dwarf_Addr module_low_addr, void *arg)
184 struct getmodules_callback_arg *getmodules_callback_arg = arg;
188 sym_count = dwfl_module_getsymtab (module);
189 assert (sym_count >= 0);
190 for (ndx = 0; ndx < sym_count; ndx++)
192 const char *name_got;
194 name_got = dwfl_module_getsym (module, ndx, &sym,
196 assert (name_got != NULL);
197 if (strcmp (name_got, getmodules_callback_arg->sym_name) == 0)
200 if (ndx == sym_count)
203 *getmodules_callback_arg->sym_addr = (psaddr_t) sym.st_value;
204 getmodules_callback_arg->retval = PS_OK;
209 /* Look up the named symbol in the named DSO in the symbol tables
210 associated with the process being debugged, filling in *SYM_ADDR
211 with the corresponding run-time address. */
212 ps_err_e ps_pglobal_lookup (struct ps_prochandle *proc_handle,
213 const char *object_name, const char *sym_name,
216 Dwfl *dwfl = get_dwfl (proc_handle);
217 struct getmodules_callback_arg getmodules_callback_arg;
218 ptrdiff_t err_ptrdiff;
220 /* FIXME: `object_name' ignored due to missing unresolving of shared
221 libraries symbolic links. */
222 getmodules_callback_arg.sym_name = sym_name;
223 getmodules_callback_arg.sym_addr = sym_addr;
224 getmodules_callback_arg.retval = PS_NOSYM;
225 err_ptrdiff = dwfl_getmodules (dwfl, getmodules_callback,
226 &getmodules_callback_arg, 0);
227 assert (err_ptrdiff == 0);
228 return getmodules_callback_arg.retval;
232 ps_err_e ps_get_thread_area (const struct ps_prochandle *ph, lwpid_t lwpid,
233 int idx, void **base)
237 assert (idx == FS || idx == GS);
239 if (ptrace (PTRACE_ATTACH, lwpid, NULL, NULL) != 0)
241 if (waitpid (lwpid, NULL, 0) != lwpid)
244 val = ptrace (PTRACE_ARCH_PRCTL, lwpid, base, (idx == FS ? ARCH_GET_FS
247 if (ptrace (PTRACE_DETACH, lwpid, NULL, NULL) != 0)
252 fprintf (stderr, "PTRACE_ARCH_PRCTL (%s): %m\n", (idx == FS ? "FS"
260 #error "Unsupported ps_get_thread_area ()!"
263 static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
268 err = td_thr_get_info (th_p, &info);
269 assert (err == TD_OK);
270 printf ("LWP = %ld TID = 0x%lx\n", (long) info.ti_lid, info.ti_tid);
275 static void thread_test (td_thragent_t *thread_agent)
279 err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL,
280 TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
281 TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
284 fprintf (stderr, "err = %d\n", err);
289 static void attach (pid_t pid)
292 td_thragent_t *thread_agent;
293 struct ps_prochandle proc_handle_local;
296 assert (err == TD_OK);
298 proc_handle_local.pid = pid;
299 proc_handle_local.dwfl = NULL;
300 err = td_ta_new (&proc_handle_local, &thread_agent);
301 assert (err == TD_OK || err == TD_NOLIBTHREAD);
302 if (err == TD_NOLIBTHREAD)
303 puts ("singlethreaded");
306 puts ("multithreaded");
307 thread_test (thread_agent);
308 err = td_ta_delete (thread_agent);
309 assert (err == TD_OK);
311 if (proc_handle_local.dwfl != NULL);
312 dwfl_end (proc_handle_local.dwfl);
315 static void *start (void *arg)
322 static __attribute__((__noreturn__)) void syntax (void)
324 puts ("threadtest {<pid>|multi|single}");
328 int main (int argc, char **argv)
332 if (strcmp (argv[1], "single") == 0)
334 else if (strcmp (argv[1], "multi") == 0)
337 int (*pthread_create_pointer) (pthread_t *thread,
338 const pthread_attr_t *attr,
339 void *(*start_routine) (void *),
344 /* Do not access pthread_create () directly as we would need to link
345 `-lpthread' and we could never provide the `single' option. */
346 handle = dlopen ("libpthread.so.0", RTLD_LAZY);
347 assert (handle != NULL);
348 pthread_create_pointer = dlsym (handle, "pthread_create");
349 assert (pthread_create_pointer != NULL);
351 i = (*pthread_create_pointer) (&thread, NULL, start, NULL);
353 i = (*pthread_create_pointer) (&thread, NULL, start, NULL);
361 long pidl = strtol (argv[1], &endptr, 0);
363 if (pidl < 0 || (pid_t) pidl != pidl || (endptr != NULL && *endptr != 0))