Re: [RFA/RFC] mips tracepoint: fix Bug 12013

Hui Zhu
2010-12-28T08:02:24Z

[-- Attachment #1: Type: text/plain, Size: 7399 bytes --]

Thanks for your help Pedro.

On Mon, Dec 27, 2010 at 21:09, Pedro Alves <pedro@codesourcery.com> wrote:
> On Saturday 25 December 2010 17:09:21, Hui Zhu wrote:
>> On Wed, Dec 22, 2010 at 19:26, Pedro Alves <pedro@codesourcery.com> wrote:
> ...
>> I make a patch according to your comments.
>
> Thanks!  I'm liking this.  Would be super cool to have these
> implemented on x86/x86_64 as well.

When this patch ok, I will post a separate patch for it.

>
>> It add to callback in gdbarch.  They are gdbarch_ax_pseudo_reg and
>> gdbarch_ax_pseudo_reg_mask.
>>
>> gdbarch_ax_pseudo_reg will be called by ax_reg.  It assemble code to
>> push the value of pseudo register number REG on the stack.
>> gdbarch_ax_pseudo_reg_mask will be called by ax_reg_mask. It add
>> pseudo register REG to the register mask for expression AX.
>
> Well, not to the register mask.  It really isn't garanteed
> that a pseudo register maps to a raw register.  It could
> map to some value stored at some memory address, so the new
> callback may do other things than flipping a bit
> in the raw registers to collect mask (hence the ax_reg_mask function
> name).  I can see why you named the callbacks like that, and I'll approve
> the patch with such names anyway, though I'd prefer naming them
> something more descriptive like gdbarch_ax_pseudo_register_collect /
> gdbarch_ax_pseudo_register_push_stack.  E.g.,
>
>  # Assemble agent expression bytecode to collect pseudo-register REG.
>  # Return -1 if something goes wrong, 0 otherwise.
>  M:int:ax_pseudo_register_collect:struct agent_expr *ax, int reg:ax, reg
>
>  # Assemble agent expression bytecode to push the value of pseudo-register
>  # REG on the interpreter stack.
>  # Return -1 if something goes wrong, 0 otherwise.
>  M:int:ax_pseudo_register_push_stack:struct agent_expr *ax, int reg:ax, reg

Agree with you. These names are more better than what I use. I will use them.

>
>> 2010-12-26  Hui Zhu  <teawater@gmail.com>
>>
>>       * ax-gdb.c (gen_expr): Remove pseudo-register check code.
>>       * ax-general.c (user-regs.h): New include.
>>       (ax_reg): Call gdbarch_ax_pseudo_reg.
>>       (ax_reg_mask): Call gdbarch_ax_pseudo_reg_mask.
>>       * gdbarch.sh (ax_pseudo_reg, ax_pseudo_reg_mask): new callback.
>
> Capitalize, plural: "New callbacks."
>
>>       * mips-tdep.c (ax.h): New include.
>>       (mips_ax_pseudo_reg, mips_ax_pseudo_reg_mask): New function.
>
> functions.
>
>>       (mips_gdbarch_init): Set mips_ax_pseudo_reg and
>>       mips_ax_pseudo_reg_mask.
>
> You need to mention that gdbarch.c and gdbarch.h were regenerated.
>
>>  /* Given an agent expression AX, fill in requirements and other descriptive
>> --- a/gdbarch.sh
>> +++ b/gdbarch.sh
> ...
>> @@ -919,6 +928,7 @@ struct target_desc;
>>  struct displaced_step_closure;
>>  struct core_regset_section;
>>  struct syscall;
>> +struct agent_expr;
>
> You forgot to mention this in the changelog.
>
>> +static int
>> +mips_ax_pseudo_reg (struct gdbarch *gdbarch, struct agent_expr *ax, int reg)
>> +{
>> +  int rawnum = reg % gdbarch_num_regs (gdbarch);
>> +  gdb_assert (reg >= gdbarch_num_regs (gdbarch)
>> +           && reg < 2 * gdbarch_num_regs (gdbarch));
>> +  if (register_size (gdbarch, rawnum) >= register_size (gdbarch, reg))
>> +    {
>> +      ax_reg (ax, rawnum);
>> +
>> +      if (register_size (gdbarch, rawnum) > register_size (gdbarch, reg))
>> +        {
>> +       if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
>> +           && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
>> +         {
>> +           ax->buf[ax->len] = aop_const8;
>> +           ax->buf[ax->len + 1] = 32;
>> +           ax->buf[ax->len + 2] = aop_rsh_unsigned;
>> +           ax->len += 3;
>> +         }
>> +       else
>> +         {
>> +           ax->buf[ax->len] = aop_const32;
>> +           ax->buf[ax->len + 1] = 0xff;
>> +           ax->buf[ax->len + 2] = 0xff;
>> +           ax->buf[ax->len + 3] = 0xff;
>> +           ax->buf[ax->len + 4] = 0xff;
>> +           ax->buf[ax->len + 5] = aop_bit_and;
>> +           ax->len += 6;
>
> Hmm, I'm not sure, but don't you need to sign extend?
> mips-tdep.c:mips_pseudo_register_read treats this as signed.
>
> Why do you apply the "and 0xffffffff" logic when
> mips64_transfers_32bit_regs_p is false?

I change this part to:
if (register_size (gdbarch, rawnum) > register_size (gdbarch, reg))
{
if (!gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
|| gdbarch_byte_order (gdbarch) != BFD_ENDIAN_BIG)
{
ax_const_l (ax, 32);
ax_simple (ax, aop_lsh);
}
ax_const_l (ax, 32);
ax_simple (ax, aop_rsh_signed);
}

If mips64_transfers_32bit_regs_p is false or arch is little endian,
use the low 32bit.
If not, use the the high 32bit.

Do you think it is OK?

>
>> +         }
>
> Please use the functions in ax-general.c that generate
> the bytecode instead of writing to the bytecode buffer
> directly (and forgetting to ensure there's enough room in
> the buffer): ax_const_l/ax_simple, etc.
>
>
> The patch you posted got line-wrapped/mangled, and I couldn't
> apply it even after trying to manually fix it.  Can you please
> make the necessary tweaks to your email client to make that
> not happen?  (Me, to send patches with gmail, I find it simpler
> to use an email client / SMTP than using gmail's web interface)
>

So sorry about that.
I have some net issue so I cannot use gmail with SMTP sometimes. So I
use the attachment to send the patch.

Please help me review the new patch.

Thanks,
Hui

2010-12-28 Hui Zhu <teawater@gmail.com>

* gdbarch.sh (ax_pseudo_register_collect,
ax_pseudo_register_push_stack): new callbacks.
(agent_expr): New struct.
* gdbarch.c (gdbarch): Add ax_pseudo_register_collect and
ax_pseudo_register_push_stack.
(startup_gdbarch): Add 0 for ax_pseudo_register_collect and
ax_pseudo_register_push_stack.
(verify_gdbarch): Add comments for ax_pseudo_register_collect and
ax_pseudo_register_push_stack.
(gdbarch_dump): Add fprintf_unfiltered for ax_pseudo_register_collect
and ax_pseudo_register_push_stack.
(gdbarch_ax_pseudo_register_collect_p,
gdbarch_ax_pseudo_register_collect,
set_gdbarch_ax_pseudo_register_collect,
gdbarch_ax_pseudo_register_push_stack_p,
gdbarch_ax_pseudo_register_push_stack,
set_gdbarch_ax_pseudo_register_push_stack): New functions.
* gdbarch.h (agent_expr): New struct.
(gdbarch_ax_pseudo_register_collect_p,
gdbarch_ax_pseudo_register_collect,
set_gdbarch_ax_pseudo_register_collect,
gdbarch_ax_pseudo_register_push_stack_p,
gdbarch_ax_pseudo_register_push_stack,
set_gdbarch_ax_pseudo_register_push_stack): New externs.
(gdbarch_ax_pseudo_register_collect_ftype,
gdbarch_ax_pseudo_register_push_stack_ftype): New typedeies.
* ax-gdb.c (gen_expr): Remove pseudo-register check code.
* ax-general.c (user-regs.h): New include.
(ax_reg): Call gdbarch_ax_pseudo_register_push_stack.
(ax_reg_mask): Call gdbarch_ax_pseudo_register_collect.
* mips-tdep.c (ax.h): New include.
(mips_ax_pseudo_register_collect,
mips_ax_pseudo_register_push_stack): New functions.
(mips_gdbarch_init): Set mips_ax_pseudo_register_collect and
mips_ax_pseudo_register_push_stack.

[-- Attachment #2: trace-pseudo.txt --]
[-- Type: text/plain, Size: 13332 bytes --]

---
ax-gdb.c | 4 ---
ax-general.c | 75 +++++++++++++++++++++++++++++++++++++++++------------------
gdbarch.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdbarch.h | 20 +++++++++++++++
gdbarch.sh | 10 +++++++
mips-tdep.c | 48 +++++++++++++++++++++++++++++++++++++
6 files changed, 197 insertions(+), 26 deletions(-)

--- a/ax-gdb.c
+++ b/ax-gdb.c
@@ -1978,10 +1978,6 @@ gen_expr (struct expression *exp, union
if (reg == -1)
internal_error (__FILE__, __LINE__,
_("Register $%s not available"), name);
- if (reg >= gdbarch_num_regs (exp->gdbarch))
- error (_("'%s' is a pseudo-register; "
- "GDB cannot yet trace pseudoregister contents."),
- name);
value->kind = axs_lvalue_register;
value->u.reg = reg;
value->type = register_type (exp->gdbarch, reg);
--- a/ax-general.c
+++ b/ax-general.c
@@ -28,6 +28,8 @@
#include "value.h"
#include "gdb_string.h"

+#include "user-regs.h"
+
static void grow_expr (struct agent_expr *x, int n);

static void append_const (struct agent_expr *x, LONGEST val, int n);
@@ -272,14 +274,28 @@ ax_const_d (struct agent_expr *x, LONGES
void
ax_reg (struct agent_expr *x, int reg)
{
- /* Make sure the register number is in range. */
- if (reg < 0 || reg > 0xffff)
- error (_("GDB bug: ax-general.c (ax_reg): register number out of range"));
- grow_expr (x, 3);
- x->buf[x->len] = aop_reg;
- x->buf[x->len + 1] = (reg >> 8) & 0xff;
- x->buf[x->len + 2] = (reg) & 0xff;
- x->len += 3;
+ if (reg >= gdbarch_num_regs (x->gdbarch))
+ {
+ /* This is a pseudo-register. */
+ if (!gdbarch_ax_pseudo_register_push_stack_p (x->gdbarch))
+ error (_("'%s' is a pseudo-register; "
+ "GDB cannot yet trace its contents."),
+ user_reg_map_regnum_to_name (x->gdbarch, reg));
+ if (gdbarch_ax_pseudo_register_push_stack (x->gdbarch, x, reg))
+ error (_("Trace '%s' failed."),
+ user_reg_map_regnum_to_name (x->gdbarch, reg));
+ }
+ else
+ {
+ /* Make sure the register number is in range. */
+ if (reg < 0 || reg > 0xffff)
+ error (_("GDB bug: ax-general.c (ax_reg): register number out of range"));
+ grow_expr (x, 3);
+ x->buf[x->len] = aop_reg;
+ x->buf[x->len + 1] = (reg >> 8) & 0xff;
+ x->buf[x->len + 2] = (reg) & 0xff;
+ x->len += 3;
+ }
}

/* Assemble code to operate on a trace state variable. */
@@ -413,23 +429,38 @@ ax_print (struct ui_file *f, struct agen
void
ax_reg_mask (struct agent_expr *ax, int reg)
{
- int byte = reg / 8;
-
- /* Grow the bit mask if necessary. */
- if (byte >= ax->reg_mask_len)
+ if (reg >= gdbarch_num_regs (ax->gdbarch))
{
- /* It's not appropriate to double here. This isn't a
- string buffer. */
- int new_len = byte + 1;
- unsigned char *new_reg_mask = xrealloc (ax->reg_mask,
- new_len * sizeof (ax->reg_mask[0]));
- memset (new_reg_mask + ax->reg_mask_len, 0,
- (new_len - ax->reg_mask_len) * sizeof (ax->reg_mask[0]));
- ax->reg_mask_len = new_len;
- ax->reg_mask = new_reg_mask;
+ /* This is a pseudo-register. */
+ if (!gdbarch_ax_pseudo_register_collect_p (ax->gdbarch))
+ error (_("'%s' is a pseudo-register; "
+ "GDB cannot yet trace its contents."),
+ user_reg_map_regnum_to_name (ax->gdbarch, reg));
+ if (gdbarch_ax_pseudo_register_collect (ax->gdbarch, ax, reg))
+ error (_("Trace '%s' failed."),
+ user_reg_map_regnum_to_name (ax->gdbarch, reg));
}
+ else
+ {
+ int byte = reg / 8;

- ax->reg_mask[byte] |= 1 << (reg % 8);
+ /* Grow the bit mask if necessary. */
+ if (byte >= ax->reg_mask_len)
+ {
+ /* It's not appropriate to double here. This isn't a
+ string buffer. */
+ int new_len = byte + 1;
+ unsigned char *new_reg_mask = xrealloc (ax->reg_mask,
+ new_len
+ * sizeof (ax->reg_mask[0]));
+ memset (new_reg_mask + ax->reg_mask_len, 0,
+ (new_len - ax->reg_mask_len) * sizeof (ax->reg_mask[0]));
+ ax->reg_mask_len = new_len;
+ ax->reg_mask = new_reg_mask;
+ }
+
+ ax->reg_mask[byte] |= 1 << (reg % 8);
+ }
}

/* Given an agent expression AX, fill in requirements and other descriptive
--- a/gdbarch.c
+++ b/gdbarch.c
@@ -164,6 +164,8 @@ struct gdbarch
gdbarch_pseudo_register_write_ftype *pseudo_register_write;
int num_regs;
int num_pseudo_regs;
+ gdbarch_ax_pseudo_register_collect_ftype *ax_pseudo_register_collect;
+ gdbarch_ax_pseudo_register_push_stack_ftype *ax_pseudo_register_push_stack;
int sp_regnum;
int pc_regnum;
int ps_regnum;
@@ -314,6 +316,8 @@ struct gdbarch startup_gdbarch =
0, /* pseudo_register_write */
0, /* num_regs */
0, /* num_pseudo_regs */
+ 0, /* ax_pseudo_register_collect */
+ 0, /* ax_pseudo_register_push_stack */
-1, /* sp_regnum */
-1, /* pc_regnum */
-1, /* ps_regnum */
@@ -594,6 +598,8 @@ verify_gdbarch (struct gdbarch *gdbarch)
if (gdbarch->num_regs == -1)
fprintf_unfiltered (log, "\n\tnum_regs");
/* Skip verify of num_pseudo_regs, invalid_p == 0 */
+ /* Skip verify of ax_pseudo_register_collect, has predicate */
+ /* Skip verify of ax_pseudo_register_push_stack, has predicate */
/* Skip verify of sp_regnum, invalid_p == 0 */
/* Skip verify of pc_regnum, invalid_p == 0 */
/* Skip verify of ps_regnum, invalid_p == 0 */
@@ -761,6 +767,18 @@ gdbarch_dump (struct gdbarch *gdbarch, s
"gdbarch_dump: auto_wide_charset = <%s>\n",
host_address_to_string (gdbarch->auto_wide_charset));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_ax_pseudo_register_collect_p() = %d\n",
+ gdbarch_ax_pseudo_register_collect_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: ax_pseudo_register_collect = <%s>\n",
+ host_address_to_string (gdbarch->ax_pseudo_register_collect));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_ax_pseudo_register_push_stack_p() = %d\n",
+ gdbarch_ax_pseudo_register_push_stack_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: ax_pseudo_register_push_stack = <%s>\n",
+ host_address_to_string (gdbarch->ax_pseudo_register_push_stack));
+ fprintf_unfiltered (file,
"gdbarch_dump: believe_pcc_promotion = %s\n",
plongest (gdbarch->believe_pcc_promotion));
fprintf_unfiltered (file,
@@ -1741,6 +1759,54 @@ set_gdbarch_num_pseudo_regs (struct gdba
}

int
+gdbarch_ax_pseudo_register_collect_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->ax_pseudo_register_collect != NULL;
+}
+
+int
+gdbarch_ax_pseudo_register_collect (struct gdbarch *gdbarch, struct agent_expr *ax, int reg)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->ax_pseudo_register_collect != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_ax_pseudo_register_collect called\n");
+ return gdbarch->ax_pseudo_register_collect (gdbarch, ax, reg);
+}
+
+void
+set_gdbarch_ax_pseudo_register_collect (struct gdbarch *gdbarch,
+ gdbarch_ax_pseudo_register_collect_ftype ax_pseudo_register_collect)
+{
+ gdbarch->ax_pseudo_register_collect = ax_pseudo_register_collect;
+}
+
+int
+gdbarch_ax_pseudo_register_push_stack_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->ax_pseudo_register_push_stack != NULL;
+}
+
+int
+gdbarch_ax_pseudo_register_push_stack (struct gdbarch *gdbarch, struct agent_expr *ax, int reg)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->ax_pseudo_register_push_stack != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_ax_pseudo_register_push_stack called\n");
+ return gdbarch->ax_pseudo_register_push_stack (gdbarch, ax, reg);
+}
+
+void
+set_gdbarch_ax_pseudo_register_push_stack (struct gdbarch *gdbarch,
+ gdbarch_ax_pseudo_register_push_stack_ftype ax_pseudo_register_push_stack)
+{
+ gdbarch->ax_pseudo_register_push_stack = ax_pseudo_register_push_stack;
+}
+
+int
gdbarch_sp_regnum (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
--- a/gdbarch.h
+++ b/gdbarch.h
@@ -53,6 +53,7 @@ struct target_desc;
struct displaced_step_closure;
struct core_regset_section;
struct syscall;
+struct agent_expr;

/* The architecture associated with the connection to the target.

@@ -232,6 +233,25 @@ extern void set_gdbarch_num_regs (struct
extern int gdbarch_num_pseudo_regs (struct gdbarch *gdbarch);
extern void set_gdbarch_num_pseudo_regs (struct gdbarch *gdbarch, int num_pseudo_regs);

+/* Assemble agent expression bytecode to collect pseudo-register REG.
+ Return -1 if something goes wrong, 0 otherwise. */
+
+extern int gdbarch_ax_pseudo_register_collect_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_ax_pseudo_register_collect_ftype) (struct gdbarch *gdbarch, struct agent_expr *ax, int reg);
+extern int gdbarch_ax_pseudo_register_collect (struct gdbarch *gdbarch, struct agent_expr *ax, int reg);
+extern void set_gdbarch_ax_pseudo_register_collect (struct gdbarch *gdbarch, gdbarch_ax_pseudo_register_collect_ftype *ax_pseudo_register_collect);
+
+/* Assemble agent expression bytecode to push the value of pseudo-register
+ REG on the interpreter stack.
+ Return -1 if something goes wrong, 0 otherwise. */
+
+extern int gdbarch_ax_pseudo_register_push_stack_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_ax_pseudo_register_push_stack_ftype) (struct gdbarch *gdbarch, struct agent_expr *ax, int reg);
+extern int gdbarch_ax_pseudo_register_push_stack (struct gdbarch *gdbarch, struct agent_expr *ax, int reg);
+extern void set_gdbarch_ax_pseudo_register_push_stack (struct gdbarch *gdbarch, gdbarch_ax_pseudo_register_push_stack_ftype *ax_pseudo_register_push_stack);
+
/* GDB's standard (or well known) register numbers. These can map onto
a real register or a pseudo (computed) register or not be defined at
all (-1).
--- a/gdbarch.sh
+++ b/gdbarch.sh
@@ -427,6 +427,15 @@ v:int:num_regs:::0:-1
# combinations of other registers, or they may be computed by GDB.
v:int:num_pseudo_regs:::0:0::0

+# Assemble agent expression bytecode to collect pseudo-register REG.
+# Return -1 if something goes wrong, 0 otherwise.
+M:int:ax_pseudo_register_collect:struct agent_expr *ax, int reg:ax, reg
+
+# Assemble agent expression bytecode to push the value of pseudo-register
+# REG on the interpreter stack.
+# Return -1 if something goes wrong, 0 otherwise.
+M:int:ax_pseudo_register_push_stack:struct agent_expr *ax, int reg:ax, reg
+
# GDB's standard (or well known) register numbers. These can map onto
# a real register or a pseudo (computed) register or not be defined at
# all (-1).
@@ -919,6 +928,7 @@ struct target_desc;
struct displaced_step_closure;
struct core_regset_section;
struct syscall;
+struct agent_expr;

/* The architecture associated with the connection to the target.

--- a/mips-tdep.c
+++ b/mips-tdep.c
@@ -58,6 +58,7 @@
#include "dwarf2-frame.h"
#include "user-regs.h"
#include "valprint.h"
+#include "ax.h"

static const struct objfile_data *mips_pdr_data;

@@ -616,6 +617,48 @@ mips_pseudo_register_write (struct gdbar
internal_error (__FILE__, __LINE__, _("bad register size"));
}

+static int
+mips_ax_pseudo_register_collect (struct gdbarch *gdbarch,
+ struct agent_expr *ax, int reg)
+{
+ int rawnum = reg % gdbarch_num_regs (gdbarch);
+ gdb_assert (reg >= gdbarch_num_regs (gdbarch)
+ && reg < 2 * gdbarch_num_regs (gdbarch));
+
+ ax_reg_mask (ax, rawnum);
+
+ return 0;
+}
+
+static int
+mips_ax_pseudo_register_push_stack (struct gdbarch *gdbarch,
+ struct agent_expr *ax, int reg)
+{
+ int rawnum = reg % gdbarch_num_regs (gdbarch);
+ gdb_assert (reg >= gdbarch_num_regs (gdbarch)
+ && reg < 2 * gdbarch_num_regs (gdbarch));
+ if (register_size (gdbarch, rawnum) >= register_size (gdbarch, reg))
+ {
+ ax_reg (ax, rawnum);
+
+ if (register_size (gdbarch, rawnum) > register_size (gdbarch, reg))
+ {
+ if (!gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
+ || gdbarch_byte_order (gdbarch) != BFD_ENDIAN_BIG)
+ {
+ ax_const_l (ax, 32);
+ ax_simple (ax, aop_lsh);
+ }
+ ax_const_l (ax, 32);
+ ax_simple (ax, aop_rsh_signed);
+ }
+ }
+ else
+ internal_error (__FILE__, __LINE__, _("bad register size"));
+
+ return 0;
+}
+
/* Table to translate MIPS16 register field to actual register number. */
static int mips16_to_32_reg[8] = { 16, 17, 2, 3, 4, 5, 6, 7 };

@@ -5933,6 +5976,11 @@ mips_gdbarch_init (struct gdbarch_info i
set_gdbarch_pseudo_register_read (gdbarch, mips_pseudo_register_read);
set_gdbarch_pseudo_register_write (gdbarch, mips_pseudo_register_write);

+ set_gdbarch_ax_pseudo_register_collect (gdbarch,
+ mips_ax_pseudo_register_collect);
+ set_gdbarch_ax_pseudo_register_push_stack
+ (gdbarch, mips_ax_pseudo_register_push_stack);
+
set_gdbarch_elf_make_msymbol_special (gdbarch,
mips_elf_make_msymbol_special);