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