Fixed attaching to commands with invalid shared library symbols count.
[debugger.git] / debugger.c
1 /* Copyright 2007, Red Hat Inc.  */
2
3 #define _GNU_SOURCE 1
4 #define ps_prochandle attach_state_struct
5
6 #include <unistd.h>
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <signal.h>
10 #include <errno.h>
11 #include <stdio.h>
12 #include <sys/ptrace.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15 #include <limits.h>
16 #include <string.h>
17 #include <time.h>
18 #include <sys/reg.h>
19 #include <linux/ptrace.h>
20 #include <asm/prctl.h>
21 #include <elfutils/libdwfl.h>
22 #include <thread_db.h>
23 #include <fcntl.h>
24
25 #include "debugger.h"
26
27
28 /* Insert constant delay for before each critical check?  */
29 #if 0
30 #define USLEEP (1000000 / 2)
31 #endif
32
33 #if 1   /* Standard run.  */
34 #define TIMEOUT_SECS 4
35 #define LOOPS_MIN 100000
36 #else   /* QEMU?  */
37 /* LOOPS_MIN is a safety as QEMU clock time sucks.
38    100000 is 4s natively and 53s in QEMU.  */
39 #define TIMEOUT_SECS 20
40 #define LOOPS_MIN 500000
41 #endif  /* QEMU?  */
42
43
44 #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
45
46 void delay (void)
47 {
48 #ifdef USLEEP
49   int i;
50
51   i = usleep (USLEEP);
52   assert (i == 0);
53 #endif
54 }
55
56 static __attribute__((__noreturn__)) void crash (void)
57 {
58 #if 0
59   void *array[0x100];
60   int count;
61 #endif
62   char command[256];
63
64   fputs (">>> CRASH START\n", stderr);
65 #if 0
66   count = backtrace (array, ARRAY_SIZE (array));
67   backtrace_symbols_fd (array, count, STDERR_FILENO);
68 #endif
69   snprintf (command, sizeof (command), "echo -e \"bt\\nquit\""
70             " >/tmp/debugger.%d; gdb --batch -nx --command=/tmp/debugger.%d"
71             " /proc/%d/exe %d </dev/null;rm -f /tmp/debugger.%d",
72             (int) getpid(), (int) getpid(), (int) getpid(), (int) getpid(),
73             (int) getpid());
74   system (command);
75   fputs (">>> CRASH FINISH\n", stderr);
76   abort ();
77 }
78
79 enum state
80   {
81     /* Separate the valid `1 << enum state' and `enum state' ranges.  */
82     STATE_FIRST = 4,
83     STATE_INSTABLE,
84     STATE_ENOENT,
85     STATE_SLEEPING,
86     STATE_RUNNING,
87     STATE_STOPPED,
88     STATE_PTRACED,
89     STATE_ZOMBIE,
90     STATE_DEAD,
91     STATE_LAST
92   };
93
94 static const char *state_to_name (enum state state)
95 {
96   switch (state)
97     {
98       case STATE_INSTABLE: return "STATE_INSTABLE";
99       case STATE_ENOENT:   return "STATE_ENOENT";
100       case STATE_SLEEPING: return "STATE_SLEEPING";
101       case STATE_RUNNING:  return "STATE_RUNNING";
102       case STATE_STOPPED:  return "STATE_STOPPED";
103       case STATE_PTRACED:  return "STATE_PTRACED";
104       case STATE_ZOMBIE:   return "STATE_ZOMBIE";
105       case STATE_DEAD:     return "STATE_DEAD";
106       default: crash ();
107     }
108   /* NOTREACHED */
109   crash ();
110 }
111
112 static enum state state_get (pid_t pid)
113 {
114   char status_name[32];
115   char line[LINE_MAX];
116   FILE *f;
117   enum state found;
118
119   delay ();
120
121   snprintf (status_name, sizeof (status_name), "/proc/%d/status", (int) pid);
122   f = fopen (status_name, "r");
123   if (f == NULL && errno == ENOENT)
124     found = STATE_ENOENT;
125   else if (f == NULL)
126     {
127       fprintf (stderr, "errno = %d\n", errno);
128       crash ();
129     }
130   else
131     {
132       int i;
133
134       found = STATE_INSTABLE;
135       while (errno = 0, fgets (line, sizeof (line), f) != NULL)
136         {
137           const char *const string = "State:\t";
138           const size_t length = sizeof "State:\t" - 1;
139
140           if (strncmp (line, string, length) != 0)
141             continue;
142           if (strcmp (line + length, "S (sleeping)\n") == 0)
143             found = STATE_SLEEPING;
144           else if (strcmp (line + length, "R (running)\n") == 0)
145             found = STATE_RUNNING;
146           else if (strcmp (line + length, "T (stopped)\n") == 0)
147             found = STATE_STOPPED;
148           else if (strcmp (line + length, "T (tracing stop)\n") == 0)
149             found = STATE_PTRACED;
150           else if (strcmp (line + length, "Z (zombie)\n") == 0)
151             found = STATE_ZOMBIE;
152           /* FIXME: What does it mean?  */
153           else if (strcmp (line + length, "X (dead)\n") == 0)
154             found = STATE_DEAD;
155           else
156             {
157               fprintf (stderr, "Found an unknown state: %s", line + length);
158               crash ();
159             }
160         }
161       assert (found != STATE_INSTABLE || errno == ESRCH);
162       i = fclose (f);
163       assert (i == 0);
164     }
165   return found;
166 }
167
168 #define STATE(pid, expect_mask) state ((pid), (expect_mask), #expect_mask )
169
170 static enum state state (pid_t pid, unsigned expect_mask, const char *expect_mask_string)
171 {
172   enum state found;
173   time_t timeout = time (NULL) + TIMEOUT_SECS;
174   unsigned loops = 0;
175
176   /* Sanity check `1 << enum state' was not misplaced with `enum state'.  */
177   assert (1 << (STATE_FIRST + 1) >= STATE_LAST);
178   assert (expect_mask != 0);
179 #define MASK_UNDER_EXCLUSIVE(bit) ((1 << (bit)) - 1)
180 #define MASK_ABOVE_INCLUSIVE(bit) (~MASK_UNDER_EXCLUSIVE (bit))
181   assert ((expect_mask & MASK_UNDER_EXCLUSIVE (STATE_FIRST + 1)) == 0);
182   assert ((expect_mask & MASK_ABOVE_INCLUSIVE (STATE_LAST)) == 0);
183 #undef MASK_ABOVE_INCLUSIVE
184 #undef MASK_UNDER_EXCLUSIVE
185
186   do
187     {
188       found = state_get (pid);
189
190       if (((1 << found) & expect_mask) != 0)
191         return found;
192     }
193   while (loops++ < LOOPS_MIN || time (NULL) < timeout);
194
195   fprintf (stderr, "Found for PID %d state %s but expecting (%s)\n",
196            (int) pid, state_to_name (found), expect_mask_string);
197   crash ();
198 }
199
200 struct attach_state_struct
201   {
202     pid_t pid;
203     Dwfl *dwfl;
204     int stopped;
205     td_thragent_t *thread_agent;
206     /* Debugging only: Number of signal needing redelivery on PTRACE_ATTACH.  */
207     int redelivered;
208     int threads_count;
209   };
210
211 int attach_state_redelivered_get (struct attach_state_struct *attach_state)
212 {
213   assert (attach_state != NULL);
214
215   return attach_state->redelivered;
216 }
217
218 int attach_state_threads_count_get (struct attach_state_struct *attach_state)
219 {
220   assert (attach_state != NULL);
221
222   return attach_state->threads_count;
223 }
224
225 int attach_state_stopped_get (struct attach_state_struct *attach_state)
226 {
227   assert (attach_state != NULL);
228
229   return attach_state->stopped;
230 }
231
232 pid_t attach_state_pid_get (struct attach_state_struct *attach_state)
233 {
234   assert (attach_state != NULL);
235
236   return attach_state->pid;
237 }
238
239 struct attach_state_struct *attach_single (pid_t pid)
240 {
241   int i;
242   int status;
243   struct attach_state_struct *attach_state;
244
245   attach_state = malloc (sizeof (*attach_state));
246   assert (attach_state != NULL);
247   attach_state->pid = pid;
248   attach_state->dwfl = NULL;
249   attach_state->redelivered = 0;
250   attach_state->threads_count = -1;
251
252   delay ();
253
254   attach_state->stopped = (STATE (pid, (1 << STATE_SLEEPING)
255                                        | (1 << STATE_RUNNING)
256                                        | (1 << STATE_STOPPED))
257                            == STATE_STOPPED);
258
259   i = ptrace (PTRACE_ATTACH, pid, NULL, NULL);
260   assert (i == 0);
261
262   /* FIXME: Why it does not work?
263      Disable also the STATE () call above.  */
264 #if 0
265   delay();
266
267   i = ptrace (PTRACE_CONT, pid, (void *) 1, (void *) SIGSTOP);
268   /* `STOPPED == 1' may be false, even if the process was not stopped.  */
269   if (i == 0)
270     attach_state->stopped = 1;
271   else if (errno == ESRCH)
272     attach_state->stopped = 0;
273   else
274     crash ();
275 #endif
276
277   for (;;)
278     {
279       delay ();
280
281       i = waitpid (pid, &status, 0);
282       assert (i == pid);
283       if (!WIFSTOPPED (status))
284         {
285           /* Process may have exited.  */
286           fprintf (stderr, "PID %d waitpid(2) status %d\n", (int) pid,
287                    status);
288           exit (EXIT_FAILURE);
289         }
290       if (WSTOPSIG (status) == SIGSTOP)
291         break;
292
293       if (attach_state->redelivered == 0)
294         attach_state->redelivered = WSTOPSIG (status);
295       else
296         attach_state->redelivered = -1;
297
298       delay ();
299
300       /* Re-deliver the signal received before SIGSTOP.
301          It happens with about only 1:200000 probability.  */
302       i = ptrace (PTRACE_CONT, pid, (void *) 1,
303                   (void *) (unsigned long) WSTOPSIG (status));
304       assert (i == 0);
305     }
306
307   return attach_state;
308 }
309
310 void detach_single (struct attach_state_struct *attach_state)
311 {
312   int i;
313
314   delay ();
315
316   i = ptrace (PTRACE_DETACH, attach_state->pid, NULL,
317               (void *) (unsigned long) (attach_state->stopped ? SIGSTOP : 0));
318   assert (i == 0);
319
320   delay ();
321 }
322
323 static Dwfl *get_dwfl (struct ps_prochandle *proc_handle)
324 {
325   static char *debuginfo_path;
326
327   static const Dwfl_Callbacks proc_callbacks =
328    {
329      .find_debuginfo = dwfl_standard_find_debuginfo,
330      .debuginfo_path = &debuginfo_path,
331
332      .find_elf = dwfl_linux_proc_find_elf,
333    };
334
335   if (proc_handle->dwfl == NULL)
336     {
337       proc_handle->dwfl = dwfl_begin (&proc_callbacks);
338       assert (proc_handle->dwfl != NULL);
339
340       errno = 0;
341       if (dwfl_linux_proc_report (proc_handle->dwfl, proc_handle->pid) != 0
342          || dwfl_report_end (proc_handle->dwfl, NULL, NULL) != 0)
343         {
344           fprintf (stderr, "dwfl reporting: %m\n");
345           abort ();
346         }
347     }
348   return proc_handle->dwfl;
349 }
350
351 /* Functions in this interface return one of these status codes.  */
352 typedef enum
353 {
354   PS_OK,                /* Generic "call succeeded".  */
355   PS_ERR,               /* Generic error. */
356   PS_BADPID,            /* Bad process handle.  */
357   PS_BADLID,            /* Bad LWP identifier.  */ 
358   PS_BADADDR,           /* Bad address.  */
359   PS_NOSYM,             /* Could not find given symbol.  */
360   PS_NOFREGS            /* FPU register set not available for given LWP.  */
361 } ps_err_e;
362
363 ps_err_e ps_pdread (struct ps_prochandle *proc_handle, psaddr_t addr,
364                     void *buffer, size_t length)
365 {
366   pid_t pid = proc_handle->pid;
367   char filename[64];
368   int fd;
369
370   if (pid == getpid ())
371     {
372       memcpy (buffer, addr, length);
373       return PS_OK;
374     }
375
376 /* Already under PTRACE_ATTACH.  */
377 #if 0
378   if (ptrace (PTRACE_ATTACH, pid, NULL, NULL) != 0)
379     abort ();
380   if (waitpid (pid, NULL, 0) != pid)
381     abort ();
382 #endif
383
384   snprintf (filename, sizeof (filename), "/proc/%ld/mem", (long) pid);
385   fd = open (filename, O_RDONLY);
386   assert (fd != -1);
387   if (lseek64 (fd, (off64_t) addr, SEEK_SET) != (off64_t) addr)
388     abort ();
389   if (read (fd, buffer, length) != length)
390     {
391       /* It occurs for singlethreaded processes.  */
392       if ((off64_t) addr == 0)
393         return PS_ERR;
394       fprintf (stderr, "read() error @0x%lx length %lu: %m\n",
395                (unsigned long) addr, (unsigned long) length);
396       abort ();
397     }
398   if (close (fd) != 0)
399     abort ();
400
401 /* Already under PTRACE_ATTACH.  */
402 #if 0
403   if (ptrace (PTRACE_DETACH, pid, NULL, NULL) != 0)
404     abort ();
405 #endif
406
407   return PS_OK;
408 }
409
410 ps_err_e ps_pdwrite (struct ps_prochandle *proc_handle, psaddr_t addr,
411                      const void *buffer, size_t length)
412 {
413   crash ();
414 }
415
416 ps_err_e ps_lgetregs (struct ps_prochandle *proc_handle, lwpid_t lwp,
417                       prgregset_t regs)
418 {
419   crash ();
420 }
421
422 ps_err_e ps_lsetregs (struct ps_prochandle *proc_handle, lwpid_t lwp,
423                       const prgregset_t regs)
424 {
425   crash ();
426 }
427
428 ps_err_e ps_lgetfpregs (struct ps_prochandle *proc_handle, lwpid_t lwp,
429                         prfpregset_t *fpregs)
430 {
431   crash ();
432 }
433
434 ps_err_e ps_lsetfpregs (struct ps_prochandle *proc_handle, lwpid_t lwp,
435                         const prfpregset_t *fpregs)
436 {
437   crash ();
438 }
439
440 /* Return the PID of the process.  */
441 pid_t ps_getpid (struct ps_prochandle *proc_handle)
442 {
443   return proc_handle->pid;
444 }
445
446 struct getmodules_callback_arg
447   {
448     const char *sym_name;
449     psaddr_t *sym_addr;
450     ps_err_e retval;
451   };
452
453 static int getmodules_callback (Dwfl_Module *module,
454                                 void **module_userdata_pointer,
455                                 const char *module_name,
456                                 Dwarf_Addr module_low_addr, void *arg)
457 {
458   struct getmodules_callback_arg *getmodules_callback_arg = arg;
459   int sym_count, ndx;
460   GElf_Sym sym;
461
462   sym_count = dwfl_module_getsymtab (module);
463   if (sym_count == -1)
464     return DWARF_CB_OK;
465   assert (sym_count >= 0);
466
467   for (ndx = 0; ndx < sym_count; ndx++)
468     {
469       const char *name_got;
470
471       name_got = dwfl_module_getsym (module, ndx, &sym,
472                                      NULL);
473       assert (name_got != NULL);
474       if (strcmp (name_got, getmodules_callback_arg->sym_name) == 0)
475         break;
476     }
477   if (ndx == sym_count)
478     return DWARF_CB_OK;
479
480   *getmodules_callback_arg->sym_addr = (psaddr_t) sym.st_value;
481   getmodules_callback_arg->retval = PS_OK;
482
483   return DWARF_CB_OK;
484 }
485
486 /* Look up the named symbol in the named DSO in the symbol tables
487    associated with the process being debugged, filling in *SYM_ADDR
488    with the corresponding run-time address.  */
489 ps_err_e ps_pglobal_lookup (struct ps_prochandle *proc_handle,
490                             const char *object_name, const char *sym_name,
491                             psaddr_t *sym_addr)
492 {
493   Dwfl *dwfl = get_dwfl (proc_handle);
494   struct getmodules_callback_arg getmodules_callback_arg;
495   ptrdiff_t err_ptrdiff;
496
497   /* FIXME: `object_name' ignored due to missing unresolving of shared
498      libraries symbolic links.  */
499   getmodules_callback_arg.sym_name = sym_name;
500   getmodules_callback_arg.sym_addr = sym_addr;
501   getmodules_callback_arg.retval = PS_NOSYM;
502   err_ptrdiff = dwfl_getmodules (dwfl, getmodules_callback,
503                                  &getmodules_callback_arg, 0);
504   assert (err_ptrdiff == 0);
505   return getmodules_callback_arg.retval;
506 }
507
508 #ifdef __x86_64__
509 ps_err_e ps_get_thread_area (const struct ps_prochandle *ph, lwpid_t lwpid,
510                              int idx, void **base)
511 {
512   long val;
513
514   assert (idx == FS || idx == GS);
515
516   if (ptrace (PTRACE_ATTACH, lwpid, NULL, NULL) != 0)
517     abort ();
518   if (waitpid (lwpid, NULL, 0) != lwpid)
519     abort ();
520
521   val = ptrace (PTRACE_ARCH_PRCTL, lwpid, base, (idx == FS ? ARCH_GET_FS
522                                                            : ARCH_GET_GS));
523
524   if (ptrace (PTRACE_DETACH, lwpid, NULL, NULL) != 0)
525     abort ();
526
527   if (val != 0)
528     {
529       fprintf (stderr, "PTRACE_ARCH_PRCTL (%s): %m\n", (idx == FS ? "FS"
530                                                                   : "GS"));
531       return PS_ERR;
532     }
533
534   return PS_OK;
535 }
536 #else
537 #error "Unsupported ps_get_thread_area ()!"
538 #endif
539
540 static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
541 {
542   td_err_e err;
543   td_thrinfo_t info;
544   struct attach_state_struct *attach_state = data;
545
546   err = td_thr_get_info (th_p, &info);
547   assert (err == TD_OK);
548   /* printf ("LWP = %ld TID = 0x%lx\n", (long) info.ti_lid, info.ti_tid);  */
549
550   attach_state->threads_count++;
551
552   return 0;
553 }
554
555 static void attach_multi (struct attach_state_struct *attach_state)
556 {
557   td_err_e err;
558
559   err = td_init ();
560   assert (err == TD_OK);
561
562   err = td_ta_new (attach_state, &attach_state->thread_agent);
563   assert (err == TD_OK || err == TD_NOLIBTHREAD);
564   attach_state->threads_count = 0;
565   if (err == TD_NOLIBTHREAD)
566     {
567       attach_state->thread_agent = NULL;
568       return;
569     }
570   assert (attach_state->thread_agent != NULL);
571   /* Multithreading test:  */
572   err = td_ta_thr_iter (attach_state->thread_agent, find_new_threads_callback,
573                         attach_state, TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
574                         TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
575   if (err != TD_OK)
576     {
577       fprintf (stderr, "err = %d\n", err);
578       abort ();
579     }
580   assert (attach_state->threads_count > 0);
581 }
582
583 struct attach_state_struct *attach (pid_t pid)
584 {
585   struct attach_state_struct *attach_state;
586
587   attach_state = attach_single (pid);
588   attach_multi (attach_state);
589
590   return attach_state;
591 }
592
593 void detach (struct attach_state_struct *attach_state)
594 {
595   if (attach_state->thread_agent != NULL)
596     {
597       td_err_e err;
598
599       err = td_ta_delete (attach_state->thread_agent);
600       assert (err == TD_OK);
601     }
602   if (attach_state->dwfl != NULL);
603     dwfl_end (attach_state->dwfl);
604
605   detach_single (attach_state);
606 }
607
608 #ifndef LIBRARY
609
610 int main (int argc, char **argv)
611 {
612   pid_t pid;
613   struct attach_state_struct *attach_state;
614
615   if (argc != 2)
616     {
617       fprintf (stderr, "Usage: %s <PID>\n", argv[0]);
618       exit (EXIT_FAILURE);
619     }
620
621   pid = atoi (argv[1]);
622
623   attach_state = attach (pid);
624   detach (attach_state);
625
626   return EXIT_SUCCESS;
627 }
628
629 #endif /* !LIBRARY */