aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorJoel Brobecker <brobecker@gnat.com>2012-08-16 23:55:02 +0000
committerJoel Brobecker <brobecker@gnat.com>2012-08-16 23:55:02 +0000
commit973e3cf70d3a47d0093916dbe8459bee2e5f41cb (patch)
treee4958df1f656f8314846b9bed87acab030239195 /gdb
parentd80ee84fe21876c78f66e60b70e335e8dab99d07 (diff)
downloadbinutils-973e3cf70d3a47d0093916dbe8459bee2e5f41cb.zip
binutils-973e3cf70d3a47d0093916dbe8459bee2e5f41cb.tar.gz
binutils-973e3cf70d3a47d0093916dbe8459bee2e5f41cb.tar.bz2
fix internal_error during fork event handling.
When running on ia64-hpux a program that calls fork, GDB currently reports the following internal error: internal-error: Can't determine the current address space of thread process 1882 Here is what happens: 1. GDB receives a "fork" event; 2. handle_inferior_event calls detach_breakpoints for the child process; 3. detach_breakpoints calls ia64's gdbarch remove_breakpoint hook, which needs to read an entire instruction slot in order to remove a breakpoint instruction from memory; 4. To read inferior memory, the ia64-hpux code needs to know where that memory is located relative to the bsp..bspstore area, and thus needs to read the value of those registers; 5. To get the value of those registers, ia64_hpux_xfer_memory current uses the current regcache. The problem is that at the time we are trying to remove the breakpoints from the child, the child process is not part of the list of inferiors really known to GDB (it has not been added to inferior_list), so trying to create a regcache for it triggers an internal error when creating address space for the regcache (as the address space is ultimately fetched from the inferior). To work around this limitation, ia64_hpux_xfer_memory has been modified to detect the fact the current inferior is not in our inferior list, and to go, in that case, straight to the source to fetch the registers it needs. gdb/ChangeLog: * ia64-hpux-nat.c (ia64_hpux_get_register_from_save_state_t): New function. (ia64_hpux_xfer_memory): Check if inferior_ptid is known before using the regache. Use ia64_hpux_get_register_from_save_state_t to access the bsp and bspstore registers if not.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog8
-rw-r--r--gdb/ia64-hpux-nat.c52
2 files changed, 57 insertions, 3 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f52139f..ec0532e 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,13 @@
2012-08-16 Joel Brobecker <brobecker@adacore.com>
+ * ia64-hpux-nat.c (ia64_hpux_get_register_from_save_state_t):
+ New function.
+ (ia64_hpux_xfer_memory): Check if inferior_ptid is known before
+ using the regache. Use ia64_hpux_get_register_from_save_state_t
+ to access the bsp and bspstore registers if not.
+
+2012-08-16 Joel Brobecker <brobecker@adacore.com>
+
* breakpoint.h (detach_breakpoints): pid parameter is now a ptid.
* breakpoint.c (detach_breakpoints): Change pid parameter into
a ptid. Adjust code accordingly.
diff --git a/gdb/ia64-hpux-nat.c b/gdb/ia64-hpux-nat.c
index 07a433e..741d3d8 100644
--- a/gdb/ia64-hpux-nat.c
+++ b/gdb/ia64-hpux-nat.c
@@ -485,6 +485,37 @@ ia64_hpux_xfer_memory_bs (struct target_ops *ops, const char *annex,
return 0;
}
+/* Get a register value as a unsigned value directly from the system,
+ instead of going through the regcache.
+
+ This function is meant to be used when inferior_ptid is not
+ a thread/process known to GDB. */
+
+static ULONGEST
+ia64_hpux_get_register_from_save_state_t (int regnum, int reg_size)
+{
+ gdb_byte *buf = alloca (reg_size);
+ int offset = u_offsets[regnum];
+ int status;
+
+ /* The register is assumed to be available for fetching. */
+ gdb_assert (offset != -1);
+
+ status = ia64_hpux_read_register_from_save_state_t (offset, buf, reg_size);
+ if (status < 0)
+ {
+ /* This really should not happen. If it does, emit a warning
+ and pretend the register value is zero. Not exactly the best
+ error recovery mechanism, but better than nothing. We will
+ try to do better if we can demonstrate that this can happen
+ under normal circumstances. */
+ warning (_("Failed to read value of register number %d."), regnum);
+ return 0;
+ }
+
+ return extract_unsigned_integer (buf, reg_size, BFD_ENDIAN_BIG);
+}
+
/* The "xfer_partial" target_ops routine for ia64-hpux, in the case
where the requested object is TARGET_OBJECT_MEMORY. */
@@ -504,9 +535,24 @@ ia64_hpux_xfer_memory (struct target_ops *ops, const char *annex,
(3) The region inside the backing-store, which needs to be
read/written specially. */
- regcache_raw_read_unsigned (get_current_regcache (), IA64_BSP_REGNUM, &bsp);
- regcache_raw_read_unsigned (get_current_regcache (), IA64_BSPSTORE_REGNUM,
- &bspstore);
+ if (in_inferior_list (ptid_get_pid (inferior_ptid)))
+ {
+ struct regcache *regcache = get_current_regcache ();
+
+ regcache_raw_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
+ regcache_raw_read_unsigned (regcache, IA64_BSPSTORE_REGNUM, &bspstore);
+ }
+ else
+ {
+ /* This is probably a child of our inferior created by a fork.
+ Because this process has not been added to our inferior list
+ (we are probably in the process of handling that child
+ process), we do not have a regcache to read the registers
+ from. So get those values directly from the kernel. */
+ bsp = ia64_hpux_get_register_from_save_state_t (IA64_BSP_REGNUM, 8);
+ bspstore =
+ ia64_hpux_get_register_from_save_state_t (IA64_BSPSTORE_REGNUM, 8);
+ }
/* 1. Memory region before BSPSTORE. */