diff options
-rw-r--r-- | gdb/ChangeLog | 9 | ||||
-rw-r--r-- | gdb/arch-utils.c | 23 | ||||
-rw-r--r-- | gdb/arch-utils.h | 4 | ||||
-rw-r--r-- | gdb/gdbarch.c | 23 | ||||
-rw-r--r-- | gdb/gdbarch.h | 9 | ||||
-rwxr-xr-x | gdb/gdbarch.sh | 6 | ||||
-rw-r--r-- | gdb/tracefile.c | 60 |
7 files changed, 95 insertions, 39 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index e507dd1..c8832c9 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,12 @@ +2016-02-18 Marcin KoĆcielnicki <koriakin@0x04.net> + + * arch-utils.c (default_guess_tracepoint_registers): New function. + * arch-utils.h (default_guess_tracepoint_registers): New prototype. + * gdbarch.c: Regenerate. + * gdbarch.h: Regenerate. + * gdbarch.sh: Add guess_tracepoint_registers hook. + * tracefile.c (tracefile_fetch_registers): Use the new gdbarch hook. + 2016-02-17 Gary Benson <gbenson@redhat.com> * exec.c (exec_file_locate_attach): Add missing cleanup. diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index fe64627..c3d7802 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -897,6 +897,29 @@ default_addressable_memory_unit_size (struct gdbarch *gdbarch) return 1; } +void +default_guess_tracepoint_registers (struct gdbarch *gdbarch, + struct regcache *regcache, + CORE_ADDR addr) +{ + int pc_regno = gdbarch_pc_regnum (gdbarch); + gdb_byte *regs; + + /* This guessing code below only works if the PC register isn't + a pseudo-register. The value of a pseudo-register isn't stored + in the (non-readonly) regcache -- instead it's recomputed + (probably from some other cached raw register) whenever the + register is read. In this case, a custom method implementation + should be used by the architecture. */ + if (pc_regno < 0 || pc_regno >= gdbarch_num_regs (gdbarch)) + return; + + regs = (gdb_byte *) alloca (register_size (gdbarch, pc_regno)); + store_unsigned_integer (regs, register_size (gdbarch, pc_regno), + gdbarch_byte_order (gdbarch), addr); + regcache_raw_supply (regcache, pc_regno, regs); +} + /* -Wmissing-prototypes */ extern initialize_file_ftype _initialize_gdbarch_utils; diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index 3fad2c3..9e1e70e 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -204,4 +204,8 @@ extern char *default_gcc_target_options (struct gdbarch *gdbarch); extern const char *default_gnu_triplet_regexp (struct gdbarch *gdbarch); extern int default_addressable_memory_unit_size (struct gdbarch *gdbarch); +extern void default_guess_tracepoint_registers (struct gdbarch *gdbarch, + struct regcache *regcache, + CORE_ADDR addr); + #endif diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 4143744..0136c75 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -312,6 +312,7 @@ struct gdbarch int has_global_breakpoints; gdbarch_has_shared_address_space_ftype *has_shared_address_space; gdbarch_fast_tracepoint_valid_at_ftype *fast_tracepoint_valid_at; + gdbarch_guess_tracepoint_registers_ftype *guess_tracepoint_registers; gdbarch_auto_charset_ftype *auto_charset; gdbarch_auto_wide_charset_ftype *auto_wide_charset; const char * solib_symbols_extension; @@ -419,6 +420,7 @@ gdbarch_alloc (const struct gdbarch_info *info, gdbarch->relocate_instruction = NULL; gdbarch->has_shared_address_space = default_has_shared_address_space; gdbarch->fast_tracepoint_valid_at = default_fast_tracepoint_valid_at; + gdbarch->guess_tracepoint_registers = default_guess_tracepoint_registers; gdbarch->auto_charset = default_auto_charset; gdbarch->auto_wide_charset = default_auto_wide_charset; gdbarch->gen_return_address = default_gen_return_address; @@ -658,6 +660,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of has_global_breakpoints, invalid_p == 0 */ /* Skip verify of has_shared_address_space, invalid_p == 0 */ /* Skip verify of fast_tracepoint_valid_at, invalid_p == 0 */ + /* Skip verify of guess_tracepoint_registers, invalid_p == 0 */ /* Skip verify of auto_charset, invalid_p == 0 */ /* Skip verify of auto_wide_charset, invalid_p == 0 */ /* Skip verify of has_dos_based_file_system, invalid_p == 0 */ @@ -1024,6 +1027,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "gdbarch_dump: gnu_triplet_regexp = <%s>\n", host_address_to_string (gdbarch->gnu_triplet_regexp)); fprintf_unfiltered (file, + "gdbarch_dump: guess_tracepoint_registers = <%s>\n", + host_address_to_string (gdbarch->guess_tracepoint_registers)); + fprintf_unfiltered (file, "gdbarch_dump: half_bit = %s\n", plongest (gdbarch->half_bit)); fprintf_unfiltered (file, @@ -4450,6 +4456,23 @@ set_gdbarch_fast_tracepoint_valid_at (struct gdbarch *gdbarch, gdbarch->fast_tracepoint_valid_at = fast_tracepoint_valid_at; } +void +gdbarch_guess_tracepoint_registers (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR addr) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->guess_tracepoint_registers != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_guess_tracepoint_registers called\n"); + gdbarch->guess_tracepoint_registers (gdbarch, regcache, addr); +} + +void +set_gdbarch_guess_tracepoint_registers (struct gdbarch *gdbarch, + gdbarch_guess_tracepoint_registers_ftype guess_tracepoint_registers) +{ + gdbarch->guess_tracepoint_registers = guess_tracepoint_registers; +} + const char * gdbarch_auto_charset (struct gdbarch *gdbarch) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 3fadcd1..7ffbf1f 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -1327,6 +1327,15 @@ typedef int (gdbarch_fast_tracepoint_valid_at_ftype) (struct gdbarch *gdbarch, C extern int gdbarch_fast_tracepoint_valid_at (struct gdbarch *gdbarch, CORE_ADDR addr, char **msg); extern void set_gdbarch_fast_tracepoint_valid_at (struct gdbarch *gdbarch, gdbarch_fast_tracepoint_valid_at_ftype *fast_tracepoint_valid_at); +/* Guess register state based on tracepoint location. Used for tracepoints + where no registers have been collected, but there's only one location, + allowing us to guess the PC value, and perhaps some other registers. + On entry, regcache has all registers marked as unavailable. */ + +typedef void (gdbarch_guess_tracepoint_registers_ftype) (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR addr); +extern void gdbarch_guess_tracepoint_registers (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR addr); +extern void set_gdbarch_guess_tracepoint_registers (struct gdbarch *gdbarch, gdbarch_guess_tracepoint_registers_ftype *guess_tracepoint_registers); + /* Return the "auto" target charset. */ typedef const char * (gdbarch_auto_charset_ftype) (void); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 4ac6b90..61cb04a 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -1028,6 +1028,12 @@ m:int:has_shared_address_space:void:::default_has_shared_address_space::0 # True if a fast tracepoint can be set at an address. m:int:fast_tracepoint_valid_at:CORE_ADDR addr, char **msg:addr, msg::default_fast_tracepoint_valid_at::0 +# Guess register state based on tracepoint location. Used for tracepoints +# where no registers have been collected, but there's only one location, +# allowing us to guess the PC value, and perhaps some other registers. +# On entry, regcache has all registers marked as unavailable. +m:void:guess_tracepoint_registers:struct regcache *regcache, CORE_ADDR addr:regcache, addr::default_guess_tracepoint_registers::0 + # Return the "auto" target charset. f:const char *:auto_charset:void::default_auto_charset:default_auto_charset::0 # Return the "auto" target wide charset. diff --git a/gdb/tracefile.c b/gdb/tracefile.c index de42165..609b7e5 100644 --- a/gdb/tracefile.c +++ b/gdb/tracefile.c @@ -388,7 +388,8 @@ void tracefile_fetch_registers (struct regcache *regcache, int regno) { struct gdbarch *gdbarch = get_regcache_arch (regcache); - int regn, pc_regno; + struct tracepoint *tp = get_tracepoint (get_tracepoint_number ()); + int regn; /* We get here if no register data has been found. Mark registers as unavailable. */ @@ -397,48 +398,29 @@ tracefile_fetch_registers (struct regcache *regcache, int regno) /* We can often usefully guess that the PC is going to be the same as the address of the tracepoint. */ - pc_regno = gdbarch_pc_regnum (gdbarch); - - /* XXX This guessing code below only works if the PC register isn't - a pseudo-register. The value of a pseudo-register isn't stored - in the (non-readonly) regcache -- instead it's recomputed - (probably from some other cached raw register) whenever the - register is read. This guesswork should probably move to some - higher layer. */ - if (pc_regno < 0 || pc_regno >= gdbarch_num_regs (gdbarch)) + if (tp == NULL || tp->base.loc == NULL) return; - if (regno == -1 || regno == pc_regno) + /* But don't try to guess if tracepoint is multi-location... */ + if (tp->base.loc->next) { - struct tracepoint *tp = get_tracepoint (get_tracepoint_number ()); - gdb_byte *regs; - - if (tp && tp->base.loc) - { - /* But don't try to guess if tracepoint is multi-location... */ - if (tp->base.loc->next) - { - warning (_("Tracepoint %d has multiple " - "locations, cannot infer $pc"), - tp->base.number); - return; - } - /* ... or does while-stepping. */ - if (tp->step_count > 0) - { - warning (_("Tracepoint %d does while-stepping, " - "cannot infer $pc"), - tp->base.number); - return; - } - - regs = (gdb_byte *) alloca (register_size (gdbarch, pc_regno)); - store_unsigned_integer (regs, register_size (gdbarch, pc_regno), - gdbarch_byte_order (gdbarch), - tp->base.loc->address); - regcache_raw_supply (regcache, pc_regno, regs); - } + warning (_("Tracepoint %d has multiple " + "locations, cannot infer $pc"), + tp->base.number); + return; + } + /* ... or does while-stepping. */ + else if (tp->step_count > 0) + { + warning (_("Tracepoint %d does while-stepping, " + "cannot infer $pc"), + tp->base.number); + return; } + + /* Guess what we can from the tracepoint location. */ + gdbarch_guess_tracepoint_registers (gdbarch, regcache, + tp->base.loc->address); } /* This is the implementation of target_ops method to_has_all_memory. */ |