OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [gdb/] [thread.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.