1 /* Multi-process/thread control for GDB, the GNU debugger.
2 Copyright 1986, 1987, 1988, 1993, 1998
4 Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
5 Free Software Foundation, Inc.
7 This file is part of GDB.
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.
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.
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. */
30 #include "gdbthread.h"
35 #include <sys/types.h>
38 /*#include "lynxos-core.h"*/
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;
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;
60 static struct target_thread_vector *target_thread_functions;
63 target_find_new_threads ()
66 if (target_thread_functions &&
67 target_thread_functions->find_new_threads)
68 retval = (*(target_thread_functions->find_new_threads)) ();
69 return retval; /* no support */
74 target_get_thread_info PARAMS ((
76 int selection, /* FIXME: Selection */
77 struct gdb_ext_thread_info * info));
80 target_get_thread_info (ref, selection, info)
84 /* FIXME: Selection */
85 struct gdb_ext_thread_info *info;
89 if (target_thread_functions
90 && target_thread_functions->get_thread_info)
91 retval = (*(target_thread_functions->get_thread_info)) (ref, selection, info);
96 /* It is possible that these bind and unbinf functions implement a
97 stack the interface allows it, but its not implemented that way
102 bind_target_thread_vector (vec)
103 struct target_thread_vector *vec;
105 target_thread_functions = vec;
107 /* Prototypes for exported functions. */
109 struct target_thread_vector *
110 unbind_target_thread_vector ()
112 struct target_thread_vector *retval;
113 retval = target_thread_functions;
114 target_thread_functions = 0;
116 } /* unbind_target_thread-vector */
118 void _initialize_thread PARAMS ((void));
121 /* Prototypes for local functions. */
122 /* If the host has threads, the host machine definition may
123 set this macro. But, for remote thread debugging, it gets more
124 complex and setting macros does not bind to the various target
125 dependent methods well. So, we use the vector target_thread_functions
127 #if !defined(FIND_NEW_THREADS)
128 #define FIND_NEW_THREADS target_find_new_threads
131 static struct thread_info *thread_list = NULL;
132 static int highest_thread_num;
135 thread_command PARAMS ((char * tidstr, int from_tty));
137 prune_threads PARAMS ((void));
140 switch_to_thread PARAMS ((int pid));
142 static struct thread_info *
143 find_thread_id PARAMS ((int num));
146 info_threads_command PARAMS ((char *, int));
149 restore_current_thread PARAMS ((int));
152 thread_apply_all_command PARAMS ((char *, int));
155 thread_apply_command PARAMS ((char *, int));
157 static void info_threads_command PARAMS ((char *, int));
159 static void restore_current_thread PARAMS ((int));
161 static void thread_apply_all_command PARAMS ((char *, int));
163 static void thread_apply_command PARAMS ((char *, int));
165 static int thread_alive PARAMS ((struct thread_info *));
170 struct thread_info *tp, *tpnext;
175 for (tp = thread_list; tp; tp = tpnext)
182 highest_thread_num = 0;
189 struct thread_info *tp;
191 tp = (struct thread_info *) xmalloc (sizeof (struct thread_info));
194 tp->num = ++highest_thread_num;
196 tp->prev_func_start = 0;
197 tp->prev_func_name = NULL;
198 tp->step_range_start = 0;
199 tp->step_range_end = 0;
200 tp->step_frame_address =0;
201 tp->step_resume_breakpoint = 0;
202 tp->through_sigtramp_breakpoint = 0;
203 tp->handling_longjmp = 0;
204 tp->trap_expected = 0;
205 tp->another_trap = 0;
206 tp->next = thread_list;
214 struct thread_info *tp, *tpprev;
218 for (tp = thread_list; tp; tpprev = tp, tp = tp->next)
226 tpprev->next = tp->next;
228 thread_list = tp->next;
235 static struct thread_info *
239 struct thread_info *tp;
241 for (tp = thread_list; tp; tp = tp->next)
249 valid_thread_id (num)
252 struct thread_info *tp;
254 for (tp = thread_list; tp; tp = tp->next)
262 pid_to_thread_id (pid)
265 struct thread_info *tp;
267 for (tp = thread_list; tp; tp = tp->next)
275 thread_id_to_pid (num)
278 struct thread_info *thread = find_thread_id (num);
289 struct thread_info *tp;
291 for (tp = thread_list; tp; tp = tp->next)
295 return 0; /* Never heard of 'im */
298 /* Load infrun state for the thread PID. */
300 void load_infrun_state (pid, prev_pc, prev_func_start, prev_func_name,
301 trap_expected, step_resume_breakpoint,
302 through_sigtramp_breakpoint, step_range_start,
303 step_range_end, step_frame_address,
304 handling_longjmp, another_trap)
307 CORE_ADDR *prev_func_start;
308 char **prev_func_name;
310 struct breakpoint **step_resume_breakpoint;
311 struct breakpoint **through_sigtramp_breakpoint;
312 CORE_ADDR *step_range_start;
313 CORE_ADDR *step_range_end;
314 CORE_ADDR *step_frame_address;
315 int *handling_longjmp;
318 struct thread_info *tp;
320 /* If we can't find the thread, then we're debugging a single threaded
321 process. No need to do anything in that case. */
322 tp = find_thread_id (pid_to_thread_id (pid));
326 *prev_pc = tp->prev_pc;
327 *prev_func_start = tp->prev_func_start;
328 *prev_func_name = tp->prev_func_name;
329 *step_resume_breakpoint = tp->step_resume_breakpoint;
330 *step_range_start = tp->step_range_start;
331 *step_range_end = tp->step_range_end;
332 *step_frame_address = tp->step_frame_address;
333 *through_sigtramp_breakpoint = tp->through_sigtramp_breakpoint;
334 *handling_longjmp = tp->handling_longjmp;
335 *trap_expected = tp->trap_expected;
336 *another_trap = tp->another_trap;
339 /* Save infrun state for the thread PID. */
341 void save_infrun_state (pid, prev_pc, prev_func_start, prev_func_name,
342 trap_expected, step_resume_breakpoint,
343 through_sigtramp_breakpoint, step_range_start,
344 step_range_end, step_frame_address,
345 handling_longjmp, another_trap)
348 CORE_ADDR prev_func_start;
349 char *prev_func_name;
351 struct breakpoint *step_resume_breakpoint;
352 struct breakpoint *through_sigtramp_breakpoint;
353 CORE_ADDR step_range_start;
354 CORE_ADDR step_range_end;
355 CORE_ADDR step_frame_address;
356 int handling_longjmp;
359 struct thread_info *tp;
361 /* If we can't find the thread, then we're debugging a single-threaded
362 process. Nothing to do in that case. */
363 tp = find_thread_id (pid_to_thread_id (pid));
367 tp->prev_pc = prev_pc;
368 tp->prev_func_start = prev_func_start;
369 tp->prev_func_name = prev_func_name;
370 tp->step_resume_breakpoint = step_resume_breakpoint;
371 tp->step_range_start = step_range_start;
372 tp->step_range_end = step_range_end;
373 tp->step_frame_address = step_frame_address;
374 tp->through_sigtramp_breakpoint = through_sigtramp_breakpoint;
375 tp->handling_longjmp = handling_longjmp;
376 tp->trap_expected = trap_expected;
377 tp->another_trap = another_trap;
380 /* Return true if TP is an active thread. */
383 struct thread_info *tp;
387 if (! target_thread_alive (tp->pid))
389 tp->pid = -1; /* Mark it as dead */
398 struct thread_info *tp, *tpprev, *next;
401 for (tp = thread_list; tp; tp = next)
404 if (!thread_alive (tp))
417 /* Print information about currently known threads */
420 info_threads_command (arg, from_tty)
424 struct thread_info *tp;
425 int current_pid = inferior_pid;
427 /* Avoid coredumps which would happen if we tried to access a NULL
429 if (!target_has_stack) error ("No stack.");
432 #if defined(FIND_NEW_THREADS)
436 for (tp = thread_list; tp; tp = tp->next)
438 if (tp->pid == current_pid)
439 printf_filtered ("* ");
441 printf_filtered (" ");
443 printf_filtered ("%d %s ", tp->num, target_pid_to_str (tp->pid));
445 switch_to_thread (tp->pid);
447 print_stack_frame (selected_frame, -1, 0);
449 printf_filtered ("[No stack.]\n");
452 switch_to_thread (current_pid);
455 /* Switch from one thread to another. */
458 switch_to_thread (pid)
461 if (pid == inferior_pid)
465 flush_cached_frames ();
466 registers_changed ();
468 select_frame (get_current_frame (), 0);
472 restore_current_thread (pid)
475 if (pid != inferior_pid)
476 switch_to_thread (pid);
479 /* Apply a GDB command to a list of threads. List syntax is a whitespace
480 seperated list of numbers, or ranges, or the keyword `all'. Ranges consist
481 of two numbers seperated by a hyphen. Examples:
483 thread apply 1 2 7 4 backtrace Apply backtrace cmd to threads 1,2,7,4
484 thread apply 2-7 9 p foo(1) Apply p foo(1) cmd to threads 2->7 & 9
485 thread apply all p x/i $pc Apply x/i $pc cmd to all threads
489 thread_apply_all_command (cmd, from_tty)
493 struct thread_info *tp;
494 struct cleanup *old_chain;
496 if (cmd == NULL || *cmd == '\000')
497 error ("Please specify a command following the thread ID list");
499 old_chain = make_cleanup ((make_cleanup_func) restore_current_thread,
500 (void *) inferior_pid);
502 for (tp = thread_list; tp; tp = tp->next)
503 if (thread_alive (tp))
505 switch_to_thread (tp->pid);
506 printf_filtered ("\nThread %d (%s):\n", tp->num,
507 target_pid_to_str (inferior_pid));
508 execute_command (cmd, from_tty);
513 thread_apply_command (tidlist, from_tty)
519 struct cleanup *old_chain;
521 if (tidlist == NULL || *tidlist == '\000')
522 error ("Please specify a thread ID list");
524 for (cmd = tidlist; *cmd != '\000' && !isalpha(*cmd); cmd++);
527 error ("Please specify a command following the thread ID list");
529 old_chain = make_cleanup ((make_cleanup_func) restore_current_thread,
530 (void *) inferior_pid);
532 while (tidlist < cmd)
534 struct thread_info *tp;
537 start = strtol (tidlist, &p, 10);
539 error ("Error parsing %s", tidlist);
542 while (*tidlist == ' ' || *tidlist == '\t')
545 if (*tidlist == '-') /* Got a range of IDs? */
547 tidlist++; /* Skip the - */
548 end = strtol (tidlist, &p, 10);
550 error ("Error parsing %s", tidlist);
553 while (*tidlist == ' ' || *tidlist == '\t')
559 for (; start <= end; start++)
561 tp = find_thread_id (start);
564 warning ("Unknown thread %d.", start);
565 else if (!thread_alive (tp))
566 warning ("Thread %d has terminated.", start);
569 switch_to_thread (tp->pid);
570 printf_filtered ("\nThread %d (%s):\n", tp->num,
571 target_pid_to_str (inferior_pid));
572 execute_command (cmd, from_tty);
578 /* Switch to the specified thread. Will dispatch off to thread_apply_command
579 if prefix of arg is `apply'. */
582 thread_command (tidstr, from_tty)
587 struct thread_info *tp;
590 error ("Please specify a thread ID. Use the \"info threads\" command to\n\
591 see the IDs of currently known threads.");
595 tp = find_thread_id (num);
598 error ("Thread ID %d not known. Use the \"info threads\" command to\n\
599 see the IDs of currently known threads.", num);
601 if (!thread_alive (tp))
602 error ("Thread ID %d has terminated.\n", num);
604 switch_to_thread (tp->pid);
607 printf_filtered ("[Switching to %s]\n", target_pid_to_str (inferior_pid));
608 print_stack_frame (selected_frame, selected_frame_level, 1);
611 /* Commands with a prefix of `thread'. */
612 struct cmd_list_element *thread_cmd_list = NULL;
615 _initialize_thread ()
617 static struct cmd_list_element *thread_apply_list = NULL;
618 extern struct cmd_list_element *cmdlist;
620 add_info ("threads", info_threads_command,
621 "IDs of currently known threads.");
623 add_prefix_cmd ("thread", class_run, thread_command,
624 "Use this command to switch between threads.\n\
625 The new thread ID must be currently known.", &thread_cmd_list, "thread ", 1,
628 add_prefix_cmd ("apply", class_run, thread_apply_command,
629 "Apply a command to a list of threads.",
630 &thread_apply_list, "apply ", 1, &thread_cmd_list);
632 add_cmd ("all", class_run, thread_apply_all_command,
633 "Apply a command to all threads.",
636 add_com_alias ("t", "thread", class_run, 1);