direct-io.hg

view tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c @ 11774:5d2ce349f9f4

[SOLARIS] Don't build ptrace code on Solaris.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Tue Oct 17 17:59:32 2006 +0100 (2006-10-17)
parents 86d26e6ec89b
children
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>
40 #define TRACE_ENTER /* printf("enter %s\n", __FUNCTION__) */
42 static int xc_handle;
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);
53 }
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);
62 int debug_threads;
63 int using_threads;
64 extern int isfile;
66 struct pending_signals
67 {
68 int signal;
69 struct pending_signals *prev;
70 };
72 #define PTRACE_ARG3_TYPE long
73 #define PTRACE_XFER_TYPE long
75 static int use_regsets_p = 1;
78 #define pid_of(proc) ((proc)->head.id)
80 /* FIXME: Delete eventually. */
81 #define inferior_pid (pid_of (get_thread_process (current_inferior)))
83 /* This function should only be called if the process got a SIGTRAP.
84 The SIGTRAP could mean several things.
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.
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) ();
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 }
115 static void *
116 add_process (int pid, long tid)
117 {
118 struct process_info *process;
120 process = (struct process_info *) malloc (sizeof (*process));
121 memset (process, 0, sizeof (*process));
123 process->head.id = pid;
125 process->tid = tid;
126 process->lwpid = tid;
128 add_inferior_to_list (&all_processes, &process->head);
130 return process;
131 }
133 /* Start an inferior process and returns its pid.
134 ALLARGS is a vector of program-name and args. */
136 static int
137 linux_create_inferior (char *program, char **allargs)
138 {
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 }
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;
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 }
168 return 0;
169 }
171 /* Kill the inferior process. Make us have no inferior. */
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 }
182 static void
183 linux_kill (void)
184 {
185 for_each_inferior (&all_threads, linux_kill_one_process);
186 }
188 static void
189 linux_detach_one_process (struct inferior_list_entry *entry)
190 {
192 xc_ptrace (xc_handle, PTRACE_DETACH, current_domid, 0, 0);
193 }
196 static void
197 linux_detach (void)
198 {
199 for_each_inferior (&all_threads, linux_detach_one_process);
200 }
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 }
212 /* Wait for process, returns status. */
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;
221 *status = 'T';
222 if (expect_signal)
223 return expect_signal;
224 else
225 return SIGTRAP;
227 }
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);
241 }
244 static int
245 regsets_fetch_inferior_registers ()
246 {
247 struct regset_info *regset;
248 TRACE_ENTER;
249 regset = target_regsets;
251 while (regset->size >= 0)
252 {
253 void *buf;
254 int res;
256 if (regset->size == 0)
257 {
258 regset ++;
259 continue;
260 }
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 }
297 static int
298 regsets_store_inferior_registers ()
299 {
300 struct regset_info *regset;
301 TRACE_ENTER;
302 regset = target_regsets;
304 while (regset->size >= 0)
305 {
306 void *buf;
307 int res;
309 if (regset->size == 0)
310 {
311 regset ++;
312 continue;
313 }
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 }
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 }
360 }
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 }
373 /* Copy LEN bytes from inferior's memory starting at MEMADDR
374 to debugger memory starting at MYADDR. */
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));
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 }
400 /* Copy appropriate bytes out of the buffer. */
401 memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len);
403 return 0;
404 }
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. */
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;
424 TRACE_ENTER;
426 /* Fill start and end extra bytes of buffer with existing memory data. */
428 buffer[0] = xc_ptrace (xc_handle, PTRACE_PEEKTEXT, curvcpuid(),
429 (PTRACE_ARG3_TYPE) addr, 0);
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 }
440 /* Copy data to be written over corresponding part of buffer */
442 memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), myaddr, len);
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 }
454 return 0;
455 }
457 static void
458 linux_look_up_symbols (void)
459 {
460 if (using_threads)
461 return;
463 using_threads = thread_db_init ();
465 }
467 static void
468 linux_send_signal (int signum)
469 {
470 extern int signal_pid;
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;
479 process = get_thread_process (current_inferior);
480 kill (process->lwpid, signum);
481 }
482 else
483 kill (signal_pid, signum);
484 }
486 /* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
487 to debugger memory starting at MYADDR. */
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;
495 TRACE_ENTER;
496 snprintf (filename, sizeof filename, "/proc/%d/auxv", inferior_pid);
498 fd = open (filename, O_RDONLY);
499 if (fd < 0)
500 return -1;
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);
508 close (fd);
510 return n;
511 }
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 };
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 }
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 ();
551 }
554 static void
555 thread_create_callback(long vcpuid)
556 {
557 struct thread_info *inferior;
558 struct process_info *process;
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;
583 if (debug_threads)
584 fprintf (stderr, "Attaching to thread %ld\n",
585 vcpuid);
587 process = add_process(current_domid, vcpuid);
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 }
600 found:
601 if (debug_threads)
602 fprintf (stderr, "notifying of new thread %ld\n",
603 vcpuid);
604 new_thread_notify (vcpuid);
606 process->tid = vcpuid;
607 process->lwpid = vcpuid;
609 process->thread_known = 1;
610 }
612 static void
613 thread_death_callback(long vcpuid)
614 {
615 if (debug_threads)
616 fprintf (stderr, "Buuurp...! CPU down event.\n");
617 }
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 }
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;
655 }
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 }