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. */
23
#include "linux-low.h"
27
#include <sys/param.h>
29
#include <sys/ptrace.h>
32
#include <sys/ioctl.h>
40
#define TRACE_ENTER /* printf("enter %s\n", __FUNCTION__) */
47
struct process_info *process;
48
if (current_inferior == NULL)
50
process = get_thread_process(current_inferior);
51
return (process->thread_known ? process->tid : 0);
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);
66
struct pending_signals
69
struct pending_signals *prev;
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
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
107
CORE_ADDR stop_pc = (*the_low_target.get_pc) ();
109
if (get_thread_process (current_inferior)->stepping)
112
return stop_pc - the_low_target.decr_pc_after_break;
116
add_process (int pid, long tid)
118
struct process_info *process;
120
process = (struct process_info *) malloc (sizeof (*process));
121
memset (process, 0, sizeof (*process));
123
process->head.id = pid;
126
process->lwpid = tid;
128
add_inferior_to_list (&all_processes, &process->head);
133
/* Start an inferior process and returns its pid.
134
ALLARGS is a vector of program-name and args. */
137
linux_create_inferior (char *program, char **allargs)
140
fprintf (stderr, "Cannot exec %s: %s.\n", program,
149
linux_attach (int domid)
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. */
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);
171
/* Kill the inferior process. Make us have no inferior. */
174
linux_kill_one_process (struct inferior_list_entry *entry)
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);
185
for_each_inferior (&all_threads, linux_kill_one_process);
189
linux_detach_one_process (struct inferior_list_entry *entry)
192
xc_ptrace (xc_handle, PTRACE_DETACH, current_domid, 0, 0);
199
for_each_inferior (&all_threads, linux_detach_one_process);
202
/* Return nonzero if the given thread is still alive. */
204
linux_thread_alive (int tid)
206
if (find_inferior_id (&all_threads, tid) != NULL)
212
/* Wait for process, returns status. */
215
linux_wait (char *status)
218
if (xc_waitdomain(xc_handle, current_domid, &w, 0))
223
return expect_signal;
230
linux_resume (struct thread_resume *resume_info)
232
int step = resume_info->step;
234
expect_signal = resume_info->sig;
235
for_each_inferior(&all_threads, regcache_invalidate_one);
237
fprintf(stderr, "step: %d\n", step);
238
xc_ptrace (xc_handle, step ? PTRACE_SINGLESTEP : PTRACE_CONT,
239
resume_info->thread, 0, 0);
245
regsets_fetch_inferior_registers ()
247
struct regset_info *regset;
249
regset = target_regsets;
251
while (regset->size >= 0)
256
if (regset->size == 0)
262
buf = malloc (regset->size);
263
res = xc_ptrace (xc_handle, regset->get_request,
265
0, (PTRACE_XFER_TYPE)buf);
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)
286
sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d",
291
regset->store_function (buf);
298
regsets_store_inferior_registers ()
300
struct regset_info *regset;
302
regset = target_regsets;
304
while (regset->size >= 0)
309
if (regset->size == 0)
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);
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)
338
perror ("Warning: ptrace(regsets_store_inferior_registers)");
352
linux_fetch_registers (int regno)
356
if (regsets_fetch_inferior_registers () == 0)
363
linux_store_registers (int regno)
367
if (regsets_store_inferior_registers () == 0)
373
/* Copy LEN bytes from inferior's memory starting at MEMADDR
374
to debugger memory starting at MYADDR. */
377
linux_read_memory (CORE_ADDR memaddr, char *myaddr, int len)
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. */
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));
391
/* Read all the longwords */
392
for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
395
buffer[i] = xc_ptrace (xc_handle, PTRACE_PEEKTEXT, curvcpuid(), (PTRACE_ARG3_TYPE) addr, 0);
400
/* Copy appropriate bytes out of the buffer. */
401
memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len);
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. */
412
linux_write_memory (CORE_ADDR memaddr, const char *myaddr, int len)
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. */
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));
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);
434
= xc_ptrace (xc_handle, PTRACE_PEEKTEXT, curvcpuid(),
435
(PTRACE_ARG3_TYPE) (addr + (count - 1)
436
* sizeof (PTRACE_XFER_TYPE)),
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))
448
xc_ptrace (xc_handle, PTRACE_POKETEXT, curvcpuid(),
449
(PTRACE_ARG3_TYPE) addr, buffer[i]);
458
linux_look_up_symbols (void)
463
using_threads = thread_db_init ();
468
linux_send_signal (int signum)
470
extern int signal_pid;
473
signal_to_send = signum;
474
psignal(signum, "need to send ");
477
struct process_info *process;
479
process = get_thread_process (current_inferior);
480
kill (process->lwpid, signum);
483
kill (signal_pid, signum);
486
/* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
487
to debugger memory starting at MYADDR. */
490
linux_read_auxv (CORE_ADDR offset, char *myaddr, unsigned int len)
492
char filename[PATH_MAX];
496
snprintf (filename, sizeof filename, "/proc/%d/auxv", inferior_pid);
498
fd = open (filename, O_RDONLY);
502
if (offset != (CORE_ADDR) 0
503
&& lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
506
n = read (fd, myaddr, len);
514
static struct target_ops linux_xen_target_ops = {
515
linux_create_inferior,
522
linux_fetch_registers,
523
linux_store_registers,
526
linux_look_up_symbols,
532
linux_init_signals ()
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);
540
initialize_low (void)
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);
548
linux_init_signals ();
549
using_threads = thread_db_init ();
555
thread_create_callback(long vcpuid)
557
struct thread_info *inferior;
558
struct process_info *process;
560
/* If we are attaching to our first thread, things are a little
563
if (all_threads.head == all_threads.tail)
565
inferior = (struct thread_info *) all_threads.head;
566
process = get_thread_process (inferior);
567
if (process->thread_known == 0)
569
/* Switch to indexing the threads list by TID. */
570
change_inferior_id (&all_threads, vcpuid);
575
fprintf (stderr, "looking up thread %ld\n",
577
inferior = (struct thread_info *) find_inferior_id (&all_threads,
579
/* if vcpu alread registered - do nothing */
580
if (inferior != NULL)
584
fprintf (stderr, "Attaching to thread %ld\n",
587
process = add_process(current_domid, vcpuid);
589
add_thread(vcpuid, process);
590
inferior = (struct thread_info *) find_inferior_id (&all_threads,
592
if (inferior == NULL)
594
warning ("Could not attach to thread %ld\n",
602
fprintf (stderr, "notifying of new thread %ld\n",
604
new_thread_notify (vcpuid);
606
process->tid = vcpuid;
607
process->lwpid = vcpuid;
609
process->thread_known = 1;
613
thread_death_callback(long vcpuid)
616
fprintf (stderr, "Buuurp...! CPU down event.\n");
623
xc_register_event_handler(thread_create_callback, TD_CREATE);
624
xc_register_event_handler(thread_death_callback, TD_DEATH);
629
static int breakpoint_found;
631
set_breakpoint_inferior (struct inferior_list_entry *entry)
633
struct thread_info *thread = (struct thread_info *) entry;
634
struct thread_info *saved_inferior = current_inferior;
636
unsigned char buf[2] = {0, 0};
637
current_inferior = thread;
638
if (!breakpoint_found) {
640
linux_read_memory(eip, buf, 1);
641
if (buf[0] == 0xcc) {
642
breakpoint_found = 1;
645
} else if (breakpoint_found == 2) {
646
if (get_thread_process (current_inferior)->stepping) {
647
printf("stepping\n");
648
breakpoint_found = 1;
652
current_inferior = saved_inferior;
658
linux_set_inferior (void)
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);