Re: PING: PATCH: PR backtrace/14646: [x32] backtrace doesn't work

H.J. Lu
2012-10-05T02:08:18Z

On Wed, Oct 3, 2012 at 10:03 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Wed, Oct 3, 2012 at 8:59 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Wed, Oct 3, 2012 at 8:43 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>>> Date: Wed, 3 Oct 2012 08:26:34 -0700
>>>> From: "H.J. Lu" <hjl.tools@gmail.com>
>>>>
>>>> On Sun, Sep 30, 2012 at 2:40 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>> > Hi,
>>>> >
>>>> > amd64_x32_init_abi has
>>>> >
>>>> > tdep->sp_regnum_from_eax = AMD64_RSP_REGNUM;
>>>> > tdep->pc_regnum_from_eax = AMD64_RIP_REGNUM;
>>>> >
>>>> > But unwind frame info is based on the real RSP/RIP
>>>> > registers. Pseudo sp/pc registers don't work with
>>>> > frame related codes:
>>>> >
>>>> > [hjl@gnu-tools-1 gdb]$ egrep "pc_regnum|sp_regnum" *fram*.c
>>>> > dwarf2-frame.c: if (regnum == gdbarch_pc_regnum (gdbarch))
>>>> > dwarf2-frame.c: else if (regnum == gdbarch_sp_regnum (gdbarch))
>>>> > dwarf2-frame.c: == gdbarch_sp_regnum (gdbarch)))
>>>> > dwarf2-frame-tailcall.c: if (regnum == gdbarch_pc_regnum
>>>> > (this_gdbarch))
>>>> > dwarf2-frame-tailcall.c: else if (cache->prev_sp_p && regnum ==
>>>> > gdbarch_sp_regnum (this_gdbarch))
>>>> > dwarf2-frame-tailcall.c: int sp_regnum;
>>>> > dwarf2-frame-tailcall.c: sp_regnum = gdbarch_sp_regnum
>>>> > (prev_gdbarch);
>>>> > dwarf2-frame-tailcall.c: if (sp_regnum == -1)
>>>> > dwarf2-frame-tailcall.c: prev_sp = frame_unwind_register_unsigned
>>>> > (this_frame, sp_regnum);
>>>> > frame.c: && gdbarch_pc_regnum (gdbarch) >= 0
>>>> > frame.c: gdbarch_pc_regnum (gdbarch),
>>>> > frame.c: gdbarch_pc_regnum (gdbarch),
>>>> > frame.c: the gdbarch_sp_regnum register is meaningful. */
>>>> > frame.c: if (gdbarch_sp_regnum (gdbarch) >= 0)
>>>> > frame.c: gdbarch_sp_regnum (gdbarch));
>>>> > [hjl@gnu-tools-1 gdb]$
>>>> >
>>>> > It is nice to print
>>>> >
>>>> > (gdb) p $sp
>>>> > $1 = (void *) 0xffffd028
>>>> >
>>>> > instead of
>>>> >
>>>> > (gdb) p $sp
>>>> > $1 = 4294955048
>>>> >
>>>> > But it breaks frame unwind. This patch removes pseudo sp/pc regnum from
>>>> > x32. "p $sp" and "p $pc" will print 64bit integers. But "p $esp" and
>>>> > "p $esp" work fine. OK for trunk and 4.5 branch?
>>>> >
>>>> > Thanks.
>>>> >
>>>> >
>>>> > H.J.
>>>> > ---
>>>> > 2012-09-30 H.J. Lu <hongjiu.lu@intel.com>
>>>> >
>>>> > PR backtrace/14646
>>>> > PR gdb/14647
>>>> > * i386-tdep.h (gdbarch_tdep): Remove sp_regnum_from_eax and
>>>> > pc_regnum_from_eax.
>>>> > * i386-tdep.c (i386_gdbarch_init): Don't use sp_regnum_from_eax
>>>> > nor pc_regnum_from_eax.
>>>> > * amd64-tdep.c (amd64_x32_init_abi): Don't set sp_regnum_from_eax
>>>> > nor pc_regnum_from_eax.
>>>> >
>>>
>>> There's got to be a better way to handle that. Did you look into
>>> using dwarf2_frame_set_init_reg() to establish mappings to the "raw"
>>> rip and rsp registers?
>>
>> It doesn't work for x32 since gdbarch_sp_regnum and
>> gdbarch_pc_regnum are used like:
>>
>> if (get_frame_func_if_available (this_frame, &entry_pc))
>> {
>> /* Decode the insns in the FDE up to the entry PC. */
>> instr = execute_cfa_program (fde, fde->instructions, fde->end, gdbarch,
>> entry_pc, fs);
>>
>> if (fs->regs.cfa_how == CFA_REG_OFFSET
>> && (gdbarch_dwarf2_reg_to_regnum (gdbarch, fs->regs.cfa_reg)
>> == gdbarch_sp_regnum (gdbarch)))
>> {
>> entry_cfa_sp_offset = fs->regs.cfa_offset;
>> entry_cfa_sp_offset_p = 1;
>> }
>> }
>>
>> gdbarch_sp_regnum will return the wrong register number. If there are
>> gdbarch_frame_sp_regnum and gdbarch_frame_pc_regnum, which
>> default to gdbarch_sp_regnum and gdbarch_pc_regnum, respectively,
>> and use them everywhere, except for "p $pc/$sp", x32 can set up proper
>> gdbarch_frame_sp_regnum and gdbarch_frame_pc_regnum.
>>
>
> This patch adds frame_sp_regnum and frame_pc_regnum, which
> are used for "p $pc"/"p $sp". I can override them for x32 with
>
> static int
> amd64_x32_frame_pc_regnum (struct gdbarch *gdbarch)
> {
> struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> return tdep->eax_regnum + AMD64_RIP_REGNUM;
> }
>
> static int
> amd64_x32_frame_sp_regnum (struct gdbarch *gdbarch)
> {
> struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> return tdep->eax_regnum + AMD64_RSP_REGNUM;
> }
>
> Any comments?
>
> Thanks.
>
> --
> H.J.
> ---
> 2012-10-03 H.J. Lu <hongjiu.lu@intel.com>
>
> * frame.h (default_frame_pc_regnum): New prototype.
> (default_frame_sp_regnum): Likewise.
> * gdbarch.sh: Add frame_sp_regnum and frame_pc_regnum.
> * std-regs.c (default_frame_pc_regnum): New function.
> (default_frame_sp_regnum): Likewise.
> (value_of_builtin_frame_pc_reg): Replace gdbarch_pc_regnum
> with gdbarch_frame_pc_regnum.
> (value_of_builtin_frame_sp_reg): Replace gdbarch_sp_regnum
> with gdbarch_frame_sp_regnum.
> * gdbarch.c: Regenerated.
> * gdbarch.h: Likewise.
>

Pseudo registers, like esp, aren't updated during stack unwind:

http://sourceware.org/bugzilla/show_bug.cgi?id=14673

--
H.J.