diff options
-rw-r--r-- | gdb/ChangeLog | 11 | ||||
-rw-r--r-- | gdb/gdbarch.c | 33 | ||||
-rw-r--r-- | gdb/gdbarch.h | 18 | ||||
-rwxr-xr-x | gdb/gdbarch.sh | 13 | ||||
-rw-r--r-- | gdb/infrun.c | 4 | ||||
-rw-r--r-- | gdb/ppc-linux-tdep.c | 57 | ||||
-rw-r--r-- | gdb/symtab.c | 2 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/sigbpt.exp | 2 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/step-bt.c | 11 |
10 files changed, 156 insertions, 2 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 2069aae..9f4636f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,16 @@ 2014-02-04 Ulrich Weigand <uweigand@de.ibm.com> + * gdbarch.sh (skip_entrypoint): New callback. + * gdbarch.c, gdbarch.h: Regenerate. + * symtab.c (skip_prologue_sal): Call gdbarch_skip_entrypoint. + * infrun.c (fill_in_stop_func): Likewise. + * ppc-linux-tdep.c: Include "elf/ppc64.h". + (ppc_elfv2_elf_make_msymbol_special): New function. + (ppc_elfv2_skip_entrypoint): Likewise. + (ppc_linux_init_abi): Install them for ELFv2. + +2014-02-04 Ulrich Weigand <uweigand@de.ibm.com> + * ppc-sysv-tdep.c (ppc64_aggregate_candidate): New routine. (ppc64_elfv2_abi_homogeneous_aggregate): Likewise. (ppc64_sysv_abi_push_param): Handle ELFv2 homogeneous structs. diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index ee41d50..e26681c 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -229,6 +229,7 @@ struct gdbarch gdbarch_return_in_first_hidden_param_p_ftype *return_in_first_hidden_param_p; gdbarch_skip_prologue_ftype *skip_prologue; gdbarch_skip_main_prologue_ftype *skip_main_prologue; + gdbarch_skip_entrypoint_ftype *skip_entrypoint; gdbarch_inner_than_ftype *inner_than; gdbarch_breakpoint_from_pc_ftype *breakpoint_from_pc; gdbarch_remote_breakpoint_from_pc_ftype *remote_breakpoint_from_pc; @@ -405,6 +406,7 @@ struct gdbarch startup_gdbarch = default_return_in_first_hidden_param_p, /* return_in_first_hidden_param_p */ 0, /* skip_prologue */ 0, /* skip_main_prologue */ + 0, /* skip_entrypoint */ 0, /* inner_than */ 0, /* breakpoint_from_pc */ default_remote_breakpoint_from_pc, /* remote_breakpoint_from_pc */ @@ -714,6 +716,7 @@ verify_gdbarch (struct gdbarch *gdbarch) if (gdbarch->skip_prologue == 0) fprintf_unfiltered (log, "\n\tskip_prologue"); /* Skip verify of skip_main_prologue, has predicate. */ + /* Skip verify of skip_entrypoint, has predicate. */ if (gdbarch->inner_than == 0) fprintf_unfiltered (log, "\n\tinner_than"); if (gdbarch->breakpoint_from_pc == 0) @@ -1353,6 +1356,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "gdbarch_dump: single_step_through_delay = <%s>\n", host_address_to_string (gdbarch->single_step_through_delay)); fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_skip_entrypoint_p() = %d\n", + gdbarch_skip_entrypoint_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: skip_entrypoint = <%s>\n", + host_address_to_string (gdbarch->skip_entrypoint)); + fprintf_unfiltered (file, "gdbarch_dump: gdbarch_skip_main_prologue_p() = %d\n", gdbarch_skip_main_prologue_p (gdbarch)); fprintf_unfiltered (file, @@ -2703,6 +2712,30 @@ set_gdbarch_skip_main_prologue (struct gdbarch *gdbarch, } int +gdbarch_skip_entrypoint_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->skip_entrypoint != NULL; +} + +CORE_ADDR +gdbarch_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR ip) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->skip_entrypoint != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_skip_entrypoint called\n"); + return gdbarch->skip_entrypoint (gdbarch, ip); +} + +void +set_gdbarch_skip_entrypoint (struct gdbarch *gdbarch, + gdbarch_skip_entrypoint_ftype skip_entrypoint) +{ + gdbarch->skip_entrypoint = skip_entrypoint; +} + +int gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs) { gdb_assert (gdbarch != NULL); diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index b28a80e..9698e11 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -486,6 +486,24 @@ typedef CORE_ADDR (gdbarch_skip_main_prologue_ftype) (struct gdbarch *gdbarch, C extern CORE_ADDR gdbarch_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR ip); extern void set_gdbarch_skip_main_prologue (struct gdbarch *gdbarch, gdbarch_skip_main_prologue_ftype *skip_main_prologue); +/* On some platforms, a single function may provide multiple entry points, + e.g. one that is used for function-pointer calls and a different one + that is used for direct function calls. + In order to ensure that breakpoints set on the function will trigger + no matter via which entry point the function is entered, a platform + may provide the skip_entrypoint callback. It is called with IP set + to the main entry point of a function (as determined by the symbol table), + and should return the address of the innermost entry point, where the + actual breakpoint needs to be set. Note that skip_entrypoint is used + by GDB common code even when debugging optimized code, where skip_prologue + is not used. */ + +extern int gdbarch_skip_entrypoint_p (struct gdbarch *gdbarch); + +typedef CORE_ADDR (gdbarch_skip_entrypoint_ftype) (struct gdbarch *gdbarch, CORE_ADDR ip); +extern CORE_ADDR gdbarch_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR ip); +extern void set_gdbarch_skip_entrypoint (struct gdbarch *gdbarch, gdbarch_skip_entrypoint_ftype *skip_entrypoint); + typedef int (gdbarch_inner_than_ftype) (CORE_ADDR lhs, CORE_ADDR rhs); extern int gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs); extern void set_gdbarch_inner_than (struct gdbarch *gdbarch, gdbarch_inner_than_ftype *inner_than); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 36dff57..e785999 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -530,6 +530,19 @@ m:int:return_in_first_hidden_param_p:struct type *type:type::default_return_in_f m:CORE_ADDR:skip_prologue:CORE_ADDR ip:ip:0:0 M:CORE_ADDR:skip_main_prologue:CORE_ADDR ip:ip +# On some platforms, a single function may provide multiple entry points, +# e.g. one that is used for function-pointer calls and a different one +# that is used for direct function calls. +# In order to ensure that breakpoints set on the function will trigger +# no matter via which entry point the function is entered, a platform +# may provide the skip_entrypoint callback. It is called with IP set +# to the main entry point of a function (as determined by the symbol table), +# and should return the address of the innermost entry point, where the +# actual breakpoint needs to be set. Note that skip_entrypoint is used +# by GDB common code even when debugging optimized code, where skip_prologue +# is not used. +M:CORE_ADDR:skip_entrypoint:CORE_ADDR ip:ip + f:int:inner_than:CORE_ADDR lhs, CORE_ADDR rhs:lhs, rhs:0:0 m:const gdb_byte *:breakpoint_from_pc:CORE_ADDR *pcptr, int *lenptr:pcptr, lenptr::0: # Return the adjusted address and kind to use for Z0/Z1 packets. diff --git a/gdb/infrun.c b/gdb/infrun.c index 71d9615..c0df124 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -3159,6 +3159,10 @@ fill_in_stop_func (struct gdbarch *gdbarch, ecs->stop_func_start += gdbarch_deprecated_function_start_offset (gdbarch); + if (gdbarch_skip_entrypoint_p (gdbarch)) + ecs->stop_func_start = gdbarch_skip_entrypoint (gdbarch, + ecs->stop_func_start); + ecs->stop_func_filled_in = 1; } } diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index 25008c0..6d3b2d8 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -44,6 +44,7 @@ #include "observer.h" #include "auxv.h" #include "elf/common.h" +#include "elf/ppc64.h" #include "exceptions.h" #include "arch-utils.h" #include "spu-tdep.h" @@ -876,6 +877,55 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch, } } + +/* Implementation of `gdbarch_elf_make_msymbol_special', as defined in + gdbarch.h. This implementation is used for the ELFv2 ABI only. */ + +static void +ppc_elfv2_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym) +{ + elf_symbol_type *elf_sym = (elf_symbol_type *)sym; + + /* If the symbol is marked as having a local entry point, set a target + flag in the msymbol. We currently only support local entry point + offsets of 8 bytes, which is the only entry point offset ever used + by current compilers. If/when other offsets are ever used, we will + have to use additional target flag bits to store them. */ + switch (PPC64_LOCAL_ENTRY_OFFSET (elf_sym->internal_elf_sym.st_other)) + { + default: + break; + case 8: + MSYMBOL_TARGET_FLAG_1 (msym) = 1; + break; + } +} + +/* Implementation of `gdbarch_skip_entrypoint', as defined in + gdbarch.h. This implementation is used for the ELFv2 ABI only. */ + +static CORE_ADDR +ppc_elfv2_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + struct bound_minimal_symbol fun; + int local_entry_offset = 0; + + fun = lookup_minimal_symbol_by_pc (pc); + if (fun.minsym == NULL) + return pc; + + /* See ppc_elfv2_elf_make_msymbol_special for how local entry point + offset values are encoded. */ + if (MSYMBOL_TARGET_FLAG_1 (fun.minsym)) + local_entry_offset = 8; + + if (SYMBOL_VALUE_ADDRESS (fun.minsym) <= pc + && pc < SYMBOL_VALUE_ADDRESS (fun.minsym) + local_entry_offset) + return SYMBOL_VALUE_ADDRESS (fun.minsym) + local_entry_offset; + + return pc; +} + /* Implementation of `gdbarch_stap_is_single_operand', as defined in gdbarch.h. */ @@ -1349,6 +1399,13 @@ ppc_linux_init_abi (struct gdbarch_info info, set_gdbarch_elf_make_msymbol_special (gdbarch, ppc64_elf_make_msymbol_special); } + else + { + set_gdbarch_elf_make_msymbol_special + (gdbarch, ppc_elfv2_elf_make_msymbol_special); + + set_gdbarch_skip_entrypoint (gdbarch, ppc_elfv2_skip_entrypoint); + } /* Shared library handling. */ set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code); diff --git a/gdb/symtab.c b/gdb/symtab.c index 97b85b8..50c09c1 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -2950,6 +2950,8 @@ skip_prologue_sal (struct symtab_and_line *sal) /* Skip "first line" of function (which is actually its prologue). */ pc += gdbarch_deprecated_function_start_offset (gdbarch); + if (gdbarch_skip_entrypoint_p (gdbarch)) + pc = gdbarch_skip_entrypoint (gdbarch, pc); if (skip) pc = gdbarch_skip_prologue (gdbarch, pc); diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 7378bb2..a6c5214 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,12 @@ 2014-02-04 Ulrich Weigand <uweigand@de.ibm.com> + * gdb.base/sigbpt.exp: Do not use "*" when setting breakpoint + on a function. + * gdb.base/step-bt.c: Call hello via function pointer to make + sure its first instruction is executed on powerpc64le-linux. + +2014-02-04 Ulrich Weigand <uweigand@de.ibm.com> + * gdb.arch/powerpc-d128-regs.exp: Enable on powerpc64*-*. 2014-02-04 Ulrich Weigand <uweigand@de.ibm.com> diff --git a/gdb/testsuite/gdb.base/sigbpt.exp b/gdb/testsuite/gdb.base/sigbpt.exp index 3d0db07..142e739 100644 --- a/gdb/testsuite/gdb.base/sigbpt.exp +++ b/gdb/testsuite/gdb.base/sigbpt.exp @@ -76,7 +76,7 @@ gdb_test "break keeper" set bowler_addrs bowler set segv_addr none gdb_test {display/i $pc} -gdb_test "advance *bowler" "bowler.*" "advance to the bowler" +gdb_test "advance bowler" "bowler.*" "advance to the bowler" set test "stepping to fault" set signame "SIGSEGV" gdb_test_multiple "stepi" "$test" { diff --git a/gdb/testsuite/gdb.base/step-bt.c b/gdb/testsuite/gdb.base/step-bt.c index e772a8e..2551ebe 100644 --- a/gdb/testsuite/gdb.base/step-bt.c +++ b/gdb/testsuite/gdb.base/step-bt.c @@ -23,10 +23,19 @@ hello (void) printf ("Hello world.\n"); } +/* The test case uses "break *hello" to make sure to step at the very + first instruction of the function. This causes a problem running + the test on powerpc64le-linux, since the first instruction belongs + to the global entry point prologue, which is skipped when doing a + local direct function call. To make sure that first instruction is + indeed being executed and the breakpoint hits, we make sure to call + the routine via an indirect call. */ +void (*ptr) (void) = hello; + int main (void) { - hello (); + ptr (); return 0; } |