tech-toolchain archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

GDB breakpoint not working on alpha



For GDB on alpha, breakpoints sometimes do not work correctly:

  % gdb pwd
  GNU gdb (GDB) 7.12
  ...
  Reading symbols from pwd...Reading symbols from /tmp/pwd/pwd.debug...done.
  done.
  (gdb) b main
  Breakpoint 1 at 0x120000fa0: file pwd.c, line 71.
  (gdb) r
  Starting program: /tmp/pwd/pwd
  /tmp/pwd
  [Inferior 1 (process 8649) exited normally]
  (gdb)

This is because ___start skips first 8 bytes in main, and therefore a
breakpoint at the entrypoint of main (0x120000fa0):

  (gdb) disas ___start
  Dump of assembler code for function ___start:
  ...
     0x0000000120000c34 <+404>:   bsr     ra,0x120000fa8 <main+8>
  ...
  (gdb) disas main
  Dump of assembler code for function main:
     0x0000000120000fa0 <+0>:     ldah    gp,2(t12)
     0x0000000120000fa4 <+4>:     lda     gp,-31296(gp)
     0x0000000120000fa8 <+8>:     lda     sp,-48(sp)
     0x0000000120000fac <+12>:    stq     ra,0(sp)
     0x0000000120000fb0 <+16>:    stq     s0,8(sp)
  ...

Usually GDB skips the function prologue when it inserts a breakpoint,
but it does not skip when a target has been compiled by GCC with both
optimization and debugging information:

  https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commitdiff;h=6e22494e5076e4d3c0b2c2785883162f83db499e

Instead, GDB call gdbarch_skip_entrypoint() in this case, which is not
defined for almost platforms:

  https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commitdiff;h=141c5cc4c44a6ce1a5c628c0f4849a8b1c91d383

src/external/gpl3/gdb/dist/gdb/symtab.c
  3584  struct symtab_and_line
  3585  find_function_start_sal (struct symbol *sym, int funfirstline)
  3586  {
  ...
  3594    if (funfirstline && sal.symtab != NULL
  3595        && (COMPUNIT_LOCATIONS_VALID (SYMTAB_COMPUNIT (sal.symtab))
  3596            || SYMTAB_LANGUAGE (sal.symtab) == language_asm))
  3597      {
  3598        struct gdbarch *gdbarch = symbol_arch (sym);
  3599
  3600        sal.pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
  3601        if (gdbarch_skip_entrypoint_p (gdbarch))
  3602          sal.pc = gdbarch_skip_entrypoint (gdbarch, sal.pc);
  3603        return sal;
  3604      }
  ...
  3618    if (funfirstline)
  3619      skip_prologue_sal (&sal);
  3620
  3621    return sal;
  3622  }

The problem is who skips the first 8 bytes of main, out of control of
GCC. The answer is ld(1). It so clever that the redundant GP load in
function entrypoint is skipped:

src/external/gpl3/binutils/dist/bfd/elf64-alpha.c
  3180  static bfd_vma
  3181  elf64_alpha_relax_opt_call (struct alpha_relax_info *info, bfd_vma symva
l)
  3182  {
  3183    /* If the function has the same gp, and we can identify that the
  3184       function does not use its function pointer, we can eliminate the
  3185       address load.  */
  ...
  3241    /* We've now determined that we can skip an initial gp load.  Verify
  3242       that the call and the target use the same gp.   */
  3243    if (info->link_info->output_bfd->xvec != info->tsec->owner->xvec
  3244        || info->gotobj != alpha_elf_tdata (info->tsec->owner)->gotobj)
  3245      return 0;
  3246
  3247    return symval + 8;
  3248  }

We do not know for which function ld(1) determined the initial GP load
can be skipped. Therefore GDB should also skips initial GP loads for
every functions by using gdbarch_skip_entrypoint(), IMO.

With the attached patch below, breakpoints work well:

  % gdb.patched pwd
  GNU gdb (GDB) 7.12
  ...
  Reading symbols from pwd...Reading symbols from /var/shm/pwd/pwd.debug...done.
  done.
  (gdb) b main
  Breakpoint 1 at 0x120000fa8: file pwd.c, line 71.
  (gdb) r
  Starting program: /var/shm/pwd/pwd
Breakpoint 1, 0x0000000120000fa8 in main (argc=1, argv=0x1ffffd470) at pwd.c:71
  71      {
  (gdb)

Could I commit this? Any questions or suggestions?

Thanks,
Rin
--- src/external/gpl3/gdb/dist/gdb/alpha-tdep.c.orig	2016-12-15 05:13:41.674443412 +0900
+++ src/external/gpl3/gdb/dist/gdb/alpha-tdep.c	2016-12-15 05:37:39.860738374 +0900
@@ -757,6 +757,31 @@
   return pc + offset;
 }
+/* GNU ld for alpha is so clever that the redundant GP load in function
+   entrypoint is skipped.  We must therefore skip initial GP loads; otherwise
+   breakpoints in function entrypoints can also be skipped.  */
+
+static CORE_ADDR
+alpha_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  unsigned long inst;
+  gdb_byte buf[ALPHA_INSN_SIZE];
+
+  /* Refer to the comment in alpha_skip_prologue above.  */
+  if (target_read_memory (pc, buf, sizeof (buf)))
+    return pc;
+
+  /* Skip a GP load in the first two words in the function entrypoint.  */
+  inst = alpha_read_insn (gdbarch, pc);
+  if ((inst & 0xffff0000) != 0x27bb0000)	/* ldah $gp,n($t12) */
+    return pc;
+  inst = alpha_read_insn (gdbarch, pc + ALPHA_INSN_SIZE);
+  if ((inst & 0xffff0000) != 0x23bd0000)	/* lda $gp,n($gp) */
+    return pc;
+
+  return pc + 2 * ALPHA_INSN_SIZE;
+}
+
 
 static const int ldl_l_opcode = 0x2a;
 static const int ldq_l_opcode = 0x2b;
@@ -1802,6 +1827,9 @@
   /* Prologue heuristics.  */
   set_gdbarch_skip_prologue (gdbarch, alpha_skip_prologue);
+ /* Entrypoint heuristics. */
+  set_gdbarch_skip_entrypoint (gdbarch, alpha_skip_entrypoint);
+
   /* Disassembler.  */
   set_gdbarch_print_insn (gdbarch, print_insn_alpha);


Home | Main Index | Thread Index | Old Index