aboutsummaryrefslogtreecommitdiff
path: root/gdb/regcache.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2016-07-01 11:56:39 +0100
committerPedro Alves <palves@redhat.com>2016-07-01 11:56:39 +0100
commit20aa2c606ef682889722b03b1d874befa84fbf53 (patch)
treec8065566524f06148aa653ca90a58e73af5c2c26 /gdb/regcache.c
parentced2dffbf17bc661e959da1e39411d706ade9f77 (diff)
downloadgdb-20aa2c606ef682889722b03b1d874befa84fbf53.zip
gdb-20aa2c606ef682889722b03b1d874befa84fbf53.tar.gz
gdb-20aa2c606ef682889722b03b1d874befa84fbf53.tar.bz2
Extend JIT-reader test and fix GDB problems that exposes
The jit-reader.exp test isn't really exercising the jit-reader's unwinder API at all. This commit address that, and then fixes GDB problems exposed. - The custom JIT reader provided for the jit-reader.exp testcase always rejects the jitted function's frame... This is because the custom JIT reader in the testcase never ever sets state->code_begin/end, so the bounds check in gdb.base/jitreader.c:unwind_frame: if (this_ip >= state->code_end || this_ip < state->code_begin) return GDB_FAIL; tends to fail, unless you're "lucky" (because it references uninitialized data). The result is that GDB is always actually using a built-in unwinder for the jitted function. - The provided unwinder doesn't do anything that GDB's built-in unwinder can't do. IOW, we can't really tell whether the JIT reader's unwinder is working or not. I fixed that by making the jitted function mangle its own stack pointer with a xor, and then teaching the jit unwinder to demangle it back (another xor). So now "backtrace" with GDB's built-in unwinder fails while with the jit unwinder, it succeeds. - GDB crashes after unloading the JIT reader, and flushing frames... I made the testcase use the "flushregs" command after unloading the JIT reader, to force the JIT frames to be flushed. However, that crashes GDB... When reinit_frame_cache tears down a frame's cache, it calls its unwinder's dealloc_cache method, which for JIT frames ends up in jit.c:jit_dealloc_cache. This function calls each of the frame's gdb_reg_value's "free" pointer: for (i = 0; i < gdbarch_num_regs (frame_arch); i++) if (priv_data->registers[i] && priv_data->registers[i]->free) priv_data->registers[i]->free (priv_data->registers[i]); and the problem is these gdb_reg_value instances have been returned by the JIT reader that has been already unloaded, and their "free" function pointers likely point to functions in the DSO that has already been unloaded... A fix for that could be to call reinit_frame_cache in jit_reader_unload_command _before_ unloading the jit reader DSO so that the jit reader is given a chance to clean up the gdb_reg_values before it is unloaded. However, the fix for the point below makes this unnecessary, because it stops jit.c from keeping around gdb_reg_values in the first place. - However, it still makes sense to clear the frame cache when loading or unloading a JIT unwinder. This makes testing a JIT unwinder a bit simpler. - Not only the frame cache actually -- gdb is not unloading the jit-registered objfiles when the JIT reader is unloaded, and not loading the already-registered descriptors when a JIT reader is loaded. The new test exercises unloading the jit reader, loading it back again, and then making sure the JIT reader's unwinder works again. Without the unload/re-load of already-read descriptors, the newly loaded JIT would have no idea where the new function is, because it's stored at symbol read time. - I added a couple "info frame" calls to the test, and that crashes GDB... The problem is that jit_frame_prev_register assumes it'll only be called for raw registers, so when it gets a pseudo register number, the "priv->registers[reg]" access is really an out-of-bounds access. To fix that, I made jit_frame_prev_register use gdbarch_pseudo_register_read_value for reading the pseudo-registers. However, that works with a regcache and we don't have one. To fix that, I made the JIT unwinder store a regcache in its cache instead of an array of gdb_reg_value pointers. gdb/ChangeLog: 2016-07-01 Pedro Alves <palves@redhat.com> Tom Tromey <tom@tromey.com> * jit.c (jit_reader_load_command): Call reinit_frame_cache and jit_inferior_created_hook. (jit_reader_unload_command): Call reinit_frame_cache and jit_inferior_exit_hook. * jit.c (struct jit_unwind_private) <registers>: Delete field. <regcache>: New field. (jit_unwind_reg_set_impl): Set the register's value in the regcache. Free the passed-in gdb_reg_value. (jit_dealloc_cache): Adjust to free the regcache. (jit_frame_sniffer): Allocate a regcache instead of an array of gdb_reg_value pointers. (jit_frame_this_id): Adjust. (jit_frame_prev_register): Read raw registers off of the regcache instead of from the gdb_reg_value pointer array. Use gdbarch_pseudo_register_read_value to read pseudo registers. * regcache.c (regcache_raw_set_cached_value): New function, factored out from ... (regcache_raw_write): ... here. * regcache.h (regcache_raw_set_cached_value): Declare. gdb/testsuite/ChangeLog: 2016-07-01 Pedro Alves <palves@redhat.com> * gdb.base/jit-reader.exp (info_registers_current_frame): New procedure. (jit_reader_test): Test the jit reader's unwinder. * gdb.base/jithost.c (jit_function_00_code): New global. (main): Use memcpy to fill in the mmapped code, instead of poking bytes manually here. * gdb.base/jitreader.c (enum register_mapping) <AMD64_RBP>: New value. (read_debug_info): Save the function's range. (read_sp): New function. (unwind_frame): Use it. Also unwind RBP. (get_frame_id): Use read_sp. (gdb_init_reader): Use calloc instead of malloc. * lib/gdb.exp (get_hexadecimal_valueof): Add optional 'test' parameter. Use gdb_test_multiple.
Diffstat (limited to 'gdb/regcache.c')
-rw-r--r--gdb/regcache.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/gdb/regcache.c b/gdb/regcache.c
index f0ba0cf..a5c90a6 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -890,6 +890,17 @@ regcache_cooked_write_unsigned (struct regcache *regcache, int regnum,
regcache_cooked_write (regcache, regnum, buf);
}
+/* See regcache.h. */
+
+void
+regcache_raw_set_cached_value (struct regcache *regcache, int regnum,
+ const gdb_byte *buf)
+{
+ memcpy (register_buffer (regcache, regnum), buf,
+ regcache->descr->sizeof_register[regnum]);
+ regcache->register_status[regnum] = REG_VALID;
+}
+
void
regcache_raw_write (struct regcache *regcache, int regnum,
const gdb_byte *buf)
@@ -917,9 +928,7 @@ regcache_raw_write (struct regcache *regcache, int regnum,
inferior_ptid = regcache->ptid;
target_prepare_to_store (regcache);
- memcpy (register_buffer (regcache, regnum), buf,
- regcache->descr->sizeof_register[regnum]);
- regcache->register_status[regnum] = REG_VALID;
+ regcache_raw_set_cached_value (regcache, regnum, buf);
/* Register a cleanup function for invalidating the register after it is
written, in case of a failure. */