From 8785ced03ac5b8817f23f2bbfa590763a535cac2 Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Mon, 10 Jan 2005 20:36:38 +0000 Subject: * inf-ptrace.h: Update copyright year. Sync comment with inf-ptrace.c. (inf_ptrace_trad_target): New prototype. * inf-ptrace.c: Update copyright year. Include "regcache.h" and "gdb_assert.h" (inf_ptrace_target): Add comment. (inf_ptrace+register_u_offset): New variable. (inf_ptrace_fetch_register, inf_ptrace_fetch_registers) (inf_ptrace_store_register, inf_ptrace_store_registers) (inf_ptrace_trad_target): New functions. * Makefile.in (inf-ptrace.o): Update dependencies. --- gdb/ChangeLog | 14 ++++++ gdb/Makefile.in | 4 +- gdb/inf-ptrace.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- gdb/inf-ptrace.h | 12 +++-- 4 files changed, 156 insertions(+), 6 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4fc76e1..d3c3a7b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2005-01-10 Mark Kettenis + + * inf-ptrace.h: Update copyright year. Sync comment with + inf-ptrace.c. + (inf_ptrace_trad_target): New prototype. + * inf-ptrace.c: Update copyright year. Include "regcache.h" and + "gdb_assert.h" + (inf_ptrace_target): Add comment. + (inf_ptrace+register_u_offset): New variable. + (inf_ptrace_fetch_register, inf_ptrace_fetch_registers) + (inf_ptrace_store_register, inf_ptrace_store_registers) + (inf_ptrace_trad_target): New functions. + * Makefile.in (inf-ptrace.o): Update dependencies. + 2005-01-09 Mark Kettenis * configure.ac: Provide prerequisite headers when checking diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 77f5e62..68c2a60 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -2079,8 +2079,8 @@ inflow.o: inflow.c $(defs_h) $(frame_h) $(inferior_h) $(command_h) \ $(serial_h) $(terminal_h) $(target_h) $(gdbthread_h) $(gdb_string_h) \ $(inflow_h) inf-ptrace.o: inf-ptrace.c $(defs_h) $(command_h) $(inferior_h) $(inflow_h) \ - $(gdbcore_h) $(observer_h) $(gdb_string_h) $(gdb_ptrace_h) \ - $(gdb_wait_h) $(inf_child_h) + $(gdbcore_h) $(observer_h) $(regcache_h) $(gdb_assert_h) \ + $(gdb_string_h) $(gdb_ptrace_h) $(gdb_wait_h) $(inf_child_h) inf-ttrace.o: inf-ttrace.c $(defs_h) $(command_h) $(gdbcore_h) \ $(gdbthread_h) $(inferior_h) $(observer_h) $(target_h) \ $(gdb_assert_h) $(gdb_string_h) $(inf_child_h) $(inf_ttrace_h) diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c index c2f5ead..821e424 100644 --- a/gdb/inf-ptrace.c +++ b/gdb/inf-ptrace.c @@ -1,7 +1,8 @@ /* Low-level child interface to ptrace. Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, - 1998, 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2004, 2005 + Free Software Foundation, Inc. This file is part of GDB. @@ -26,7 +27,9 @@ #include "inflow.h" #include "gdbcore.h" #include "observer.h" +#include "regcache.h" +#include "gdb_assert.h" #include "gdb_string.h" #include "gdb_ptrace.h" #include "gdb_wait.h" @@ -592,10 +595,14 @@ inf_ptrace_pid_to_str (ptid_t ptid) return normal_pid_to_str (ptid); } +/* Create a prototype ptrace target. The client can override it with + local methods. */ + struct target_ops * inf_ptrace_target (void) { struct target_ops *t = inf_child_target (); + t->to_open = inf_ptrace_open; t->to_attach = inf_ptrace_attach; t->to_post_attach = inf_ptrace_post_attach; @@ -633,5 +640,128 @@ inf_ptrace_target (void) t->to_has_execution = 1; t->to_magic = OPS_MAGIC; ptrace_ops_hack = t; + + return t; +} + + +/* Pointer to a function that returns the oggset within the user area + where a particular register is stored. */ +static CORE_ADDR (*inf_ptrace_register_u_offset)(int); + +/* Fetch register REGNUM from the inferior. */ + +static void +inf_ptrace_fetch_register (int regnum) +{ + CORE_ADDR addr; + size_t size; + PTRACE_TYPE_RET *buf; + int pid, i; + + /* Cater for systems like GNU/Linux, that implement threads as + seperate processes. */ + pid = ptid_get_lwp (inferior_ptid); + if (pid == 0) + pid = ptid_get_pid (inferior_ptid); + + /* This isn't really an address, but ptrace thinks of it as one. */ + addr = inf_ptrace_register_u_offset (regnum); + size = register_size (current_gdbarch, regnum); + + gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0); + buf = alloca (size); + + /* Read the register contents from the inferior a chuck at the time. */ + for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++) + { + errno = 0; + buf[i] = ptrace (PT_READ_U, pid, (PTRACE_TYPE_ARG3) addr, 0); + if (errno != 0) + error ("Couldn't read register %s (#%d): %s.", REGISTER_NAME (regnum), + regnum, safe_strerror (errno)); + + addr += sizeof (PTRACE_TYPE_RET); + } + regcache_raw_supply (current_regcache, regnum, buf); +} + +/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this + for all registers. */ + +static void +inf_ptrace_fetch_registers (int regnum) +{ + if (regnum == -1) + for (regnum = 0; regnum < NUM_REGS; regnum++) + inf_ptrace_fetch_register (regnum); + else + inf_ptrace_fetch_register (regnum); +} + +/* Store register REGNUM into the inferior. */ + +static void +inf_ptrace_store_register (int regnum) +{ + CORE_ADDR addr; + size_t size; + PTRACE_TYPE_RET *buf; + int pid, i; + + /* Cater for systems like GNU/Linux, that implement threads as + seperate processes. */ + pid = ptid_get_lwp (inferior_ptid); + if (pid == 0) + pid = ptid_get_pid (inferior_ptid); + + /* This isn't really an address, but ptrace thinks of it as one. */ + addr = inf_ptrace_register_u_offset (regnum); + size = register_size (current_gdbarch, regnum); + + gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0); + buf = alloca (size); + + /* Write the register contents into the inferior a chunk at the time. */ + regcache_raw_collect (current_regcache, regnum, buf); + for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++) + { + errno = 0; + ptrace (PT_WRITE_U, pid, (PTRACE_TYPE_ARG3) addr, buf[i]); + if (errno != 0) + error ("Couldn't write register %s (#%d): %s.", REGISTER_NAME (regnum), + regnum, safe_strerror (errno)); + + addr += sizeof (PTRACE_TYPE_RET); + } +} + +/* Store register REGNUM back into the inferior. If REGNUM is -1, do + this for all registers. */ + +void +inf_ptrace_store_registers (int regnum) +{ + if (regnum == -1) + for (regnum = 0; regnum < NUM_REGS; regnum++) + inf_ptrace_store_register (regnum); + else + inf_ptrace_store_register (regnum); +} + +/* Create a "traditional" ptrace target. REGISTER_U_OFFSET should be + a function returning the offset within the user area where a + particular register is stored. */ + +struct target_ops * +inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)(int)) +{ + struct target_ops *t = inf_ptrace_target(); + + gdb_assert (register_u_offset); + inf_ptrace_register_u_offset = register_u_offset; + t->to_fetch_registers = inf_ptrace_fetch_registers; + t->to_store_registers = inf_ptrace_store_registers; + return t; } diff --git a/gdb/inf-ptrace.h b/gdb/inf-ptrace.h index e9ceae3..ef86b51 100644 --- a/gdb/inf-ptrace.h +++ b/gdb/inf-ptrace.h @@ -1,7 +1,6 @@ -/* Low level Unix child interface to ptrace, for GDB when running - under Unix. +/* Low level child interface to ptrace. - Copyright 2004 Free Software Foundation, Inc. + Copyright 2004, 2005 Free Software Foundation, Inc. This file is part of GDB. @@ -28,4 +27,11 @@ extern struct target_ops *inf_ptrace_target (void); +/* Create a "traditional" ptrace target. REGISTER_U_OFFSET should be + a function returning the offset within the user area where a + particular register is stored. */ + +extern struct target_ops * + inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)(int)); + #endif -- cgit v1.1