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