diff options
author | Joel Brobecker <brobecker@gnat.com> | 2011-01-13 16:24:27 +0000 |
---|---|---|
committer | Joel Brobecker <brobecker@gnat.com> | 2011-01-13 16:24:27 +0000 |
commit | 77ca787b12516ebb1b0d23710021b26b9c81b018 (patch) | |
tree | c566d4c91a59e95671e251887b36d704ec6e8d1a /gdb/ia64-hpux-tdep.c | |
parent | 92c9a4639bb3294d74a36b6d0c0cb07771bbe906 (diff) | |
download | gdb-77ca787b12516ebb1b0d23710021b26b9c81b018.zip gdb-77ca787b12516ebb1b0d23710021b26b9c81b018.tar.gz gdb-77ca787b12516ebb1b0d23710021b26b9c81b018.tar.bz2 |
[ia64-hpux] unwinding bsp value from system call
This fixes unwinding from a thread that is stopped inside a system call.
This can be seen when switching to a thread that is stopped doing a
pthread_cond_wait, for instance...
The comments inside the code should explain what is happening in our
case (the HP-UX exception in the case of system calls): Under certain
circumstances (program stopped inside syscall), the offset to apply to
the current BSP in order to compute the previous BSP is not the usual
CFM & 0x7f.
We parts in this patch:
1. Figuring out that we are stopped inside a syscal: This requires
a TT_LWP_RUREGS ttrace call, which is not directly possible from
ia64-tdep.c. So use defined a new TARGET_OBJECT_HPUX_UREGS object
to request it from the -nat side.
2. Add a gdbarch_tdep method that allows us to change the default
behavior on ia64-hpux, permitting us to have a different "size of
register frame" in that one particular case.
gdb/ChangeLog:
* target.h (enum target_object): Add TARGET_OBJECT_HPUX_UREGS.
* ia64-tdep.h (struct frame_info): forward declaration.
(struct gdbarch_tdep): Add field size_of_register_frame.
* ia64-tdep.c (ia64_access_reg): Use tdep->size_of_register_frame
to determine the size of the register frame.
(ia64_size_of_register_frame): New function.
(ia64_gdbarch_init): Set tdep->size_of_register_frame.
* ia64-hpux-tdep.c: Include "target.h" and "frame.h".
(IA64_HPUX_UREG_REASON): New macro.
(ia64_hpux_stopped_in_syscall, ia64_hpux_size_of_register_frame):
New functions.
(ia64_hpux_init_abi): Set tdep->size_of_register_frame.
* ia64-hpux-nat.c (ia64_hpux_xfer_uregs): New function.
(ia64_hpux_xfer_partial): Add handling of TARGET_OBJECT_HPUX_UREGS
objects.
Diffstat (limited to 'gdb/ia64-hpux-tdep.c')
-rw-r--r-- | gdb/ia64-hpux-tdep.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/gdb/ia64-hpux-tdep.c b/gdb/ia64-hpux-tdep.c index 139ff83..a4d2fa7 100644 --- a/gdb/ia64-hpux-tdep.c +++ b/gdb/ia64-hpux-tdep.c @@ -23,6 +23,17 @@ #include "osabi.h" #include "gdbtypes.h" #include "solib.h" +#include "target.h" +#include "frame.h" + +/* The offset to be used in order to get the __reason pseudo-register + when using one of the *UREGS ttrace requests (see system header file + /usr/include/ia64/sys/uregs.h for more details). + + The documentation for this pseudo-register says that a nonzero value + indicates that the thread stopped due to a fault, trap, or interrupt. + A null value indicates a stop inside a syscall. */ +#define IA64_HPUX_UREG_REASON 0x00070000 /* Return nonzero if the value of the register identified by REGNUM can be modified. */ @@ -74,6 +85,47 @@ ia64_hpux_cannot_store_register (struct gdbarch *gdbarch, int regnum) return 0; } +/* Return nonzero if the inferior is stopped inside a system call. */ + +static int +ia64_hpux_stopped_in_syscall (struct gdbarch *gdbarch) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct target_ops *ops = ¤t_target; + gdb_byte buf[8]; + int len; + + len = target_read (ops, TARGET_OBJECT_HPUX_UREGS, NULL, + buf, IA64_HPUX_UREG_REASON, sizeof (buf)); + if (len == -1) + /* The target wasn't able to tell us. Assume we are not stopped + in a system call, which is the normal situation. */ + return 0; + gdb_assert (len == 8); + + return (extract_unsigned_integer (buf, len, byte_order) == 0); +} + +/* The "size_of_register_frame" gdbarch_tdep routine for ia64-hpux. */ + +static int +ia64_hpux_size_of_register_frame (struct frame_info *this_frame, + ULONGEST cfm) +{ + int sof; + + if (frame_relative_level (this_frame) == 0 + && ia64_hpux_stopped_in_syscall (get_frame_arch (this_frame))) + /* If the inferior stopped in a system call, the base address + of the register frame is at BSP - SOL instead of BSP - SOF. + This is an HP-UX exception. */ + sof = (cfm & 0x3f80) >> 7; + else + sof = (cfm & 0x7f); + + return sof; +} + /* Should be set to non-NULL if the ia64-hpux solib module is linked in. This may not be the case because the shared library support code can only be compiled on ia64-hpux. */ @@ -83,6 +135,10 @@ struct target_so_ops *ia64_hpux_so_ops = NULL; static void ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + tdep->size_of_register_frame = ia64_hpux_size_of_register_frame; + set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad); set_gdbarch_cannot_store_register (gdbarch, ia64_hpux_cannot_store_register); |