Sun Aug 30 00:49:18 1998 Martin M. Hunt <hunt@cygnus.com>
[external/binutils.git] / gdb / thread.c
1 /* Multi-process/thread control for GDB, the GNU debugger.
2    Copyright 1986, 1987, 1988, 1993
3
4    Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
5    Free Software Foundation, Inc.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
22
23 #include "defs.h"
24 #include "symtab.h"
25 #include "frame.h"
26 #include "inferior.h"
27 #include "environ.h"
28 #include "value.h"
29 #include "target.h"
30 #include "gdbthread.h"
31 #include "command.h"
32 #include "gdbcmd.h"
33
34 #include <ctype.h>
35 #include <sys/types.h>
36 #include <signal.h>
37
38 /*#include "lynxos-core.h"*/
39
40 struct thread_info
41 {
42   struct thread_info *next;
43   int pid;                      /* Actual process id */
44   int num;                      /* Convenient handle */
45   CORE_ADDR prev_pc;            /* State from wait_for_inferior */
46   CORE_ADDR prev_func_start;
47   char *prev_func_name;
48   struct breakpoint *step_resume_breakpoint;
49   struct breakpoint *through_sigtramp_breakpoint;
50   CORE_ADDR step_range_start;
51   CORE_ADDR step_range_end;
52   CORE_ADDR step_frame_address;
53   int trap_expected;
54   int handling_longjmp;
55   int another_trap;
56 };
57
58 static struct thread_info *thread_list = NULL;
59 static int highest_thread_num;
60
61 static void
62 thread_command PARAMS ((char * tidstr, int from_tty));
63
64 static void
65 prune_threads PARAMS ((void));
66
67 static void
68 switch_to_thread PARAMS ((int pid));
69
70 static struct thread_info *
71 find_thread_id PARAMS ((int num));
72
73 static void
74 info_threads_command PARAMS ((char *, int));
75
76 static void
77 restore_current_thread PARAMS ((int));
78
79 static void
80 thread_apply_all_command PARAMS ((char *, int));
81
82 static void
83 thread_apply_command PARAMS ((char *, int));
84
85 void
86 init_thread_list ()
87 {
88   struct thread_info *tp, *tpnext;
89
90   if (!thread_list)
91     return;
92
93   for (tp = thread_list; tp; tp = tpnext)
94     {
95       tpnext = tp->next;
96       free (tp);
97     }
98
99   thread_list = NULL;
100   highest_thread_num = 0;
101 }
102
103 void
104 add_thread (pid)
105      int pid;
106 {
107   struct thread_info *tp;
108
109   tp = (struct thread_info *) xmalloc (sizeof (struct thread_info));
110
111   tp->pid = pid;
112   tp->num = ++highest_thread_num;
113   tp->prev_pc = 0;
114   tp->prev_func_start = 0;
115   tp->prev_func_name = NULL;
116   tp->step_range_start = 0;
117   tp->step_range_end = 0;
118   tp->step_frame_address =0;
119   tp->step_resume_breakpoint = 0;
120   tp->through_sigtramp_breakpoint = 0;
121   tp->handling_longjmp = 0;
122   tp->trap_expected = 0;
123   tp->another_trap = 0;
124   tp->next = thread_list;
125   thread_list = tp;
126 }
127
128 void
129 delete_thread (pid)
130      int pid;
131 {
132   struct thread_info *tp, *tpprev;
133
134   tpprev = NULL;
135
136   for (tp = thread_list; tp; tpprev = tp, tp = tp->next)
137     if (tp->pid == pid)
138       break;
139
140   if (!tp)
141     return;
142
143   if (tpprev)
144     tpprev->next = tp->next;
145   else
146     thread_list = tp->next;
147
148   free (tp);
149
150   return;
151 }
152
153 static struct thread_info *
154 find_thread_id (num)
155     int num;
156 {
157   struct thread_info *tp;
158
159   for (tp = thread_list; tp; tp = tp->next)
160     if (tp->num == num)
161       return tp;
162
163   return NULL;
164 }
165
166 int
167 valid_thread_id (num)
168     int num;
169 {
170   struct thread_info *tp;
171
172   for (tp = thread_list; tp; tp = tp->next)
173     if (tp->num == num)
174       return 1;
175
176   return 0;
177 }
178
179 int
180 pid_to_thread_id (pid)
181     int pid;
182 {
183   struct thread_info *tp;
184
185   for (tp = thread_list; tp; tp = tp->next)
186     if (tp->pid == pid)
187       return tp->num;
188
189   return 0;
190 }
191
192 int
193 thread_id_to_pid (num)
194     int num;
195 {
196   struct thread_info *thread = find_thread_id (num);
197   if (thread)
198     return thread->pid;
199   else
200     return -1;
201 }
202
203 int
204 in_thread_list (pid)
205     int pid;
206 {
207   struct thread_info *tp;
208
209   for (tp = thread_list; tp; tp = tp->next)
210     if (tp->pid == pid)
211       return 1;
212
213   return 0;                     /* Never heard of 'im */
214 }
215
216 /* Load infrun state for the thread PID.  */
217
218 void load_infrun_state (pid, prev_pc, prev_func_start, prev_func_name,
219                         trap_expected, step_resume_breakpoint,
220                         through_sigtramp_breakpoint, step_range_start,
221                         step_range_end, step_frame_address,
222                         handling_longjmp, another_trap)
223      int pid;
224      CORE_ADDR *prev_pc;
225      CORE_ADDR *prev_func_start;
226      char **prev_func_name;
227      int *trap_expected;
228      struct breakpoint **step_resume_breakpoint;
229      struct breakpoint **through_sigtramp_breakpoint;
230      CORE_ADDR *step_range_start;
231      CORE_ADDR *step_range_end;
232      CORE_ADDR *step_frame_address;
233      int *handling_longjmp;
234      int *another_trap;
235 {
236   struct thread_info *tp;
237
238   /* If we can't find the thread, then we're debugging a single threaded
239      process.  No need to do anything in that case.  */
240   tp = find_thread_id (pid_to_thread_id (pid));
241   if (tp == NULL)
242     return;
243
244   *prev_pc = tp->prev_pc;
245   *prev_func_start = tp->prev_func_start;
246   *prev_func_name = tp->prev_func_name;
247   *step_resume_breakpoint = tp->step_resume_breakpoint;
248   *step_range_start = tp->step_range_start;
249   *step_range_end = tp->step_range_end;
250   *step_frame_address = tp->step_frame_address;
251   *through_sigtramp_breakpoint = tp->through_sigtramp_breakpoint;
252   *handling_longjmp = tp->handling_longjmp;
253   *trap_expected = tp->trap_expected;
254   *another_trap = tp->another_trap;
255 }
256
257 /* Save infrun state for the thread PID.  */
258
259 void save_infrun_state (pid, prev_pc, prev_func_start, prev_func_name,
260                         trap_expected, step_resume_breakpoint,
261                         through_sigtramp_breakpoint, step_range_start,
262                         step_range_end, step_frame_address,
263                         handling_longjmp, another_trap)
264      int pid;
265      CORE_ADDR prev_pc;
266      CORE_ADDR prev_func_start;
267      char *prev_func_name;
268      int trap_expected;
269      struct breakpoint *step_resume_breakpoint;
270      struct breakpoint *through_sigtramp_breakpoint;
271      CORE_ADDR step_range_start;
272      CORE_ADDR step_range_end;
273      CORE_ADDR step_frame_address;
274      int handling_longjmp;
275      int another_trap;
276 {
277   struct thread_info *tp;
278
279   /* If we can't find the thread, then we're debugging a single-threaded
280      process.  Nothing to do in that case.  */
281   tp = find_thread_id (pid_to_thread_id (pid));
282   if (tp == NULL)
283     return;
284
285   tp->prev_pc = prev_pc;
286   tp->prev_func_start = prev_func_start;
287   tp->prev_func_name = prev_func_name;
288   tp->step_resume_breakpoint = step_resume_breakpoint;
289   tp->step_range_start = step_range_start;
290   tp->step_range_end = step_range_end;
291   tp->step_frame_address = step_frame_address;
292   tp->through_sigtramp_breakpoint = through_sigtramp_breakpoint;
293   tp->handling_longjmp = handling_longjmp;
294   tp->trap_expected = trap_expected;
295   tp->another_trap = another_trap;
296 }
297
298 /* Return true if TP is an active thread. */
299 static int
300 thread_alive (tp)
301      struct thread_info *tp;
302 {
303   if (tp->pid == -1)
304     return 0;
305   if (! target_thread_alive (tp->pid))
306     {
307       tp->pid = -1;     /* Mark it as dead */
308       return 0;
309     }
310   return 1;
311 }
312
313 static void
314 prune_threads ()
315 {
316   struct thread_info *tp, *tpprev, *next;
317
318   tpprev = 0;
319   for (tp = thread_list; tp; tp = next)
320     {
321       next = tp->next;
322       if (!thread_alive (tp))
323         {
324           if (tpprev)
325             tpprev->next = next;
326           else
327             thread_list  = next;
328           free (tp);
329         }
330       else
331         tpprev = tp;
332     }
333 }
334
335 /* Print information about currently known threads */
336
337 static void
338 info_threads_command (arg, from_tty)
339      char *arg;
340      int from_tty;
341 {
342   struct thread_info *tp;
343   int current_pid = inferior_pid;
344
345   /* Avoid coredumps which would happen if we tried to access a NULL
346      selected_frame.  */
347   if (!target_has_stack) error ("No stack.");
348
349   prune_threads ();
350 #if defined(FIND_NEW_THREADS)
351   FIND_NEW_THREADS ();
352 #endif
353
354   for (tp = thread_list; tp; tp = tp->next)
355     {
356       if (tp->pid == current_pid)
357         printf_filtered ("* ");
358       else
359         printf_filtered ("  ");
360
361       printf_filtered ("%d %s  ", tp->num, target_pid_to_str (tp->pid));
362
363       switch_to_thread (tp->pid);
364       if (selected_frame)
365         print_stack_frame (selected_frame, -1, 0);
366       else
367         printf_filtered ("[No stack.]\n");
368     }
369
370   switch_to_thread (current_pid);
371 }
372
373 /* Switch from one thread to another. */
374
375 static void
376 switch_to_thread (pid)
377      int pid;
378 {
379   if (pid == inferior_pid)
380     return;
381
382   inferior_pid = pid;
383   flush_cached_frames ();
384   registers_changed ();
385   stop_pc = read_pc();
386   select_frame (get_current_frame (), 0);
387 }
388
389 static void
390 restore_current_thread (pid)
391      int pid;
392 {
393   if (pid != inferior_pid)
394     switch_to_thread (pid);
395 }
396
397 /* Apply a GDB command to a list of threads.  List syntax is a whitespace
398    seperated list of numbers, or ranges, or the keyword `all'.  Ranges consist
399    of two numbers seperated by a hyphen.  Examples:
400
401         thread apply 1 2 7 4 backtrace  Apply backtrace cmd to threads 1,2,7,4
402         thread apply 2-7 9 p foo(1)     Apply p foo(1) cmd to threads 2->7 & 9
403         thread apply all p x/i $pc      Apply x/i $pc cmd to all threads
404 */
405
406 static void
407 thread_apply_all_command (cmd, from_tty)
408      char *cmd;
409      int from_tty;
410 {
411   struct thread_info *tp;
412   struct cleanup *old_chain;
413
414   if (cmd == NULL || *cmd == '\000')
415     error ("Please specify a command following the thread ID list");
416
417   old_chain = make_cleanup (restore_current_thread, inferior_pid);
418
419   for (tp = thread_list; tp; tp = tp->next)
420     if (thread_alive (tp))
421       {
422         switch_to_thread (tp->pid);
423         printf_filtered ("\nThread %d (%s):\n", tp->num,
424                          target_pid_to_str (inferior_pid));
425         execute_command (cmd, from_tty);
426       }
427 }
428
429 static void
430 thread_apply_command (tidlist, from_tty)
431      char *tidlist;
432      int from_tty;
433 {
434   char *cmd;
435   char *p;
436   struct cleanup *old_chain;
437
438   if (tidlist == NULL || *tidlist == '\000')
439     error ("Please specify a thread ID list");
440
441   for (cmd = tidlist; *cmd != '\000' && !isalpha(*cmd); cmd++);
442
443   if (*cmd == '\000')
444     error ("Please specify a command following the thread ID list");
445
446   old_chain = make_cleanup (restore_current_thread, inferior_pid);
447
448   while (tidlist < cmd)
449     {
450       struct thread_info *tp;
451       int start, end;
452
453       start = strtol (tidlist, &p, 10);
454       if (p == tidlist)
455         error ("Error parsing %s", tidlist);
456       tidlist = p;
457
458       while (*tidlist == ' ' || *tidlist == '\t')
459         tidlist++;
460
461       if (*tidlist == '-')      /* Got a range of IDs? */
462         {
463           tidlist++;    /* Skip the - */
464           end = strtol (tidlist, &p, 10);
465           if (p == tidlist)
466             error ("Error parsing %s", tidlist);
467           tidlist = p;
468
469           while (*tidlist == ' ' || *tidlist == '\t')
470             tidlist++;
471         }
472       else
473         end = start;
474
475       for (; start <= end; start++)
476         {
477           tp = find_thread_id (start);
478
479           if (!tp)
480             warning ("Unknown thread %d.", start);
481           else if (!thread_alive (tp))
482             warning ("Thread %d has terminated.", start);
483           else
484             {
485               switch_to_thread (tp->pid);
486               printf_filtered ("\nThread %d (%s):\n", tp->num,
487                                target_pid_to_str (inferior_pid));
488               execute_command (cmd, from_tty);
489             }
490         }
491     }
492 }
493
494 /* Switch to the specified thread.  Will dispatch off to thread_apply_command
495    if prefix of arg is `apply'.  */
496
497 static void
498 thread_command (tidstr, from_tty)
499      char *tidstr;
500      int from_tty;
501 {
502   int num;
503   struct thread_info *tp;
504
505   if (!tidstr)
506     error ("Please specify a thread ID.  Use the \"info threads\" command to\n\
507 see the IDs of currently known threads.");
508
509   num = atoi (tidstr);
510
511   tp = find_thread_id (num);
512
513   if (!tp)
514     error ("Thread ID %d not known.  Use the \"info threads\" command to\n\
515 see the IDs of currently known threads.", num);
516
517   if (!thread_alive (tp))
518     error ("Thread ID %d has terminated.\n", num);
519
520   switch_to_thread (tp->pid);
521   if (context_hook)
522     context_hook (num);
523   printf_filtered ("[Switching to %s]\n", target_pid_to_str (inferior_pid));
524   print_stack_frame (selected_frame, selected_frame_level, 1);
525 }
526
527 /* Commands with a prefix of `thread'.  */
528 struct cmd_list_element *thread_cmd_list = NULL;
529
530 void
531 _initialize_thread ()
532 {
533   static struct cmd_list_element *thread_apply_list = NULL;
534   extern struct cmd_list_element *cmdlist;
535
536   add_info ("threads", info_threads_command,
537             "IDs of currently known threads.");
538
539   add_prefix_cmd ("thread", class_run, thread_command,
540                   "Use this command to switch between threads.\n\
541 The new thread ID must be currently known.", &thread_cmd_list, "thread ", 1,
542                   &cmdlist);
543
544   add_prefix_cmd ("apply", class_run, thread_apply_command,
545                   "Apply a command to a list of threads.",
546                   &thread_apply_list, "apply ", 1, &thread_cmd_list);
547
548   add_cmd ("all", class_run, thread_apply_all_command,
549            "Apply a command to all threads.",
550            &thread_apply_list);
551
552   add_com_alias ("t", "thread", class_run, 1);
553 }