ia64/xen-unstable

view tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c @ 8400:6b1d39a56c2b

Add debugging flag for domains to make domu debugging a run-time option
Signed-off-by: Kip Macy kmacy@fsmware.ckm
author kaf24@firebug.cl.cam.ac.uk
date Thu Dec 15 21:50:12 2005 +0100 (2005-12-15)
parents b5b7a9d9fc56
children 8ed131452f27
line source
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.
5 This file is part of GDB.
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.
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.
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. */
22 #include "server.h"
23 #include "linux-low.h"
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 #include <thread_db.h>
40 #include <xc_ptrace.h>
42 #define TRACE_ENTER /* printf("enter %s\n", __FUNCTION__) */
44 long (*myptrace)(int xc_handle, enum __ptrace_request, uint32_t, long, long);
45 int (*myxcwait)(int xc_handle, int domain, int *status, int options) ;
46 static int xc_handle;
48 static inline int
49 curvcpuid()
50 {
51 struct process_info *process;
52 if (current_inferior == NULL)
53 return 0;
54 process = get_thread_process(current_inferior);
55 return (process->thread_known ? process->tid : 0);
57 }
60 #define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */
61 #define DOMFLAGS_SHUTDOWN (1<<2) /* The guest OS has shut down. */
62 #define DOMFLAGS_PAUSED (1<<3) /* Currently paused by control software. */
63 #define DOMFLAGS_BLOCKED (1<<4) /* Currently blocked pending an event. */
64 #define DOMFLAGS_RUNNING (1<<5) /* Domain is currently running. */
68 struct inferior_list all_processes;
69 static int current_domid;
70 static int expect_signal = 0;
71 static int signal_to_send = 0;
72 static void linux_resume (struct thread_resume *resume_info);
73 static void linux_set_inferior (void);
75 int debug_threads;
76 int using_threads;
77 extern int isfile;
79 struct pending_signals
80 {
81 int signal;
82 struct pending_signals *prev;
83 };
85 #define PTRACE_ARG3_TYPE long
86 #define PTRACE_XFER_TYPE long
88 static int use_regsets_p = 1;
91 #define pid_of(proc) ((proc)->head.id)
93 /* FIXME: Delete eventually. */
94 #define inferior_pid (pid_of (get_thread_process (current_inferior)))
96 /* This function should only be called if the process got a SIGTRAP.
97 The SIGTRAP could mean several things.
99 On i386, where decr_pc_after_break is non-zero:
100 If we were single-stepping this process using PTRACE_SINGLESTEP,
101 we will get only the one SIGTRAP (even if the instruction we
102 stepped over was a breakpoint). The value of $eip will be the
103 next instruction.
104 If we continue the process using PTRACE_CONT, we will get a
105 SIGTRAP when we hit a breakpoint. The value of $eip will be
106 the instruction after the breakpoint (i.e. needs to be
107 decremented). If we report the SIGTRAP to GDB, we must also
108 report the undecremented PC. If we cancel the SIGTRAP, we
109 must resume at the decremented PC.
111 (Presumably, not yet tested) On a non-decr_pc_after_break machine
112 with hardware or kernel single-step:
113 If we single-step over a breakpoint instruction, our PC will
114 point at the following instruction. If we continue and hit a
115 breakpoint instruction, our PC will point at the breakpoint
116 instruction. */
117 static CORE_ADDR
118 get_stop_pc (void)
119 {
120 CORE_ADDR stop_pc = (*the_low_target.get_pc) ();
122 if (get_thread_process (current_inferior)->stepping)
123 return stop_pc;
124 else
125 return stop_pc - the_low_target.decr_pc_after_break;
126 }
128 static void *
129 add_process (int pid, long tid)
130 {
131 struct process_info *process;
133 process = (struct process_info *) malloc (sizeof (*process));
134 memset (process, 0, sizeof (*process));
136 process->head.id = pid;
138 process->tid = tid;
139 process->lwpid = tid;
141 add_inferior_to_list (&all_processes, &process->head);
143 return process;
144 }
146 /* Start an inferior process and returns its pid.
147 ALLARGS is a vector of program-name and args. */
149 static int
150 linux_create_inferior (char *program, char **allargs)
151 {
153 fprintf (stderr, "Cannot exec %s: %s.\n", program,
154 strerror (errno));
155 fflush (stderr);
156 _exit (0177);
157 /* NOT REACHED */
158 return -1;
159 }
161 int
162 linux_attach (int domid)
163 {
164 struct process_info *new_process;
165 current_domid = domid;
166 /* this is handled for all active vcpus in PTRACE_ATTACH via the thread_create_callback */
167 new_process = (struct process_info *) add_process (domid, curvcpuid());
168 /* Don't ignore the initial SIGSTOP if we just attached to this process. */
169 /* vcpuid == 0 */
170 add_thread (0, new_process);
171 new_process->stop_expected = 0;
173 if (myptrace (xc_handle, PTRACE_ATTACH, domid, 0, 0) != 0) {
174 fprintf (stderr, "Cannot attach to domain %d: %s (%d)\n", domid,
175 strerror (errno), errno);
176 fflush (stderr);
177 if (!using_threads)
178 _exit (0177);
179 }
181 return 0;
182 }
184 /* Kill the inferior process. Make us have no inferior. */
186 static void
187 linux_kill_one_process (struct inferior_list_entry *entry)
188 {
189 struct thread_info *thread = (struct thread_info *) entry;
190 struct process_info *process = get_thread_process (thread);
191 myptrace (xc_handle, PTRACE_KILL, pid_of (process), 0, 0);
192 }
195 static void
196 linux_kill (void)
197 {
198 for_each_inferior (&all_threads, linux_kill_one_process);
199 }
201 static void
202 linux_detach_one_process (struct inferior_list_entry *entry)
203 {
205 myptrace (xc_handle, PTRACE_DETACH, current_domid, 0, 0);
206 }
209 static void
210 linux_detach (void)
211 {
212 for_each_inferior (&all_threads, linux_detach_one_process);
213 }
215 /* Return nonzero if the given thread is still alive. */
216 static int
217 linux_thread_alive (int tid)
218 {
219 if (find_inferior_id (&all_threads, tid) != NULL)
220 return 1;
221 else
222 return 0;
223 }
225 /* Wait for process, returns status. */
227 static unsigned char
228 linux_wait (char *status)
229 {
230 int w;
231 if (myxcwait(xc_handle, current_domid, &w, 0))
232 return -1;
234 linux_set_inferior();
236 *status = 'T';
237 if (expect_signal)
238 return expect_signal;
239 else
240 return SIGTRAP;
242 }
244 static void
245 linux_resume (struct thread_resume *resume_info)
246 {
247 int step = resume_info->step;
248 TRACE_ENTER;
249 expect_signal = resume_info->sig;
250 for_each_inferior(&all_threads, regcache_invalidate_one);
251 if (debug_threads)
252 fprintf(stderr, "step: %d\n", step);
253 myptrace (xc_handle, step ? PTRACE_SINGLESTEP : PTRACE_CONT,
254 resume_info->thread, 0, 0);
256 }
259 static int
260 regsets_fetch_inferior_registers ()
261 {
262 struct regset_info *regset;
263 TRACE_ENTER;
264 regset = target_regsets;
266 while (regset->size >= 0)
267 {
268 void *buf;
269 int res;
271 if (regset->size == 0)
272 {
273 regset ++;
274 continue;
275 }
277 buf = malloc (regset->size);
278 res = myptrace (xc_handle, regset->get_request,
279 curvcpuid(),
280 0, (PTRACE_XFER_TYPE)buf);
281 if (res < 0)
282 {
283 if (errno == EIO)
284 {
285 /* If we get EIO on the first regset, do not try regsets again.
286 If we get EIO on a later regset, disable that regset. */
287 if (regset == target_regsets)
288 {
289 use_regsets_p = 0;
290 return -1;
291 }
292 else
293 {
294 regset->size = 0;
295 continue;
296 }
297 }
298 else
299 {
300 char s[256];
301 sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d",
302 inferior_pid);
303 perror (s);
304 }
305 }
306 regset->store_function (buf);
307 regset ++;
308 }
309 return 0;
310 }
312 static int
313 regsets_store_inferior_registers ()
314 {
315 struct regset_info *regset;
316 TRACE_ENTER;
317 regset = target_regsets;
319 while (regset->size >= 0)
320 {
321 void *buf;
322 int res;
324 if (regset->size == 0)
325 {
326 regset ++;
327 continue;
328 }
330 buf = malloc (regset->size);
331 regset->fill_function (buf);
332 res = myptrace (xc_handle, regset->set_request, curvcpuid(), 0, (PTRACE_XFER_TYPE)buf);
333 if (res < 0)
334 {
335 if (errno == EIO)
336 {
337 /* If we get EIO on the first regset, do not try regsets again.
338 If we get EIO on a later regset, disable that regset. */
339 if (regset == target_regsets)
340 {
341 use_regsets_p = 0;
342 return -1;
343 }
344 else
345 {
346 regset->size = 0;
347 continue;
348 }
349 }
350 else
351 {
352 #ifdef DEBUG
353 perror ("Warning: ptrace(regsets_store_inferior_registers)");
354 #endif
355 }
356 }
357 regset ++;
358 free (buf);
359 }
360 return 0;
361 }
366 void
367 linux_fetch_registers (int regno)
368 {
369 if (use_regsets_p)
370 {
371 if (regsets_fetch_inferior_registers () == 0)
372 return;
373 }
375 }
377 void
378 linux_store_registers (int regno)
379 {
380 if (use_regsets_p)
381 {
382 if (regsets_store_inferior_registers () == 0)
383 return;
384 }
385 }
388 /* Copy LEN bytes from inferior's memory starting at MEMADDR
389 to debugger memory starting at MYADDR. */
391 static int
392 linux_read_memory (CORE_ADDR memaddr, char *myaddr, int len)
393 {
394 register int i;
395 /* Round starting address down to longword boundary. */
396 register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
397 /* Round ending address up; get number of longwords that makes. */
398 register int count
399 = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
400 / sizeof (PTRACE_XFER_TYPE);
401 /* Allocate buffer of that many longwords. */
402 register PTRACE_XFER_TYPE *buffer
403 = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
405 TRACE_ENTER;
406 /* Read all the longwords */
407 for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
408 {
409 errno = 0;
410 buffer[i] = myptrace (xc_handle, PTRACE_PEEKTEXT, curvcpuid(), (PTRACE_ARG3_TYPE) addr, 0);
411 if (errno)
412 return errno;
413 }
415 /* Copy appropriate bytes out of the buffer. */
416 memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len);
418 return 0;
419 }
421 /* Copy LEN bytes of data from debugger memory at MYADDR
422 to inferior's memory at MEMADDR.
423 On failure (cannot write the inferior)
424 returns the value of errno. */
426 static int
427 linux_write_memory (CORE_ADDR memaddr, const char *myaddr, int len)
428 {
429 register int i;
430 /* Round starting address down to longword boundary. */
431 register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
432 /* Round ending address up; get number of longwords that makes. */
433 register int count
434 = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) / sizeof (PTRACE_XFER_TYPE);
435 /* Allocate buffer of that many longwords. */
436 register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
437 extern int errno;
439 TRACE_ENTER;
441 /* Fill start and end extra bytes of buffer with existing memory data. */
443 buffer[0] = myptrace (xc_handle, PTRACE_PEEKTEXT, curvcpuid(),
444 (PTRACE_ARG3_TYPE) addr, 0);
446 if (count > 1)
447 {
448 buffer[count - 1]
449 = myptrace (xc_handle, PTRACE_PEEKTEXT, curvcpuid(),
450 (PTRACE_ARG3_TYPE) (addr + (count - 1)
451 * sizeof (PTRACE_XFER_TYPE)),
452 0);
453 }
455 /* Copy data to be written over corresponding part of buffer */
457 memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), myaddr, len);
459 /* Write the entire buffer. */
460 for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
461 {
462 errno = 0;
463 myptrace (xc_handle, PTRACE_POKETEXT, curvcpuid(),
464 (PTRACE_ARG3_TYPE) addr, buffer[i]);
465 if (errno)
466 return errno;
467 }
469 return 0;
470 }
472 static void
473 linux_look_up_symbols (void)
474 {
475 if (using_threads)
476 return;
478 using_threads = thread_db_init ();
480 }
482 static void
483 linux_send_signal (int signum)
484 {
485 extern int signal_pid;
487 TRACE_ENTER;
488 signal_to_send = signum;
489 psignal(signum, "need to send ");
490 if (cont_thread > 0)
491 {
492 struct process_info *process;
494 process = get_thread_process (current_inferior);
495 kill (process->lwpid, signum);
496 }
497 else
498 kill (signal_pid, signum);
499 }
501 /* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
502 to debugger memory starting at MYADDR. */
504 static int
505 linux_read_auxv (CORE_ADDR offset, char *myaddr, unsigned int len)
506 {
507 char filename[PATH_MAX];
508 int fd, n;
510 TRACE_ENTER;
511 snprintf (filename, sizeof filename, "/proc/%d/auxv", inferior_pid);
513 fd = open (filename, O_RDONLY);
514 if (fd < 0)
515 return -1;
517 if (offset != (CORE_ADDR) 0
518 && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
519 n = -1;
520 else
521 n = read (fd, myaddr, len);
523 close (fd);
525 return n;
526 }
529 static struct target_ops linux_xen_target_ops = {
530 linux_create_inferior,
531 linux_attach,
532 linux_kill,
533 linux_detach,
534 linux_thread_alive,
535 linux_resume,
536 linux_wait,
537 linux_fetch_registers,
538 linux_store_registers,
539 linux_read_memory,
540 linux_write_memory,
541 linux_look_up_symbols,
542 linux_send_signal,
543 linux_read_auxv,
544 };
546 static void
547 linux_init_signals ()
548 {
549 /* FIXME drow/2002-06-09: As above, we should check with LinuxThreads
550 to find what the cancel signal actually is. */
551 signal (__SIGRTMIN+1, SIG_IGN);
552 }
554 void
555 initialize_low (void)
556 {
557 using_threads = 0;
558 xc_handle = xc_interface_open();
559 set_target_ops (&linux_xen_target_ops);
560 set_breakpoint_data (the_low_target.breakpoint,
561 the_low_target.breakpoint_len);
562 init_registers ();
563 linux_init_signals ();
564 if (isfile) {
565 myptrace = xc_ptrace_core;
566 myxcwait = xc_waitdomain_core;
567 } else {
568 myptrace = xc_ptrace;
569 myxcwait = xc_waitdomain;
570 }
571 using_threads = thread_db_init ();
573 }
576 static void
577 thread_create_callback(long vcpuid)
578 {
579 struct thread_info *inferior;
580 struct process_info *process;
582 /* If we are attaching to our first thread, things are a little
583 * different.
584 */
585 if (all_threads.head == all_threads.tail)
586 {
587 inferior = (struct thread_info *) all_threads.head;
588 process = get_thread_process (inferior);
589 if (process->thread_known == 0)
590 {
591 /* Switch to indexing the threads list by TID. */
592 change_inferior_id (&all_threads, vcpuid);
593 goto found;
594 }
595 }
596 if (debug_threads)
597 fprintf (stderr, "looking up thread %ld\n",
598 vcpuid);
599 inferior = (struct thread_info *) find_inferior_id (&all_threads,
600 vcpuid);
601 /* if vcpu alread registered - do nothing */
602 if (inferior != NULL)
603 return;
605 if (debug_threads)
606 fprintf (stderr, "Attaching to thread %ld\n",
607 vcpuid);
609 process = add_process(current_domid, vcpuid);
611 add_thread(vcpuid, process);
612 inferior = (struct thread_info *) find_inferior_id (&all_threads,
613 vcpuid);
614 if (inferior == NULL)
615 {
616 warning ("Could not attach to thread %ld\n",
617 vcpuid);
618 return;
619 }
622 found:
623 if (debug_threads)
624 fprintf (stderr, "notifying of new thread %ld\n",
625 vcpuid);
626 new_thread_notify (vcpuid);
628 process->tid = vcpuid;
629 process->lwpid = vcpuid;
631 process->thread_known = 1;
632 }
634 static void
635 thread_death_callback(long vcpuid)
636 {
637 if (debug_threads)
638 fprintf (stderr, "Buuurp...! CPU down event.\n");
639 }
641 int
642 thread_db_init(void)
643 {
644 debug_threads = 0;
645 xc_register_event_handler(thread_create_callback, TD_CREATE);
646 xc_register_event_handler(thread_death_callback, TD_DEATH);
647 return 1;
648 }
650 /* XXX GAG ME */
651 static int breakpoint_found;
652 static void
653 set_breakpoint_inferior (struct inferior_list_entry *entry)
654 {
655 struct thread_info *thread = (struct thread_info *) entry;
656 struct thread_info *saved_inferior = current_inferior;
657 CORE_ADDR eip;
658 unsigned char buf[2] = {0, 0};
659 current_inferior = thread;
660 if (!breakpoint_found) {
661 eip = get_stop_pc();
662 linux_read_memory(eip, buf, 1);
663 if (buf[0] == 0xcc) {
664 breakpoint_found = 1;
665 return;
666 }
667 } else if (breakpoint_found == 2) {
668 if (get_thread_process (current_inferior)->stepping) {
669 printf("stepping\n");
670 breakpoint_found = 1;
671 return;
672 }
673 }
674 current_inferior = saved_inferior;
677 }
679 static void
680 linux_set_inferior (void)
681 {
682 breakpoint_found = 0;
683 for_each_inferior (&all_threads, set_breakpoint_inferior);
684 if (!breakpoint_found) {
685 breakpoint_found = 2;
686 for_each_inferior (&all_threads, set_breakpoint_inferior);
687 }
688 }