aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog11
-rw-r--r--gdb/gdbarch.c33
-rw-r--r--gdb/gdbarch.h18
-rwxr-xr-xgdb/gdbarch.sh13
-rw-r--r--gdb/infrun.c4
-rw-r--r--gdb/ppc-linux-tdep.c57
-rw-r--r--gdb/symtab.c2
-rw-r--r--gdb/testsuite/ChangeLog7
-rw-r--r--gdb/testsuite/gdb.base/sigbpt.exp2
-rw-r--r--gdb/testsuite/gdb.base/step-bt.c11
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;
}