source: trunk/packages/xen-3.1/xen-3.1/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 15.3 KB
Line 
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
42static int xc_handle;
43
44static inline int
45curvcpuid()
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
55struct inferior_list all_processes;
56static int current_domid;
57static int expect_signal = 0;
58static int signal_to_send = 0; 
59static void linux_resume (struct thread_resume *resume_info);
60static void linux_set_inferior (void);
61
62int debug_threads;
63int using_threads;
64extern int isfile;
65
66struct 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
75static 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.  */
104static CORE_ADDR
105get_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
115static void *
116add_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
136static int
137linux_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
148int
149linux_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
173static void
174linux_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
182static void
183linux_kill (void)
184{
185  for_each_inferior (&all_threads, linux_kill_one_process);
186}
187
188static void
189linux_detach_one_process (struct inferior_list_entry *entry)
190{
191
192  xc_ptrace (xc_handle, PTRACE_DETACH, current_domid, 0, 0);
193}
194
195
196static void
197linux_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.  */
203static int
204linux_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
214static unsigned char
215linux_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
229static void
230linux_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
244static int
245regsets_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
297static int
298regsets_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
351void
352linux_fetch_registers (int regno)
353{
354  if (use_regsets_p)
355    {
356      if (regsets_fetch_inferior_registers () == 0)
357        return;
358    }
359
360}
361
362void
363linux_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
376static int
377linux_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
411static int
412linux_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
457static void
458linux_look_up_symbols (void)
459{
460  if (using_threads) 
461    return;
462
463  using_threads = thread_db_init ();
464
465}
466
467static void
468linux_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
489static int
490linux_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
514static 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
531static void
532linux_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
539void
540initialize_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
554static void
555thread_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
600found:
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
612static void
613thread_death_callback(long vcpuid)
614{
615    if (debug_threads)
616      fprintf (stderr, "Buuurp...! CPU down event.\n");
617}
618
619int
620thread_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 */
629static int breakpoint_found;
630static void
631set_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
657static void
658linux_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
Note: See TracBrowser for help on using the repository browser.