Add GPL copyright notices to uncopyrighted files.
[deliverable/binutils-gdb.git] / gdb / thread.c
CommitLineData
c906108c 1/* Multi-process/thread control for GDB, the GNU debugger.
0d06e24b 2 Copyright 1986, 1987, 1988, 1993, 1998, 1999, 2000
c906108c
SS
3
4 Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
5 Free Software Foundation, Inc.
6
c5aa993b 7 This file is part of GDB.
c906108c 8
c5aa993b
JM
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.
c906108c 13
c5aa993b
JM
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.
c906108c 18
c5aa993b
JM
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,
22 Boston, MA 02111-1307, USA. */
c906108c
SS
23
24#include "defs.h"
25#include "symtab.h"
26#include "frame.h"
27#include "inferior.h"
28#include "environ.h"
29#include "value.h"
30#include "target.h"
31#include "gdbthread.h"
32#include "command.h"
33#include "gdbcmd.h"
34
35#include <ctype.h>
36#include <sys/types.h>
37#include <signal.h>
8b93c638
JM
38#ifdef UI_OUT
39#include "ui-out.h"
40#endif
c906108c 41
c5aa993b 42/*#include "lynxos-core.h" */
c906108c 43
0d06e24b 44/* Definition of struct thread_info exported to gdbthread.h */
c906108c
SS
45
46/* Prototypes for exported functions. */
47
a14ed312 48void _initialize_thread (void);
c906108c
SS
49
50/* Prototypes for local functions. */
51
c906108c
SS
52static struct thread_info *thread_list = NULL;
53static int highest_thread_num;
54
a14ed312 55static struct thread_info *find_thread_id (int num);
c906108c 56
a14ed312
KB
57static void thread_command (char *tidstr, int from_tty);
58static void thread_apply_all_command (char *, int);
59static int thread_alive (struct thread_info *);
60static void info_threads_command (char *, int);
61static void thread_apply_command (char *, int);
62static void restore_current_thread (int);
63static void switch_to_thread (int pid);
64static void prune_threads (void);
c906108c 65
7c952b6d
ND
66static void
67free_thread (struct thread_info *tp)
68{
69 /* NOTE: this will take care of any left-over step_resume breakpoints,
70 but not any user-specified thread-specific breakpoints. */
71 if (tp->step_resume_breakpoint)
72 delete_breakpoint (tp->step_resume_breakpoint);
73
74 /* FIXME: do I ever need to call the back-end to give it a
75 chance at this private data before deleting the thread? */
76 if (tp->private)
77 free (tp->private);
78
79 free (tp);
80}
81
c906108c
SS
82void
83init_thread_list ()
84{
85 struct thread_info *tp, *tpnext;
86
7c952b6d 87 highest_thread_num = 0;
c906108c
SS
88 if (!thread_list)
89 return;
90
91 for (tp = thread_list; tp; tp = tpnext)
92 {
93 tpnext = tp->next;
7c952b6d 94 free_thread (tp);
c906108c
SS
95 }
96
97 thread_list = NULL;
c906108c
SS
98}
99
0d06e24b
JM
100/* add_thread now returns a pointer to the new thread_info,
101 so that back_ends can initialize their private data. */
102
103struct thread_info *
c906108c
SS
104add_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;
c5aa993b 118 tp->step_frame_address = 0;
c906108c
SS
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->stepping_through_solib_after_catch = 0;
125 tp->stepping_through_solib_catchpoints = NULL;
126 tp->stepping_through_sigtramp = 0;
127 tp->next = thread_list;
c5394b80 128 tp->private = NULL;
c906108c 129 thread_list = tp;
0d06e24b 130 return tp;
c906108c
SS
131}
132
133void
134delete_thread (pid)
135 int pid;
136{
137 struct thread_info *tp, *tpprev;
138
139 tpprev = NULL;
140
141 for (tp = thread_list; tp; tpprev = tp, tp = tp->next)
142 if (tp->pid == pid)
143 break;
144
145 if (!tp)
146 return;
147
148 if (tpprev)
149 tpprev->next = tp->next;
150 else
151 thread_list = tp->next;
152
7c952b6d 153 free_thread (tp);
c906108c
SS
154}
155
156static struct thread_info *
157find_thread_id (num)
c5aa993b 158 int num;
c906108c
SS
159{
160 struct thread_info *tp;
161
162 for (tp = thread_list; tp; tp = tp->next)
163 if (tp->num == num)
164 return tp;
165
166 return NULL;
167}
168
0d06e24b
JM
169/* Find a thread_info by matching 'pid'. */
170struct thread_info *
171find_thread_pid (pid)
172 int pid;
173{
174 struct thread_info *tp;
175
176 for (tp = thread_list; tp; tp = tp->next)
177 if (tp->pid == pid)
178 return tp;
179
180 return NULL;
181}
182
183/*
184 * Thread iterator function.
185 *
186 * Calls a callback function once for each thread, so long as
187 * the callback function returns false. If the callback function
188 * returns true, the iteration will end and the current thread
189 * will be returned. This can be useful for implementing a
190 * search for a thread with arbitrary attributes, or for applying
191 * some operation to every thread.
192 *
193 * FIXME: some of the existing functionality, such as
194 * "Thread apply all", might be rewritten using this functionality.
195 */
196
197struct thread_info *
198iterate_over_threads (callback, data)
199 int (*callback) ();
200 void *data;
201{
202 struct thread_info *tp;
203
204 for (tp = thread_list; tp; tp = tp->next)
205 if ((*callback) (tp, data))
206 return tp;
207
208 return NULL;
209}
210
c906108c
SS
211int
212valid_thread_id (num)
c5aa993b 213 int num;
c906108c
SS
214{
215 struct thread_info *tp;
216
217 for (tp = thread_list; tp; tp = tp->next)
218 if (tp->num == num)
219 return 1;
220
221 return 0;
222}
223
224int
225pid_to_thread_id (pid)
c5aa993b 226 int pid;
c906108c
SS
227{
228 struct thread_info *tp;
229
230 for (tp = thread_list; tp; tp = tp->next)
231 if (tp->pid == pid)
232 return tp->num;
233
234 return 0;
235}
236
237int
238thread_id_to_pid (num)
c5aa993b 239 int num;
c906108c
SS
240{
241 struct thread_info *thread = find_thread_id (num);
242 if (thread)
243 return thread->pid;
244 else
245 return -1;
246}
247
248int
249in_thread_list (pid)
c5aa993b 250 int pid;
c906108c
SS
251{
252 struct thread_info *tp;
253
254 for (tp = thread_list; tp; tp = tp->next)
255 if (tp->pid == pid)
256 return 1;
257
258 return 0; /* Never heard of 'im */
259}
8b93c638
JM
260#ifdef UI_OUT
261/* Print a list of thread ids currently known, and the total number of
262 threads. To be used from within catch_errors. */
263static int
264do_captured_list_thread_ids (void *arg)
265{
266 struct thread_info *tp;
267 int num = 0;
268
269 ui_out_list_begin (uiout, "thread-ids");
270
271 for (tp = thread_list; tp; tp = tp->next)
272 {
273 num++;
274 ui_out_field_int (uiout, "thread-id", tp->num);
275 }
276
277 ui_out_list_end (uiout);
278 ui_out_field_int (uiout, "number-of-threads", num);
279 return GDB_RC_OK;
280}
281
282/* Official gdblib interface function to get a list of thread ids and
283 the total number. */
284enum gdb_rc
285gdb_list_thread_ids (/* output object */)
286{
287 return catch_errors (do_captured_list_thread_ids, NULL,
288 NULL, RETURN_MASK_ALL);
289}
290#endif
c906108c
SS
291
292/* Load infrun state for the thread PID. */
293
c5aa993b
JM
294void
295load_infrun_state (pid, prev_pc, prev_func_start, prev_func_name,
296 trap_expected, step_resume_breakpoint,
297 through_sigtramp_breakpoint, step_range_start,
298 step_range_end, step_frame_address,
299 handling_longjmp, another_trap,
300 stepping_through_solib_after_catch,
301 stepping_through_solib_catchpoints,
302 stepping_through_sigtramp)
c906108c
SS
303 int pid;
304 CORE_ADDR *prev_pc;
305 CORE_ADDR *prev_func_start;
306 char **prev_func_name;
307 int *trap_expected;
308 struct breakpoint **step_resume_breakpoint;
309 struct breakpoint **through_sigtramp_breakpoint;
310 CORE_ADDR *step_range_start;
311 CORE_ADDR *step_range_end;
312 CORE_ADDR *step_frame_address;
313 int *handling_longjmp;
314 int *another_trap;
c5aa993b
JM
315 int *stepping_through_solib_after_catch;
316 bpstat *stepping_through_solib_catchpoints;
317 int *stepping_through_sigtramp;
c906108c
SS
318{
319 struct thread_info *tp;
320
321 /* If we can't find the thread, then we're debugging a single threaded
322 process. No need to do anything in that case. */
323 tp = find_thread_id (pid_to_thread_id (pid));
324 if (tp == NULL)
325 return;
326
327 *prev_pc = tp->prev_pc;
328 *prev_func_start = tp->prev_func_start;
329 *prev_func_name = tp->prev_func_name;
330 *step_resume_breakpoint = tp->step_resume_breakpoint;
331 *step_range_start = tp->step_range_start;
332 *step_range_end = tp->step_range_end;
333 *step_frame_address = tp->step_frame_address;
334 *through_sigtramp_breakpoint = tp->through_sigtramp_breakpoint;
335 *handling_longjmp = tp->handling_longjmp;
336 *trap_expected = tp->trap_expected;
337 *another_trap = tp->another_trap;
338 *stepping_through_solib_after_catch = tp->stepping_through_solib_after_catch;
339 *stepping_through_solib_catchpoints = tp->stepping_through_solib_catchpoints;
340 *stepping_through_sigtramp = tp->stepping_through_sigtramp;
341}
342
343/* Save infrun state for the thread PID. */
344
c5aa993b
JM
345void
346save_infrun_state (pid, prev_pc, prev_func_start, prev_func_name,
347 trap_expected, step_resume_breakpoint,
348 through_sigtramp_breakpoint, step_range_start,
349 step_range_end, step_frame_address,
350 handling_longjmp, another_trap,
351 stepping_through_solib_after_catch,
352 stepping_through_solib_catchpoints,
353 stepping_through_sigtramp)
c906108c
SS
354 int pid;
355 CORE_ADDR prev_pc;
356 CORE_ADDR prev_func_start;
357 char *prev_func_name;
358 int trap_expected;
359 struct breakpoint *step_resume_breakpoint;
360 struct breakpoint *through_sigtramp_breakpoint;
361 CORE_ADDR step_range_start;
362 CORE_ADDR step_range_end;
363 CORE_ADDR step_frame_address;
364 int handling_longjmp;
365 int another_trap;
c5aa993b
JM
366 int stepping_through_solib_after_catch;
367 bpstat stepping_through_solib_catchpoints;
368 int stepping_through_sigtramp;
c906108c
SS
369{
370 struct thread_info *tp;
371
372 /* If we can't find the thread, then we're debugging a single-threaded
373 process. Nothing to do in that case. */
374 tp = find_thread_id (pid_to_thread_id (pid));
375 if (tp == NULL)
376 return;
377
378 tp->prev_pc = prev_pc;
379 tp->prev_func_start = prev_func_start;
380 tp->prev_func_name = prev_func_name;
381 tp->step_resume_breakpoint = step_resume_breakpoint;
382 tp->step_range_start = step_range_start;
383 tp->step_range_end = step_range_end;
384 tp->step_frame_address = step_frame_address;
385 tp->through_sigtramp_breakpoint = through_sigtramp_breakpoint;
386 tp->handling_longjmp = handling_longjmp;
387 tp->trap_expected = trap_expected;
388 tp->another_trap = another_trap;
389 tp->stepping_through_solib_after_catch = stepping_through_solib_after_catch;
390 tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints;
391 tp->stepping_through_sigtramp = stepping_through_sigtramp;
392}
393
394/* Return true if TP is an active thread. */
395static int
396thread_alive (tp)
397 struct thread_info *tp;
398{
399 if (tp->pid == -1)
400 return 0;
c5aa993b 401 if (!target_thread_alive (tp->pid))
c906108c 402 {
c5aa993b 403 tp->pid = -1; /* Mark it as dead */
c906108c
SS
404 return 0;
405 }
406 return 1;
407}
408
409static void
410prune_threads ()
411{
d4f3574e 412 struct thread_info *tp, *next;
c906108c 413
c906108c
SS
414 for (tp = thread_list; tp; tp = next)
415 {
416 next = tp->next;
417 if (!thread_alive (tp))
53a5351d 418 delete_thread (tp->pid);
c906108c
SS
419 }
420}
421
422/* Print information about currently known threads
c5aa993b 423
c906108c
SS
424 * Note: this has the drawback that it _really_ switches
425 * threads, which frees the frame cache. A no-side
426 * effects info-threads command would be nicer.
427 */
428
429static void
430info_threads_command (arg, from_tty)
431 char *arg;
432 int from_tty;
433{
434 struct thread_info *tp;
c5aa993b
JM
435 int current_pid;
436 struct frame_info *cur_frame;
437 int saved_frame_level = selected_frame_level;
438 int counter;
0d06e24b 439 char *extra_info;
c906108c
SS
440
441 /* Avoid coredumps which would happen if we tried to access a NULL
442 selected_frame. */
c5aa993b
JM
443 if (!target_has_stack)
444 error ("No stack.");
c906108c
SS
445
446 prune_threads ();
b83266a0 447 target_find_new_threads ();
c906108c
SS
448 current_pid = inferior_pid;
449 for (tp = thread_list; tp; tp = tp->next)
450 {
451 if (tp->pid == current_pid)
452 printf_filtered ("* ");
453 else
454 printf_filtered (" ");
455
456#ifdef HPUXHPPA
0d06e24b 457 printf_filtered ("%d %s", tp->num, target_tid_to_str (tp->pid));
c906108c 458#else
0d06e24b 459 printf_filtered ("%d %s", tp->num, target_pid_to_str (tp->pid));
c906108c 460#endif
0d06e24b
JM
461
462 extra_info = target_extra_thread_info (tp);
463 if (extra_info)
464 printf_filtered (" (%s)", extra_info);
465 puts_filtered (" ");
466
c906108c
SS
467 switch_to_thread (tp->pid);
468 if (selected_frame)
469 print_only_stack_frame (selected_frame, -1, 0);
470 else
471 printf_filtered ("[No stack.]\n");
472 }
473
474 switch_to_thread (current_pid);
475
476 /* Code below copied from "up_silently_base" in "stack.c".
477 * It restores the frame set by the user before the "info threads"
478 * command. We have finished the info-threads display by switching
479 * back to the current thread. That switch has put us at the top
480 * of the stack (leaf frame).
481 */
c5aa993b
JM
482 counter = saved_frame_level;
483 cur_frame = find_relative_frame (selected_frame, &counter);
c906108c
SS
484 if (counter != 0)
485 {
486 /* Ooops, can't restore, tell user where we are. */
487 warning ("Couldn't restore frame in current thread, at frame 0");
488 print_stack_frame (selected_frame, -1, 0);
489 }
490 else
491 {
c5aa993b 492 select_frame (cur_frame, saved_frame_level);
c906108c
SS
493 }
494
495 /* re-show current frame. */
c5aa993b 496 show_stack_frame (cur_frame);
c906108c
SS
497}
498
499/* Switch from one thread to another. */
500
501static void
502switch_to_thread (pid)
503 int pid;
504{
505 if (pid == inferior_pid)
506 return;
507
508 inferior_pid = pid;
509 flush_cached_frames ();
510 registers_changed ();
c5aa993b 511 stop_pc = read_pc ();
c906108c
SS
512 select_frame (get_current_frame (), 0);
513}
514
515static void
516restore_current_thread (pid)
517 int pid;
518{
c5aa993b 519 if (pid != inferior_pid)
c906108c
SS
520 {
521 switch_to_thread (pid);
c5aa993b 522 print_stack_frame (get_current_frame (), 0, -1);
c906108c
SS
523 }
524}
525
6ecce94d
AC
526struct current_thread_cleanup
527{
528 int inferior_pid;
529};
530
531static void
532do_restore_current_thread_cleanup (void *arg)
533{
534 struct current_thread_cleanup *old = arg;
535 restore_current_thread (old->inferior_pid);
536 free (old);
537}
538
539static struct cleanup *
540make_cleanup_restore_current_thread (int inferior_pid)
541{
542 struct current_thread_cleanup *old
543 = xmalloc (sizeof (struct current_thread_cleanup));
544 old->inferior_pid = inferior_pid;
545 return make_cleanup (do_restore_current_thread_cleanup, old);
546}
547
c906108c
SS
548/* Apply a GDB command to a list of threads. List syntax is a whitespace
549 seperated list of numbers, or ranges, or the keyword `all'. Ranges consist
550 of two numbers seperated by a hyphen. Examples:
551
c5aa993b
JM
552 thread apply 1 2 7 4 backtrace Apply backtrace cmd to threads 1,2,7,4
553 thread apply 2-7 9 p foo(1) Apply p foo(1) cmd to threads 2->7 & 9
554 thread apply all p x/i $pc Apply x/i $pc cmd to all threads
555 */
c906108c
SS
556
557static void
558thread_apply_all_command (cmd, from_tty)
559 char *cmd;
560 int from_tty;
561{
562 struct thread_info *tp;
563 struct cleanup *old_chain;
564
565 if (cmd == NULL || *cmd == '\000')
566 error ("Please specify a command following the thread ID list");
567
6ecce94d 568 old_chain = make_cleanup_restore_current_thread (inferior_pid);
c906108c 569
e9d196c5
MS
570 /* It is safe to update the thread list now, before
571 traversing it for "thread apply all". MVS */
572 target_find_new_threads ();
573
c906108c
SS
574 for (tp = thread_list; tp; tp = tp->next)
575 if (thread_alive (tp))
576 {
577 switch_to_thread (tp->pid);
578#ifdef HPUXHPPA
579 printf_filtered ("\nThread %d (%s):\n",
580 tp->num,
581 target_tid_to_str (inferior_pid));
582#else
583 printf_filtered ("\nThread %d (%s):\n", tp->num,
584 target_pid_to_str (inferior_pid));
585#endif
586 execute_command (cmd, from_tty);
587 }
6ecce94d
AC
588
589 do_cleanups (old_chain);
c906108c
SS
590}
591
592static void
593thread_apply_command (tidlist, from_tty)
594 char *tidlist;
595 int from_tty;
596{
597 char *cmd;
598 char *p;
599 struct cleanup *old_chain;
600
601 if (tidlist == NULL || *tidlist == '\000')
602 error ("Please specify a thread ID list");
603
c5aa993b 604 for (cmd = tidlist; *cmd != '\000' && !isalpha (*cmd); cmd++);
c906108c
SS
605
606 if (*cmd == '\000')
607 error ("Please specify a command following the thread ID list");
608
6ecce94d 609 old_chain = make_cleanup_restore_current_thread (inferior_pid);
c906108c
SS
610
611 while (tidlist < cmd)
612 {
613 struct thread_info *tp;
614 int start, end;
615
616 start = strtol (tidlist, &p, 10);
617 if (p == tidlist)
618 error ("Error parsing %s", tidlist);
619 tidlist = p;
620
621 while (*tidlist == ' ' || *tidlist == '\t')
622 tidlist++;
623
624 if (*tidlist == '-') /* Got a range of IDs? */
625 {
c5aa993b 626 tidlist++; /* Skip the - */
c906108c
SS
627 end = strtol (tidlist, &p, 10);
628 if (p == tidlist)
629 error ("Error parsing %s", tidlist);
630 tidlist = p;
631
632 while (*tidlist == ' ' || *tidlist == '\t')
633 tidlist++;
634 }
635 else
636 end = start;
637
638 for (; start <= end; start++)
639 {
640 tp = find_thread_id (start);
641
642 if (!tp)
643 warning ("Unknown thread %d.", start);
644 else if (!thread_alive (tp))
645 warning ("Thread %d has terminated.", start);
646 else
647 {
648 switch_to_thread (tp->pid);
649#ifdef HPUXHPPA
650 printf_filtered ("\nThread %d (%s):\n", tp->num,
651 target_tid_to_str (inferior_pid));
652#else
653 printf_filtered ("\nThread %d (%s):\n", tp->num,
654 target_pid_to_str (inferior_pid));
655#endif
656 execute_command (cmd, from_tty);
657 }
658 }
659 }
6ecce94d
AC
660
661 do_cleanups (old_chain);
c906108c
SS
662}
663
664/* Switch to the specified thread. Will dispatch off to thread_apply_command
665 if prefix of arg is `apply'. */
666
667static void
668thread_command (tidstr, from_tty)
669 char *tidstr;
670 int from_tty;
671{
c906108c
SS
672 if (!tidstr)
673 {
674 /* Don't generate an error, just say which thread is current. */
675 if (target_has_stack)
676 printf_filtered ("[Current thread is %d (%s)]\n",
c5aa993b 677 pid_to_thread_id (inferior_pid),
c906108c 678#if defined(HPUXHPPA)
c5aa993b 679 target_tid_to_str (inferior_pid)
c906108c 680#else
c5aa993b 681 target_pid_to_str (inferior_pid)
c906108c 682#endif
c5aa993b 683 );
c906108c
SS
684 else
685 error ("No stack.");
686 return;
687 }
c5394b80
JM
688
689 gdb_thread_select (tidstr);
690}
691
692static int
693do_captured_thread_select (void *tidstr)
694{
695 int num;
696 struct thread_info *tp;
697
698 num = atoi ((char *)tidstr);
c906108c
SS
699
700 tp = find_thread_id (num);
701
8b93c638
JM
702#ifdef UI_OUT
703 if (!tp)
704 error ("Thread ID %d not known.", num);
705#else
c906108c
SS
706 if (!tp)
707 error ("Thread ID %d not known. Use the \"info threads\" command to\n\
708see the IDs of currently known threads.", num);
8b93c638 709#endif
c906108c
SS
710
711 if (!thread_alive (tp))
712 error ("Thread ID %d has terminated.\n", num);
713
714 switch_to_thread (tp->pid);
715
8b93c638
JM
716#ifdef UI_OUT
717 ui_out_text (uiout, "[Switching to thread ");
718 ui_out_field_int (uiout, "new-thread-id", pid_to_thread_id (inferior_pid));
719 ui_out_text (uiout, " (");
720#if defined(HPUXHPPA)
721 ui_out_text (uiout, target_tid_to_str (inferior_pid));
722#else
723 ui_out_text (uiout, target_pid_to_str (inferior_pid));
724#endif
725 ui_out_text (uiout, ")]");
726#else /* UI_OUT */
c906108c
SS
727 printf_filtered ("[Switching to thread %d (%s)]\n",
728 pid_to_thread_id (inferior_pid),
729#if defined(HPUXHPPA)
730 target_tid_to_str (inferior_pid)
731#else
732 target_pid_to_str (inferior_pid)
733#endif
c5aa993b 734 );
8b93c638 735#endif /* UI_OUT */
c5394b80 736
c906108c 737 print_stack_frame (selected_frame, selected_frame_level, 1);
c5394b80
JM
738 return GDB_RC_OK;
739}
740
741enum gdb_rc
742gdb_thread_select (char *tidstr)
743{
744 return catch_errors (do_captured_thread_select, tidstr,
745 NULL, RETURN_MASK_ALL);
c906108c
SS
746}
747
748/* Commands with a prefix of `thread'. */
749struct cmd_list_element *thread_cmd_list = NULL;
750
751void
752_initialize_thread ()
753{
754 static struct cmd_list_element *thread_apply_list = NULL;
c906108c
SS
755
756 add_info ("threads", info_threads_command,
757 "IDs of currently known threads.");
758
759 add_prefix_cmd ("thread", class_run, thread_command,
760 "Use this command to switch between threads.\n\
761The new thread ID must be currently known.", &thread_cmd_list, "thread ", 1,
762 &cmdlist);
763
764 add_prefix_cmd ("apply", class_run, thread_apply_command,
765 "Apply a command to a list of threads.",
766 &thread_apply_list, "apply ", 1, &thread_cmd_list);
767
768 add_cmd ("all", class_run, thread_apply_all_command,
769 "Apply a command to all threads.",
770 &thread_apply_list);
771
772 if (!xdb_commands)
773 add_com_alias ("t", "thread", class_run, 1);
774}
This page took 0.118583 seconds and 4 git commands to generate.