~ubuntu-branches/ubuntu/intrepid/xen-3.3/intrepid-updates

« back to all changes in this revision

Viewing changes to tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2008-08-14 10:28:57 UTC
  • Revision ID: james.westby@ubuntu.com-20080814102857-a832fn5gowurz5do
Tags: upstream-3.3.0
ImportĀ upstreamĀ versionĀ 3.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Low level interface to ptrace, for the remote server for GDB.
 
2
   Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004
 
3
   Free Software Foundation, Inc.
 
4
 
 
5
   This file is part of GDB.
 
6
 
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 2 of the License, or
 
10
   (at your option) any later version.
 
11
 
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
 
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program; if not, write to the Free Software
 
19
   Foundation, Inc., 59 Temple Place - Suite 330,
 
20
   Boston, MA 02111-1307, USA.  */
 
21
 
 
22
#include "server.h"
 
23
#include "linux-low.h"
 
24
 
 
25
#include <sys/wait.h>
 
26
#include <stdio.h>
 
27
#include <sys/param.h>
 
28
#include <sys/dir.h>
 
29
#include <sys/ptrace.h>
 
30
#include <sys/user.h>
 
31
#include <signal.h>
 
32
#include <sys/ioctl.h>
 
33
#include <fcntl.h>
 
34
#include <string.h>
 
35
#include <stdlib.h>
 
36
#include <unistd.h>
 
37
#include <errno.h>
 
38
#include <xenctrl.h>
 
39
 
 
40
#define TRACE_ENTER /* printf("enter %s\n", __FUNCTION__) */
 
41
 
 
42
static int xc_handle;
 
43
 
 
44
static inline int
 
45
curvcpuid()
 
46
{
 
47
  struct process_info *process;
 
48
  if (current_inferior == NULL)
 
49
      return 0;
 
50
  process = get_thread_process(current_inferior);
 
51
  return (process->thread_known ? process->tid : 0);
 
52
 
 
53
}
 
54
 
 
55
struct inferior_list all_processes;
 
56
static int current_domid;
 
57
static int expect_signal = 0;
 
58
static int signal_to_send = 0; 
 
59
static void linux_resume (struct thread_resume *resume_info);
 
60
static void linux_set_inferior (void);
 
61
 
 
62
int debug_threads;
 
63
int using_threads;
 
64
extern int isfile;
 
65
 
 
66
struct pending_signals
 
67
{
 
68
  int signal;
 
69
  struct pending_signals *prev;
 
70
};
 
71
 
 
72
#define PTRACE_ARG3_TYPE long
 
73
#define PTRACE_XFER_TYPE long
 
74
 
 
75
static int use_regsets_p = 1;
 
76
 
 
77
 
 
78
#define pid_of(proc) ((proc)->head.id)
 
79
 
 
80
/* FIXME: Delete eventually.  */
 
81
#define inferior_pid (pid_of (get_thread_process (current_inferior)))
 
82
 
 
83
/* This function should only be called if the process got a SIGTRAP.
 
84
   The SIGTRAP could mean several things.
 
85
 
 
86
   On i386, where decr_pc_after_break is non-zero:
 
87
   If we were single-stepping this process using PTRACE_SINGLESTEP,
 
88
   we will get only the one SIGTRAP (even if the instruction we
 
89
   stepped over was a breakpoint).  The value of $eip will be the
 
90
   next instruction.
 
91
   If we continue the process using PTRACE_CONT, we will get a
 
92
   SIGTRAP when we hit a breakpoint.  The value of $eip will be
 
93
   the instruction after the breakpoint (i.e. needs to be
 
94
   decremented).  If we report the SIGTRAP to GDB, we must also
 
95
   report the undecremented PC.  If we cancel the SIGTRAP, we
 
96
   must resume at the decremented PC.
 
97
 
 
98
   (Presumably, not yet tested) On a non-decr_pc_after_break machine
 
99
   with hardware or kernel single-step:
 
100
   If we single-step over a breakpoint instruction, our PC will
 
101
   point at the following instruction.  If we continue and hit a
 
102
   breakpoint instruction, our PC will point at the breakpoint
 
103
   instruction.  */
 
104
static CORE_ADDR
 
105
get_stop_pc (void)
 
106
{
 
107
  CORE_ADDR stop_pc = (*the_low_target.get_pc) ();
 
108
 
 
109
  if (get_thread_process (current_inferior)->stepping)
 
110
    return stop_pc;
 
111
  else
 
112
    return stop_pc - the_low_target.decr_pc_after_break;
 
113
}
 
114
 
 
115
static void *
 
116
add_process (int pid, long tid)
 
117
{
 
118
  struct process_info *process;
 
119
 
 
120
  process = (struct process_info *) malloc (sizeof (*process));
 
121
  memset (process, 0, sizeof (*process));
 
122
 
 
123
  process->head.id = pid;
 
124
 
 
125
  process->tid = tid;
 
126
  process->lwpid = tid;
 
127
 
 
128
  add_inferior_to_list (&all_processes, &process->head);
 
129
 
 
130
  return process;
 
131
}
 
132
 
 
133
/* Start an inferior process and returns its pid.
 
134
   ALLARGS is a vector of program-name and args. */
 
135
 
 
136
static int
 
137
linux_create_inferior (char *program, char **allargs)
 
138
{
 
139
 
 
140
  fprintf (stderr, "Cannot exec %s: %s.\n", program,
 
141
           strerror (errno));
 
142
  fflush (stderr);
 
143
  _exit (0177);
 
144
  /* NOT REACHED */
 
145
  return -1;
 
146
}
 
147
 
 
148
int
 
149
linux_attach (int domid)
 
150
{
 
151
    struct process_info *new_process;
 
152
    current_domid = domid;
 
153
    /* this is handled for all active vcpus in PTRACE_ATTACH via the thread_create_callback */
 
154
    new_process = (struct process_info *) add_process (domid, curvcpuid());
 
155
    /* Don't ignore the initial SIGSTOP if we just attached to this process.  */
 
156
    /* vcpuid == 0 */
 
157
    add_thread (0, new_process);
 
158
    new_process->stop_expected = 0;
 
159
 
 
160
    if (xc_ptrace (xc_handle, PTRACE_ATTACH, domid, 0, isfile) != 0) {
 
161
        fprintf (stderr, "Cannot attach to domain %d: %s (%d)\n", domid,
 
162
                 strerror (errno), errno);
 
163
        fflush (stderr);
 
164
        if (!using_threads)
 
165
            _exit (0177);
 
166
    }
 
167
 
 
168
    return 0;
 
169
}
 
170
 
 
171
/* Kill the inferior process.  Make us have no inferior.  */
 
172
 
 
173
static void
 
174
linux_kill_one_process (struct inferior_list_entry *entry)
 
175
{
 
176
  struct thread_info *thread = (struct thread_info *) entry;
 
177
  struct process_info *process = get_thread_process (thread);
 
178
  xc_ptrace (xc_handle, PTRACE_KILL, pid_of (process), 0, 0);
 
179
}
 
180
 
 
181
 
 
182
static void
 
183
linux_kill (void)
 
184
{
 
185
  for_each_inferior (&all_threads, linux_kill_one_process);
 
186
}
 
187
 
 
188
static void
 
189
linux_detach_one_process (struct inferior_list_entry *entry)
 
190
{
 
191
 
 
192
  xc_ptrace (xc_handle, PTRACE_DETACH, current_domid, 0, 0);
 
193
}
 
194
 
 
195
 
 
196
static void
 
197
linux_detach (void)
 
198
{
 
199
  for_each_inferior (&all_threads, linux_detach_one_process);
 
200
}
 
201
 
 
202
/* Return nonzero if the given thread is still alive.  */
 
203
static int
 
204
linux_thread_alive (int tid)
 
205
{
 
206
    if (find_inferior_id (&all_threads, tid) != NULL)
 
207
        return 1;
 
208
    else
 
209
        return 0;
 
210
}
 
211
 
 
212
/* Wait for process, returns status.  */
 
213
 
 
214
static unsigned char
 
215
linux_wait (char *status)
 
216
{
 
217
  int w;
 
218
  if (xc_waitdomain(xc_handle, current_domid, &w, 0))
 
219
      return -1;
 
220
  
 
221
  *status = 'T';
 
222
  if (expect_signal)
 
223
      return expect_signal;
 
224
  else
 
225
      return SIGTRAP;
 
226
 
 
227
}
 
228
 
 
229
static void
 
230
linux_resume (struct thread_resume *resume_info)
 
231
{
 
232
  int step = resume_info->step;
 
233
  TRACE_ENTER;
 
234
  expect_signal = resume_info->sig;
 
235
  for_each_inferior(&all_threads, regcache_invalidate_one);
 
236
  if (debug_threads)
 
237
    fprintf(stderr, "step: %d\n", step);
 
238
  xc_ptrace (xc_handle, step ? PTRACE_SINGLESTEP : PTRACE_CONT, 
 
239
            resume_info->thread, 0, 0);
 
240
 
 
241
}
 
242
 
 
243
 
 
244
static int
 
245
regsets_fetch_inferior_registers ()
 
246
{
 
247
  struct regset_info *regset;
 
248
  TRACE_ENTER;
 
249
  regset = target_regsets;
 
250
 
 
251
  while (regset->size >= 0)
 
252
    {
 
253
      void *buf;
 
254
      int res;
 
255
 
 
256
      if (regset->size == 0)
 
257
        {
 
258
          regset ++;
 
259
          continue;
 
260
        }
 
261
 
 
262
      buf = malloc (regset->size);
 
263
      res = xc_ptrace (xc_handle, regset->get_request, 
 
264
                      curvcpuid(),
 
265
                      0, (PTRACE_XFER_TYPE)buf);
 
266
      if (res < 0)
 
267
        {
 
268
          if (errno == EIO)
 
269
            {
 
270
              /* If we get EIO on the first regset, do not try regsets again.
 
271
                 If we get EIO on a later regset, disable that regset.  */
 
272
              if (regset == target_regsets)
 
273
                {
 
274
                  use_regsets_p = 0;
 
275
                  return -1;
 
276
                }
 
277
              else
 
278
                {
 
279
                  regset->size = 0;
 
280
                  continue;
 
281
                }
 
282
            }
 
283
          else
 
284
            {
 
285
              char s[256];
 
286
              sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d",
 
287
                       inferior_pid);
 
288
              perror (s);
 
289
            }
 
290
        }
 
291
      regset->store_function (buf);
 
292
      regset ++;
 
293
    }
 
294
  return 0;
 
295
}
 
296
 
 
297
static int
 
298
regsets_store_inferior_registers ()
 
299
{
 
300
  struct regset_info *regset;
 
301
  TRACE_ENTER;
 
302
  regset = target_regsets;
 
303
 
 
304
  while (regset->size >= 0)
 
305
    {
 
306
      void *buf;
 
307
      int res;
 
308
 
 
309
      if (regset->size == 0)
 
310
        {
 
311
          regset ++;
 
312
          continue;
 
313
        }
 
314
 
 
315
      buf = malloc (regset->size);
 
316
      regset->fill_function (buf);
 
317
      res = xc_ptrace (xc_handle, regset->set_request, curvcpuid(), 0, (PTRACE_XFER_TYPE)buf);
 
318
      if (res < 0)
 
319
        {
 
320
          if (errno == EIO)
 
321
            {
 
322
              /* If we get EIO on the first regset, do not try regsets again.
 
323
                 If we get EIO on a later regset, disable that regset.  */
 
324
              if (regset == target_regsets)
 
325
                {
 
326
                  use_regsets_p = 0;
 
327
                  return -1;
 
328
                }
 
329
              else
 
330
                {
 
331
                  regset->size = 0;
 
332
                  continue;
 
333
                }
 
334
            }
 
335
          else
 
336
            {
 
337
#ifdef DEBUG
 
338
              perror ("Warning: ptrace(regsets_store_inferior_registers)");
 
339
#endif
 
340
            }
 
341
        }
 
342
      regset ++;
 
343
      free (buf);
 
344
    }
 
345
  return 0;
 
346
}
 
347
 
 
348
 
 
349
 
 
350
 
 
351
void
 
352
linux_fetch_registers (int regno)
 
353
{
 
354
  if (use_regsets_p)
 
355
    {
 
356
      if (regsets_fetch_inferior_registers () == 0)
 
357
        return;
 
358
    }
 
359
 
 
360
}
 
361
 
 
362
void
 
363
linux_store_registers (int regno)
 
364
{
 
365
  if (use_regsets_p)
 
366
    {
 
367
      if (regsets_store_inferior_registers () == 0)
 
368
        return;
 
369
    }
 
370
}
 
371
 
 
372
 
 
373
/* Copy LEN bytes from inferior's memory starting at MEMADDR
 
374
   to debugger memory starting at MYADDR.  */
 
375
 
 
376
static int
 
377
linux_read_memory (CORE_ADDR memaddr, char *myaddr, int len)
 
378
{
 
379
  register int i;
 
380
  /* Round starting address down to longword boundary.  */
 
381
  register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
 
382
  /* Round ending address up; get number of longwords that makes.  */
 
383
  register int count
 
384
    = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
 
385
      / sizeof (PTRACE_XFER_TYPE);
 
386
  /* Allocate buffer of that many longwords.  */
 
387
  register PTRACE_XFER_TYPE *buffer
 
388
    = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
 
389
 
 
390
  TRACE_ENTER;
 
391
  /* Read all the longwords */
 
392
  for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
 
393
    {
 
394
      errno = 0;
 
395
      buffer[i] = xc_ptrace (xc_handle, PTRACE_PEEKTEXT, curvcpuid(), (PTRACE_ARG3_TYPE) addr, 0);
 
396
      if (errno)
 
397
        return errno;
 
398
    }
 
399
 
 
400
  /* Copy appropriate bytes out of the buffer.  */
 
401
  memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len);
 
402
 
 
403
  return 0;
 
404
}
 
405
 
 
406
/* Copy LEN bytes of data from debugger memory at MYADDR
 
407
   to inferior's memory at MEMADDR.
 
408
   On failure (cannot write the inferior)
 
409
   returns the value of errno.  */
 
410
 
 
411
static int
 
412
linux_write_memory (CORE_ADDR memaddr, const char *myaddr, int len)
 
413
{
 
414
  register int i;
 
415
  /* Round starting address down to longword boundary.  */
 
416
  register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
 
417
  /* Round ending address up; get number of longwords that makes.  */
 
418
  register int count
 
419
  = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) / sizeof (PTRACE_XFER_TYPE);
 
420
  /* Allocate buffer of that many longwords.  */
 
421
  register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
 
422
  extern int errno;
 
423
 
 
424
  TRACE_ENTER;
 
425
 
 
426
  /* Fill start and end extra bytes of buffer with existing memory data.  */
 
427
 
 
428
  buffer[0] = xc_ptrace (xc_handle, PTRACE_PEEKTEXT, curvcpuid(),
 
429
                      (PTRACE_ARG3_TYPE) addr, 0);
 
430
 
 
431
  if (count > 1)
 
432
    {
 
433
      buffer[count - 1]
 
434
        = xc_ptrace (xc_handle, PTRACE_PEEKTEXT, curvcpuid(),
 
435
                  (PTRACE_ARG3_TYPE) (addr + (count - 1)
 
436
                                      * sizeof (PTRACE_XFER_TYPE)),
 
437
                  0);
 
438
    }
 
439
 
 
440
  /* Copy data to be written over corresponding part of buffer */
 
441
 
 
442
  memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), myaddr, len);
 
443
 
 
444
  /* Write the entire buffer.  */
 
445
  for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
 
446
    {
 
447
      errno = 0;
 
448
      xc_ptrace (xc_handle, PTRACE_POKETEXT, curvcpuid(), 
 
449
                (PTRACE_ARG3_TYPE) addr, buffer[i]);
 
450
      if (errno)
 
451
        return errno;
 
452
    }
 
453
 
 
454
  return 0;
 
455
}
 
456
 
 
457
static void
 
458
linux_look_up_symbols (void)
 
459
{
 
460
  if (using_threads) 
 
461
    return;
 
462
 
 
463
  using_threads = thread_db_init ();
 
464
 
 
465
}
 
466
 
 
467
static void
 
468
linux_send_signal (int signum)
 
469
{
 
470
  extern int signal_pid;
 
471
 
 
472
  TRACE_ENTER;
 
473
  signal_to_send = signum;
 
474
  psignal(signum, "need to send ");
 
475
  if (cont_thread > 0)
 
476
    {
 
477
      struct process_info *process;
 
478
 
 
479
      process = get_thread_process (current_inferior);
 
480
      kill (process->lwpid, signum);
 
481
    }
 
482
  else
 
483
    kill (signal_pid, signum);
 
484
}
 
485
 
 
486
/* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
 
487
   to debugger memory starting at MYADDR.  */
 
488
 
 
489
static int
 
490
linux_read_auxv (CORE_ADDR offset, char *myaddr, unsigned int len)
 
491
{
 
492
  char filename[PATH_MAX];
 
493
  int fd, n;
 
494
 
 
495
  TRACE_ENTER;
 
496
  snprintf (filename, sizeof filename, "/proc/%d/auxv", inferior_pid);
 
497
 
 
498
  fd = open (filename, O_RDONLY);
 
499
  if (fd < 0)
 
500
    return -1;
 
501
 
 
502
  if (offset != (CORE_ADDR) 0
 
503
      && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
 
504
    n = -1;
 
505
  else
 
506
    n = read (fd, myaddr, len);
 
507
 
 
508
  close (fd);
 
509
 
 
510
  return n;
 
511
}
 
512
 
 
513
 
 
514
static struct target_ops linux_xen_target_ops = {
 
515
  linux_create_inferior,
 
516
  linux_attach,
 
517
  linux_kill,
 
518
  linux_detach,
 
519
  linux_thread_alive,
 
520
  linux_resume,
 
521
  linux_wait,
 
522
  linux_fetch_registers,
 
523
  linux_store_registers,
 
524
  linux_read_memory,
 
525
  linux_write_memory,
 
526
  linux_look_up_symbols,
 
527
  linux_send_signal,
 
528
  linux_read_auxv,
 
529
};
 
530
 
 
531
static void
 
532
linux_init_signals ()
 
533
{
 
534
  /* FIXME drow/2002-06-09: As above, we should check with LinuxThreads
 
535
     to find what the cancel signal actually is.  */
 
536
  signal (__SIGRTMIN+1, SIG_IGN);
 
537
}
 
538
 
 
539
void
 
540
initialize_low (void)
 
541
{
 
542
  using_threads = 0;
 
543
  xc_handle = xc_interface_open();
 
544
  set_target_ops (&linux_xen_target_ops);
 
545
  set_breakpoint_data (the_low_target.breakpoint,
 
546
                       the_low_target.breakpoint_len);
 
547
  init_registers ();
 
548
  linux_init_signals ();
 
549
  using_threads = thread_db_init ();
 
550
 
 
551
}
 
552
 
 
553
 
 
554
static void
 
555
thread_create_callback(long vcpuid)
 
556
{
 
557
  struct thread_info *inferior;
 
558
  struct process_info *process;
 
559
 
 
560
  /*  If we are attaching to our first thread, things are a little
 
561
   *  different.  
 
562
   */
 
563
  if (all_threads.head == all_threads.tail)
 
564
    {
 
565
      inferior = (struct thread_info *) all_threads.head;
 
566
      process = get_thread_process (inferior);
 
567
      if (process->thread_known == 0)
 
568
        {
 
569
          /* Switch to indexing the threads list by TID.  */
 
570
          change_inferior_id (&all_threads, vcpuid);
 
571
          goto found;
 
572
        }
 
573
    }
 
574
  if (debug_threads)
 
575
    fprintf (stderr, "looking up thread %ld\n",
 
576
             vcpuid);
 
577
  inferior = (struct thread_info *) find_inferior_id (&all_threads,
 
578
                                                      vcpuid);
 
579
  /* if vcpu alread registered - do nothing */
 
580
  if (inferior != NULL) 
 
581
    return;
 
582
 
 
583
  if (debug_threads)
 
584
    fprintf (stderr, "Attaching to thread %ld\n",
 
585
             vcpuid);
 
586
 
 
587
  process = add_process(current_domid, vcpuid);
 
588
 
 
589
  add_thread(vcpuid, process);
 
590
  inferior = (struct thread_info *) find_inferior_id (&all_threads,
 
591
                                                      vcpuid);
 
592
  if (inferior == NULL)
 
593
    {
 
594
      warning ("Could not attach to thread %ld\n",
 
595
               vcpuid);
 
596
      return;
 
597
    }
 
598
 
 
599
 
 
600
found:
 
601
  if (debug_threads)
 
602
    fprintf (stderr, "notifying of new thread %ld\n",
 
603
             vcpuid);
 
604
  new_thread_notify (vcpuid);
 
605
 
 
606
  process->tid = vcpuid;
 
607
  process->lwpid = vcpuid;
 
608
 
 
609
  process->thread_known = 1;
 
610
}
 
611
 
 
612
static void
 
613
thread_death_callback(long vcpuid)
 
614
{
 
615
    if (debug_threads)
 
616
      fprintf (stderr, "Buuurp...! CPU down event.\n");
 
617
}
 
618
 
 
619
int
 
620
thread_db_init(void)
 
621
{
 
622
  debug_threads = 0;
 
623
  xc_register_event_handler(thread_create_callback, TD_CREATE);
 
624
  xc_register_event_handler(thread_death_callback, TD_DEATH);
 
625
  return 1;
 
626
}
 
627
 
 
628
/* XXX GAG ME */
 
629
static int breakpoint_found;
 
630
static void
 
631
set_breakpoint_inferior (struct inferior_list_entry *entry)
 
632
{
 
633
  struct thread_info *thread = (struct thread_info *) entry;
 
634
  struct thread_info *saved_inferior = current_inferior;
 
635
  CORE_ADDR eip;
 
636
  unsigned char buf[2] = {0, 0};
 
637
  current_inferior = thread;
 
638
  if (!breakpoint_found) {
 
639
    eip = get_stop_pc();
 
640
    linux_read_memory(eip, buf, 1);
 
641
    if (buf[0] == 0xcc) {
 
642
      breakpoint_found = 1;
 
643
      return;
 
644
    }
 
645
  } else if (breakpoint_found == 2) {
 
646
    if (get_thread_process (current_inferior)->stepping) {
 
647
      printf("stepping\n");
 
648
      breakpoint_found = 1;
 
649
      return;
 
650
    } 
 
651
  }
 
652
  current_inferior = saved_inferior;
 
653
 
 
654
 
 
655
}
 
656
 
 
657
static void
 
658
linux_set_inferior (void)
 
659
{
 
660
  breakpoint_found = 0;
 
661
  for_each_inferior (&all_threads, set_breakpoint_inferior);
 
662
  if (!breakpoint_found) {
 
663
    breakpoint_found = 2;
 
664
    for_each_inferior (&all_threads, set_breakpoint_inferior);
 
665
  }
 
666
}
 
667