diff options
-rw-r--r-- | gdb/ChangeLog | 12 | ||||
-rw-r--r-- | gdb/gdbarch.c | 32 | ||||
-rw-r--r-- | gdb/gdbarch.h | 30 | ||||
-rwxr-xr-x | gdb/gdbarch.sh | 25 | ||||
-rw-r--r-- | gdb/i386-tdep.c | 29 | ||||
-rw-r--r-- | gdb/stap-probe.c | 31 |
6 files changed, 156 insertions, 3 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a55c12a..d28471e 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,17 @@ 2019-06-28 Sergio Durigan Junior <sergiodj@redhat.com> + PR breakpoints/24541 + * gdbarch.c: Regenerate. + * gdbarch.h: Regenerate. + * gdbarch.sh: Add 'stap_adjust_register'. + * i386-tdep.c: Include '<unordered_set>'. + (i386_stap_adjust_register): New function. + (i386_elf_init_abi): Register 'i386_stap_adjust_register'. + * stap-probe.c (stap_parse_register_operand): Call + 'gdbarch_stap_adjust_register'. + +2019-06-28 Sergio Durigan Junior <sergiodj@redhat.com> + PR python/24742 https://bugzilla.redhat.com/show_bug.cgi?id=1723564 * python/python.c (do_start_initialization): Use 'xmalloc' diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index a0c169d..cc7d0ac 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -324,6 +324,7 @@ struct gdbarch const char * stap_gdb_register_suffix; gdbarch_stap_is_single_operand_ftype *stap_is_single_operand; gdbarch_stap_parse_special_token_ftype *stap_parse_special_token; + gdbarch_stap_adjust_register_ftype *stap_adjust_register; gdbarch_dtrace_parse_probe_argument_ftype *dtrace_parse_probe_argument; gdbarch_dtrace_probe_is_enabled_ftype *dtrace_probe_is_enabled; gdbarch_dtrace_enable_probe_ftype *dtrace_enable_probe; @@ -687,6 +688,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of stap_gdb_register_suffix, invalid_p == 0 */ /* Skip verify of stap_is_single_operand, has predicate. */ /* Skip verify of stap_parse_special_token, has predicate. */ + /* Skip verify of stap_adjust_register, has predicate. */ /* Skip verify of dtrace_parse_probe_argument, has predicate. */ /* Skip verify of dtrace_probe_is_enabled, has predicate. */ /* Skip verify of dtrace_enable_probe, has predicate. */ @@ -1397,6 +1399,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "gdbarch_dump: stack_frame_destroyed_p = <%s>\n", host_address_to_string (gdbarch->stack_frame_destroyed_p)); fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_stap_adjust_register_p() = %d\n", + gdbarch_stap_adjust_register_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: stap_adjust_register = <%s>\n", + host_address_to_string (gdbarch->stap_adjust_register)); + fprintf_unfiltered (file, "gdbarch_dump: stap_gdb_register_prefix = %s\n", pstring (gdbarch->stap_gdb_register_prefix)); fprintf_unfiltered (file, @@ -4516,6 +4524,30 @@ set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, } int +gdbarch_stap_adjust_register_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->stap_adjust_register != NULL; +} + +void +gdbarch_stap_adjust_register (struct gdbarch *gdbarch, struct stap_parse_info *p, std::string ®name, int regnum) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->stap_adjust_register != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_adjust_register called\n"); + gdbarch->stap_adjust_register (gdbarch, p, regname, regnum); +} + +void +set_gdbarch_stap_adjust_register (struct gdbarch *gdbarch, + gdbarch_stap_adjust_register_ftype stap_adjust_register) +{ + gdbarch->stap_adjust_register = stap_adjust_register; +} + +int gdbarch_dtrace_parse_probe_argument_p (struct gdbarch *gdbarch) { gdb_assert (gdbarch != NULL); diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 7ebd365a..0857d2f 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -1350,6 +1350,36 @@ typedef int (gdbarch_stap_parse_special_token_ftype) (struct gdbarch *gdbarch, s extern int gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, struct stap_parse_info *p); extern void set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, gdbarch_stap_parse_special_token_ftype *stap_parse_special_token); +/* Perform arch-dependent adjustments to a register name. + + In very specific situations, it may be necessary for the register + name present in a SystemTap probe's argument to be handled in a + special way. For example, on i386, GCC may over-optimize the + register allocation and use smaller registers than necessary. In + such cases, the client that is reading and evaluating the SystemTap + probe (ourselves) will need to actually fetch values from the wider + version of the register in question. + + To illustrate the example, consider the following probe argument + (i386): + + 4@%ax + + This argument says that its value can be found at the %ax register, + which is a 16-bit register. However, the argument's prefix says + that its type is "uint32_t", which is 32-bit in size. Therefore, in + this case, GDB should actually fetch the probe's value from register + %eax, not %ax. In this scenario, this function would actually + replace the register name from %ax to %eax. + + The rationale for this can be found at PR breakpoints/24541. */ + +extern int gdbarch_stap_adjust_register_p (struct gdbarch *gdbarch); + +typedef void (gdbarch_stap_adjust_register_ftype) (struct gdbarch *gdbarch, struct stap_parse_info *p, std::string ®name, int regnum); +extern void gdbarch_stap_adjust_register (struct gdbarch *gdbarch, struct stap_parse_info *p, std::string ®name, int regnum); +extern void set_gdbarch_stap_adjust_register (struct gdbarch *gdbarch, gdbarch_stap_adjust_register_ftype *stap_adjust_register); + /* DTrace related functions. The expression to compute the NARTGth+1 argument to a DTrace USDT probe. NARG must be >= 0. */ diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 59493d8..f3d1bf4 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -1030,6 +1030,31 @@ M;int;stap_is_single_operand;const char *s;s # parser), and should advance the buffer pointer (p->arg). M;int;stap_parse_special_token;struct stap_parse_info *p;p +# Perform arch-dependent adjustments to a register name. +# +# In very specific situations, it may be necessary for the register +# name present in a SystemTap probe's argument to be handled in a +# special way. For example, on i386, GCC may over-optimize the +# register allocation and use smaller registers than necessary. In +# such cases, the client that is reading and evaluating the SystemTap +# probe (ourselves) will need to actually fetch values from the wider +# version of the register in question. +# +# To illustrate the example, consider the following probe argument +# (i386): +# +# 4@%ax +# +# This argument says that its value can be found at the %ax register, +# which is a 16-bit register. However, the argument's prefix says +# that its type is "uint32_t", which is 32-bit in size. Therefore, in +# this case, GDB should actually fetch the probe's value from register +# %eax, not %ax. In this scenario, this function would actually +# replace the register name from %ax to %eax. +# +# The rationale for this can be found at PR breakpoints/24541. +M;void;stap_adjust_register;struct stap_parse_info *p, std::string \®name, int regnum;p, regname, regnum + # DTrace related functions. # The expression to compute the NARTGth+1 argument to a DTrace USDT probe. diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index c542edf..00c1f8d 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -64,6 +64,7 @@ #include "parser-defs.h" #include <ctype.h> #include <algorithm> +#include <unordered_set> /* Register names. */ @@ -4385,6 +4386,32 @@ i386_stap_parse_special_token (struct gdbarch *gdbarch, return 0; } +/* Implementation of 'gdbarch_stap_adjust_register', as defined in + gdbarch.h. */ + +static void +i386_stap_adjust_register (struct gdbarch *gdbarch, struct stap_parse_info *p, + std::string ®name, int regnum) +{ + static const std::unordered_set<std::string> reg_assoc + = { "ax", "bx", "cx", "dx", + "si", "di", "bp", "sp" }; + + if (register_size (gdbarch, regnum) >= TYPE_LENGTH (p->arg_type)) + { + /* If we're dealing with a register whose size is greater or + equal than the size specified by the "[-]N@" prefix, then we + don't need to do anything. */ + return; + } + + if (reg_assoc.find (regname) != reg_assoc.end ()) + { + /* Use the extended version of the register. */ + regname = "e" + regname; + } +} + /* gdbarch gnu_triplet_regexp method. Both arches are acceptable as GDB always @@ -4433,6 +4460,8 @@ i386_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) i386_stap_is_single_operand); set_gdbarch_stap_parse_special_token (gdbarch, i386_stap_parse_special_token); + set_gdbarch_stap_adjust_register (gdbarch, + i386_stap_adjust_register); set_gdbarch_in_indirect_branch_thunk (gdbarch, i386_in_indirect_branch_thunk); diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c index e5a901b..aa1c814 100644 --- a/gdb/stap-probe.c +++ b/gdb/stap-probe.c @@ -762,13 +762,38 @@ stap_parse_register_operand (struct stap_parse_info *p) regname += gdb_reg_suffix; } + int regnum = user_reg_map_name_to_regnum (gdbarch, regname.c_str (), + regname.size ()); + /* Is this a valid register name? */ - if (user_reg_map_name_to_regnum (gdbarch, - regname.c_str (), - regname.size ()) == -1) + if (regnum == -1) error (_("Invalid register name `%s' on expression `%s'."), regname.c_str (), p->saved_arg); + /* Check if there's any special treatment that the arch-specific + code would like to perform on the register name. */ + if (gdbarch_stap_adjust_register_p (gdbarch)) + { + std::string oldregname = regname; + + gdbarch_stap_adjust_register (gdbarch, p, regname, regnum); + + if (regname != oldregname) + { + /* This is just a check we perform to make sure that the + arch-dependent code has provided us with a valid + register name. */ + regnum = user_reg_map_name_to_regnum (gdbarch, regname.c_str (), + regname.size ()); + + if (regnum == -1) + internal_error (__FILE__, __LINE__, + _("Invalid register name '%s' after replacing it" + " (previous name was '%s')"), + regname.c_str (), oldregname.c_str ()); + } + } + write_exp_elt_opcode (&p->pstate, OP_REGISTER); str.ptr = regname.c_str (); str.length = regname.size (); |