Re: [RFA] sighandler backtrace on x86-64

Elena Zannoni
2002-09-19T16:00:34Z

Michal Ludvig writes:
> Hi all,
> the attached patch enables backtrace through signal handlers on x86-64.
> It isn't yet complete, but this is the part that works.
> Can someone approve it please?
>
> Michal Ludvig
> --
> * SuSE CR, s.r.o * mludvig@suse.cz
> * +420 2 9654 5373 * http://www.suse.cz
> 2002-09-18 Michal Ludvig <mludvig@suse.cz>
>
> * dwarf2cfi.c (struct context)
> (struct context_reg): Moved to dwarf2cfi.h
> (context_alloc, frame_state_alloc, context_cpy):
> Made extern instead of static, removed prototypes.
> * dwarf2cfi.h (struct context)
> (struct context_reg): New, moved from dwarf2cfi.c
> (context_alloc, frame_state_alloc, context_cpy):
> New prototypes.

I don't see any uses of the structures and functions you are exporting.
Could you postpone these changes until they are actually used?
I have some comments anyway, see below.

> * x86-64-linux-tdep.c (x86_64_linux_sigtramp_saved_pc):
> Changed from static to extern.
> (LINUX_SIGINFO_SIZE, LINUX_SIGCONTEXT_PC_OFFSET)
> (LINUX_SIGCONTEXT_FP_OFFSET)
> (LINUX_UCONTEXT_SIGCONTEXT_OFFSET): Adjusted.
> (x86_64_linux_in_sigtramp, x86_64_linux_frame_chain)
> (x86_64_init_frame_pc, x86_64_init_extra_frame_info): New.
> * x86-64-tdep.c (x86_64_gdbarch_init): Several
> set_gdbarch_*() calls now use x86-64 specific functions
> instead of DWARF2 CFI ones.
> * x86-64-tdep.h (x86_64_linux_in_sigtramp)
> (x86_64_linux_frame_chain, x86_64_init_frame_pc)
> (x86_64_init_extra_frame_info): New prototypes.
>
> Index: dwarf2cfi.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/dwarf2cfi.c,v
> retrieving revision 1.16
> diff -u -p -r1.16 dwarf2cfi.c
> --- dwarf2cfi.c 19 Jul 2002 09:40:51 -0000 1.16
> +++ dwarf2cfi.c 18 Sep 2002 11:11:02 -0000
> @@ -90,37 +90,6 @@ struct fde_array
> int array_size;
> };
>
> -struct context_reg
> -{
> - union
> - {
> - unsigned int reg;
> - long offset;
> - CORE_ADDR addr;
> - }
> - loc;
> - enum
> - {
> - REG_CTX_UNSAVED,
> - REG_CTX_SAVED_OFFSET,
> - REG_CTX_SAVED_REG,
> - REG_CTX_SAVED_ADDR,
> - REG_CTX_VALUE,
> - }
> - how;
> -};
> -
> -/* This is the register and unwind state for a particular frame. */
> -struct context
> -{
> - struct context_reg *reg;
> -
> - CORE_ADDR cfa;
> - CORE_ADDR ra;
> - void *lsda;
> - int args_size;
> -};
> -
> struct frame_state_reg
> {
> union
> @@ -208,11 +177,8 @@ static struct fde_unit *fde_unit_alloc (
> static struct cie_unit *cie_unit_alloc (void);
> static void fde_chunks_need_space ();
>
> -static struct context *context_alloc ();
> -static struct frame_state *frame_state_alloc ();
> static void unwind_tmp_obstack_init ();
> static void unwind_tmp_obstack_free ();
> -static void context_cpy (struct context *dst, struct context *src);
>
> static unsigned int read_1u (bfd * abfd, char **p);
> static int read_1s (bfd * abfd, char **p);
> @@ -286,7 +252,7 @@ fde_chunks_need_space (void)
> }
>
> /* Alocate a new `struct context' on temporary obstack. */
> -static struct context *
> +struct context *
> context_alloc (void)
> {
> struct context *context;
> @@ -303,7 +269,7 @@ context_alloc (void)
> }
>
> /* Alocate a new `struct frame_state' on temporary obstack. */
> -static struct frame_state *
> +struct frame_state *
> frame_state_alloc (void)
> {
> struct frame_state *fs;
> @@ -332,7 +298,7 @@ unwind_tmp_obstack_free (void)
> unwind_tmp_obstack_init ();
> }
>
> -static void
> +void
> context_cpy (struct context *dst, struct context *src)
> {
> int regs_size = sizeof (struct context_reg) * NUM_REGS;
> Index: dwarf2cfi.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/dwarf2cfi.h,v
> retrieving revision 1.1
> diff -u -p -r1.1 dwarf2cfi.h
> --- dwarf2cfi.h 7 Dec 2001 12:10:15 -0000 1.1
> +++ dwarf2cfi.h 18 Sep 2002 11:11:02 -0000
> @@ -22,6 +22,37 @@
> #ifndef DWARF2CFI_H
> #define DWARF2CFI_H
>
> +struct context_reg
> +{
> + union
> + {
> + unsigned int reg;
> + long offset;
> + CORE_ADDR addr;
> + }
> + loc;
> + enum
> + {
> + REG_CTX_UNSAVED,
> + REG_CTX_SAVED_OFFSET,
> + REG_CTX_SAVED_REG,
> + REG_CTX_SAVED_ADDR,
> + REG_CTX_VALUE,
> + }
> + how;
> +};
> +
> +/* This is the register and unwind state for a particular frame. */
> +struct context
> +{
> + struct context_reg *reg;
> +
> + CORE_ADDR cfa;
> + CORE_ADDR ra;
> + void *lsda;
> + int args_size;
> +};
> +

Do you need to make the whole structure accessible? would it be enough
for your purposes to just add
struct context;
struct context_reg;

to the .h file?

> /* Return the frame address. */
> CORE_ADDR cfi_read_fp ();
>
> @@ -63,4 +94,7 @@ void cfi_get_saved_register (char *raw_b
> void cfi_virtual_frame_pointer (CORE_ADDR pc, int *frame_regnum,
> LONGEST * frame_offset);
>
> +struct context *context_alloc ();
> +void context_cpy (struct context *dst, struct context *src);
> +struct frame_state *frame_state_alloc ();

'extern' keyword?

Elena

> #endif
> Index: x86-64-linux-tdep.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/x86-64-linux-tdep.c,v
> retrieving revision 1.5
> diff -u -p -r1.5 x86-64-linux-tdep.c
> --- x86-64-linux-tdep.c 3 Sep 2002 13:06:33 -0000 1.5
> +++ x86-64-linux-tdep.c 18 Sep 2002 11:11:02 -0000
> @@ -35,8 +35,10 @@
> #define LINUX_SIGTRAMP_OFFSET1 (7)
>
> static const unsigned char linux_sigtramp_code[] = {
> - LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x89, 0x00, 0x00, 0x00, /* mov $0x89,%rax */
> - LINUX_SIGTRAMP_INSN1, 0x05 /* syscall */
> + /* mov $__NR_rt_sigreturn,%rax */
> + LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x0f, 0x00, 0x00, 0x00,
> + /* syscall */
> + LINUX_SIGTRAMP_INSN1, 0x05
> };
>
> #define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
> @@ -68,17 +70,22 @@ x86_64_linux_sigtramp_start (CORE_ADDR p
> return pc;
> }
>
> -#define LINUX_SIGINFO_SIZE 128
> +#define LINUX_SIGINFO_SIZE 0
>
> /* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>. */
> -#define LINUX_UCONTEXT_SIGCONTEXT_OFFSET (36)
> +#define LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40
> +
> +/* Offset to saved PC in sigcontext, from <asm/sigcontext.h>. */
> +#define LINUX_SIGCONTEXT_PC_OFFSET 128
> +#define LINUX_SIGCONTEXT_FP_OFFSET 120
>
> /* Assuming FRAME is for a GNU/Linux sigtramp routine, return the
> address of the associated sigcontext structure. */
> -CORE_ADDR
> +static CORE_ADDR
> x86_64_linux_sigcontext_addr (struct frame_info *frame)
> {
> CORE_ADDR pc;
> + ULONGEST rsp;
>
> pc = x86_64_linux_sigtramp_start (frame->pc);
> if (pc)
> @@ -92,7 +99,8 @@ x86_64_linux_sigcontext_addr (struct fra
>
>
> /* This is the top frame. */
> - return read_register (SP_REGNUM) + LINUX_SIGINFO_SIZE +
> + rsp = read_register (SP_REGNUM);
> + return rsp + LINUX_SIGINFO_SIZE +
> LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
>
> }
> @@ -101,13 +109,10 @@ x86_64_linux_sigcontext_addr (struct fra
> return 0;
> }
>
> -/* Offset to saved PC in sigcontext, from <asm/sigcontext.h>. */
> -#define LINUX_SIGCONTEXT_PC_OFFSET (136)
> -
> /* Assuming FRAME is for a GNU/Linux sigtramp routine, return the
> saved program counter. */
>
> -CORE_ADDR
> +static CORE_ADDR
> x86_64_linux_sigtramp_saved_pc (struct frame_info *frame)
> {
> CORE_ADDR addr;
> @@ -134,4 +139,62 @@ x86_64_linux_frame_saved_pc (struct fram
> if (frame->signal_handler_caller)
> return x86_64_linux_sigtramp_saved_pc (frame);
> return cfi_get_ra (frame);
> +}
> +
> +/* Return whether PC is in a GNU/Linux sigtramp routine. */
> +
> +int
> +x86_64_linux_in_sigtramp (CORE_ADDR pc, char *name)
> +{
> + if (name)
> + return STREQ ("__restore_rt", name);
> +
> + return (x86_64_linux_sigtramp_start (pc) != 0);
> +}
> +
> +CORE_ADDR
> +x86_64_linux_frame_chain (struct frame_info *fi)
> +{
> + ULONGEST addr;
> + CORE_ADDR fp, pc;
> +
> + if (! fi->signal_handler_caller)
> + {
> + fp = cfi_frame_chain (fi);
> + if(fp)
> + return fp;
> + else
> + addr = fi->frame;
> + }
> + else
> + addr = fi->next->frame;
> +
> + addr += LINUX_SIGINFO_SIZE + LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
> +
> + fp = read_memory_integer (addr + LINUX_SIGCONTEXT_FP_OFFSET, 8)+8;
> +
> + return fp;
> +}
> +
> +void
> +x86_64_init_frame_pc (int fromleaf, struct frame_info *fi)
> +{
> + CORE_ADDR addr;
> +
> + if(fi->next && fi->next->signal_handler_caller)
> + {
> + addr = fi->next->next->frame
> + + LINUX_SIGINFO_SIZE
> + + LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
> + fi->pc = read_memory_integer (addr
> + + LINUX_SIGCONTEXT_PC_OFFSET, 8);
> + }
> + else
> + cfi_init_frame_pc (fromleaf, fi);
> +}
> +
> +void
> +x86_64_init_extra_frame_info (int fromleaf, struct frame_info *fi)
> +{
> + cfi_init_extra_frame_info (fromleaf, fi);
> }
> Index: x86-64-tdep.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/x86-64-tdep.c,v
> retrieving revision 1.27
> diff -u -p -r1.27 x86-64-tdep.c
> --- x86-64-tdep.c 12 Sep 2002 08:39:26 -0000 1.27
> +++ x86-64-tdep.c 18 Sep 2002 11:11:03 -0000
> @@ -1026,7 +1026,7 @@ x86_64_gdbarch_init (struct gdbarch_info
>
> /* FRAME_CHAIN takes a frame's nominal address and produces the frame's
> chain-pointer. */
> - set_gdbarch_frame_chain (gdbarch, cfi_frame_chain);
> + set_gdbarch_frame_chain (gdbarch, x86_64_linux_frame_chain);
>
> set_gdbarch_frameless_function_invocation (gdbarch,
> x86_64_frameless_function_invocation);
> @@ -1041,10 +1041,10 @@ x86_64_gdbarch_init (struct gdbarch_info
> set_gdbarch_frame_init_saved_regs (gdbarch, x86_64_frame_init_saved_regs);
>
> /* Frame pc initialization is handled by unwind informations. */
> - set_gdbarch_init_frame_pc (gdbarch, cfi_init_frame_pc);
> + set_gdbarch_init_frame_pc (gdbarch, x86_64_init_frame_pc);
>
> /* Initialization of unwind informations. */
> - set_gdbarch_init_extra_frame_info (gdbarch, cfi_init_extra_frame_info);
> + set_gdbarch_init_extra_frame_info (gdbarch, x86_64_init_extra_frame_info);
>
> /* Getting saved registers is handled by unwind informations. */
> set_gdbarch_get_saved_register (gdbarch, cfi_get_saved_register);
> @@ -1054,8 +1054,7 @@ x86_64_gdbarch_init (struct gdbarch_info
> /* Cons up virtual frame pointer for trace */
> set_gdbarch_virtual_frame_pointer (gdbarch, cfi_virtual_frame_pointer);
>
> -
> - set_gdbarch_frame_chain_valid (gdbarch, generic_file_frame_chain_valid);
> + set_gdbarch_frame_chain_valid (gdbarch, file_frame_chain_valid);
>
> set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
> set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
> @@ -1121,6 +1120,8 @@ x86_64_gdbarch_init (struct gdbarch_info
> /* Use dwarf2 debug frame informations. */
> set_gdbarch_dwarf2_build_frame_info (gdbarch, dwarf2_build_frame_info);
> set_gdbarch_dwarf2_reg_to_regnum (gdbarch, x86_64_dwarf2_reg_to_regnum);
> +
> + set_gdbarch_pc_in_sigtramp (gdbarch, x86_64_linux_in_sigtramp);
>
> return gdbarch;
> }
> Index: x86-64-tdep.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/x86-64-tdep.h,v
> retrieving revision 1.5
> diff -u -p -r1.5 x86-64-tdep.h
> --- x86-64-tdep.h 20 Jun 2002 13:08:12 -0000 1.5
> +++ x86-64-tdep.h 18 Sep 2002 11:11:03 -0000
> @@ -31,8 +31,12 @@ extern int x86_64_num_gregs;
> int x86_64_register_number (const char *name);
> const char *x86_64_register_name (int reg_nr);
>
> -
> gdbarch_frame_saved_pc_ftype x86_64_linux_frame_saved_pc;
> gdbarch_saved_pc_after_call_ftype x86_64_linux_saved_pc_after_call;
> +gdbarch_pc_in_sigtramp_ftype x86_64_linux_in_sigtramp;
> +CORE_ADDR x86_64_linux_frame_chain (struct frame_info *fi);
> +void x86_64_init_frame_pc (int fromleaf, struct frame_info *fi);
> +void x86_64_init_extra_frame_info (int fromleaf, struct frame_info *fi);
> +
>
> #endif