Blame SOURCES/gdb-rhbz1125820-ppc64le-enablement-33of37.patch

2c2fa1
commit 591a12a1d4c8843343eb999145d8bcc1efedf408
2c2fa1
Author: Ulrich Weigand <ulrich.weigand@de.ibm.com>
2c2fa1
Date:   Tue Feb 4 18:44:14 2014 +0100
2c2fa1
2c2fa1
    PowerPC64 ELFv2 ABI: skip global entry point code
2c2fa1
    
2c2fa1
    This patch handles another aspect of the ELFv2 ABI, which unfortunately
2c2fa1
    requires common code changes.
2c2fa1
    
2c2fa1
    In ELFv2, functions may provide both a global and a local entry point.
2c2fa1
    The global entry point (where the function symbol points to) is intended
2c2fa1
    to be used for function-pointer or cross-module (PLT) calls, and requires
2c2fa1
    r12 to be set up to the entry point address itself.   The local entry
2c2fa1
    point (which is found at a fixed offset after the global entry point,
2c2fa1
    as defined by bits in the symbol table entries' st_other field), instead
2c2fa1
    expects r2 to be set up to the current TOC.
2c2fa1
    
2c2fa1
    Now, when setting a breakpoint on a function by name, you really want
2c2fa1
    that breakpoint to trigger either way, no matter whether the function
2c2fa1
    is called via its local or global entry point.  Since the global entry
2c2fa1
    point will always fall through into the local entry point, the way to
2c2fa1
    achieve that is to simply set the breakpoint at the local entry point.
2c2fa1
    
2c2fa1
    One way to do that would be to have prologue parsing skip the code
2c2fa1
    sequence that makes up the global entry point.  Unfortunately, this
2c2fa1
    does not work reliably, since -for optimized code- GDB these days
2c2fa1
    will not actuall invoke the prologue parsing code but instead just
2c2fa1
    set the breakpoint at the symbol address and rely on DWARF being
2c2fa1
    correct at any point throughout the function ...
2c2fa1
    
2c2fa1
    Unfortunately, I don't really see any way to express the notion of
2c2fa1
    local entry points with the current set of gdbarch callbacks.
2c2fa1
    
2c2fa1
    Thus this patch adds a new callback, skip_entrypoint, that is
2c2fa1
    somewhat analogous to skip_prologue, but is called every time
2c2fa1
    GDB needs to determine a function start address, even in those
2c2fa1
    cases where GDB decides to not call skip_prologue.
2c2fa1
    
2c2fa1
    As a side effect, the skip_entrypoint implementation on ppc64
2c2fa1
    does not need to perform any instruction parsing; it can simply
2c2fa1
    rely on the local entry point flags in the symbol table entry.
2c2fa1
    
2c2fa1
    With this implemented, two test cases would still fail to set
2c2fa1
    the breakpoint correctly, but that's because they use the construct:
2c2fa1
    
2c2fa1
     gdb_test "break *hello"
2c2fa1
    
2c2fa1
    Now, using "*hello" explicitly instructs GDB to set the breakpoint
2c2fa1
    at the numerical value of "hello" treated as function pointer, so
2c2fa1
    it will by definition only hit the global entry point.
2c2fa1
    
2c2fa1
    I think this behaviour is unavoidable, but acceptable -- most people
2c2fa1
    do not use this construct, and if they do, they get what they
2c2fa1
    asked for ...
2c2fa1
    
2c2fa1
    In one of those two test cases, use of this construct is really
2c2fa1
    not appropriate.  I think this was added way back when as a means
2c2fa1
    to work around prologue skipping problems on some platforms.  These
2c2fa1
    days that shouldn't really be necessary any more ...
2c2fa1
    
2c2fa1
    For the other (step-bt), we really want to make sure backtracing
2c2fa1
    works on the very first instruction of the routine.  To enable that
2c2fa1
    test also on powerpc64le-linux, we can modify the code to call the
2c2fa1
    test function via function pointer (which makes it use the global
2c2fa1
    entry point in the ELFv2 ABI).
2c2fa1
    
2c2fa1
    gdb/ChangeLog:
2c2fa1
    
2c2fa1
    	* gdbarch.sh (skip_entrypoint): New callback.
2c2fa1
    	* gdbarch.c, gdbarch.h: Regenerate.
2c2fa1
    	* symtab.c (skip_prologue_sal): Call gdbarch_skip_entrypoint.
2c2fa1
    	* infrun.c (fill_in_stop_func): Likewise.
2c2fa1
    	* ppc-linux-tdep.c: Include "elf/ppc64.h".
2c2fa1
    	(ppc_elfv2_elf_make_msymbol_special): New function.
2c2fa1
    	(ppc_elfv2_skip_entrypoint): Likewise.
2c2fa1
    	(ppc_linux_init_abi): Install them for ELFv2.
2c2fa1
    
2c2fa1
    gdb/testsuite/ChangeLog:
2c2fa1
    
2c2fa1
    	* gdb.base/sigbpt.exp: Do not use "*" when setting breakpoint
2c2fa1
    	on a function.
2c2fa1
    	* gdb.base/step-bt.c: Call hello via function pointer to make
2c2fa1
    	sure its first instruction is executed on powerpc64le-linux.
2c2fa1
2c2fa1
Index: gdb-7.6.1/gdb/gdbarch.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/gdbarch.c
2c2fa1
+++ gdb-7.6.1/gdb/gdbarch.c
2c2fa1
@@ -200,6 +200,7 @@ struct gdbarch
2c2fa1
   gdbarch_return_in_first_hidden_param_p_ftype *return_in_first_hidden_param_p;
2c2fa1
   gdbarch_skip_prologue_ftype *skip_prologue;
2c2fa1
   gdbarch_skip_main_prologue_ftype *skip_main_prologue;
2c2fa1
+  gdbarch_skip_entrypoint_ftype *skip_entrypoint;
2c2fa1
   gdbarch_inner_than_ftype *inner_than;
2c2fa1
   gdbarch_breakpoint_from_pc_ftype *breakpoint_from_pc;
2c2fa1
   gdbarch_remote_breakpoint_from_pc_ftype *remote_breakpoint_from_pc;
2c2fa1
@@ -371,6 +372,7 @@ struct gdbarch startup_gdbarch =
2c2fa1
   default_return_in_first_hidden_param_p,  /* return_in_first_hidden_param_p */
2c2fa1
   0,  /* skip_prologue */
2c2fa1
   0,  /* skip_main_prologue */
2c2fa1
+  0,  /* skip_entrypoint */
2c2fa1
   0,  /* inner_than */
2c2fa1
   0,  /* breakpoint_from_pc */
2c2fa1
   default_remote_breakpoint_from_pc,  /* remote_breakpoint_from_pc */
2c2fa1
@@ -672,6 +674,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
2c2fa1
   if (gdbarch->skip_prologue == 0)
2c2fa1
     fprintf_unfiltered (log, "\n\tskip_prologue");
2c2fa1
   /* Skip verify of skip_main_prologue, has predicate.  */
2c2fa1
+  /* Skip verify of skip_entrypoint, has predicate.  */
2c2fa1
   if (gdbarch->inner_than == 0)
2c2fa1
     fprintf_unfiltered (log, "\n\tinner_than");
2c2fa1
   if (gdbarch->breakpoint_from_pc == 0)
2c2fa1
@@ -1285,6 +1288,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s
2c2fa1
                       "gdbarch_dump: single_step_through_delay = <%s>\n",
2c2fa1
                       host_address_to_string (gdbarch->single_step_through_delay));
2c2fa1
   fprintf_unfiltered (file,
2c2fa1
+                      "gdbarch_dump: gdbarch_skip_entrypoint_p() = %d\n",
2c2fa1
+                      gdbarch_skip_entrypoint_p (gdbarch));
2c2fa1
+  fprintf_unfiltered (file,
2c2fa1
+                      "gdbarch_dump: skip_entrypoint = <%s>\n",
2c2fa1
+                      host_address_to_string (gdbarch->skip_entrypoint));
2c2fa1
+  fprintf_unfiltered (file,
2c2fa1
                       "gdbarch_dump: gdbarch_skip_main_prologue_p() = %d\n",
2c2fa1
                       gdbarch_skip_main_prologue_p (gdbarch));
2c2fa1
   fprintf_unfiltered (file,
2c2fa1
@@ -2635,6 +2644,30 @@ set_gdbarch_skip_main_prologue (struct g
2c2fa1
 }
2c2fa1
 
2c2fa1
 int
2c2fa1
+gdbarch_skip_entrypoint_p (struct gdbarch *gdbarch)
2c2fa1
+{
2c2fa1
+  gdb_assert (gdbarch != NULL);
2c2fa1
+  return gdbarch->skip_entrypoint != NULL;
2c2fa1
+}
2c2fa1
+
2c2fa1
+CORE_ADDR
2c2fa1
+gdbarch_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR ip)
2c2fa1
+{
2c2fa1
+  gdb_assert (gdbarch != NULL);
2c2fa1
+  gdb_assert (gdbarch->skip_entrypoint != NULL);
2c2fa1
+  if (gdbarch_debug >= 2)
2c2fa1
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_skip_entrypoint called\n");
2c2fa1
+  return gdbarch->skip_entrypoint (gdbarch, ip);
2c2fa1
+}
2c2fa1
+
2c2fa1
+void
2c2fa1
+set_gdbarch_skip_entrypoint (struct gdbarch *gdbarch,
2c2fa1
+                             gdbarch_skip_entrypoint_ftype skip_entrypoint)
2c2fa1
+{
2c2fa1
+  gdbarch->skip_entrypoint = skip_entrypoint;
2c2fa1
+}
2c2fa1
+
2c2fa1
+int
2c2fa1
 gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs)
2c2fa1
 {
2c2fa1
   gdb_assert (gdbarch != NULL);
2c2fa1
Index: gdb-7.6.1/gdb/gdbarch.h
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/gdbarch.h
2c2fa1
+++ gdb-7.6.1/gdb/gdbarch.h
2c2fa1
@@ -487,6 +487,24 @@ typedef CORE_ADDR (gdbarch_skip_main_pro
2c2fa1
 extern CORE_ADDR gdbarch_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR ip);
2c2fa1
 extern void set_gdbarch_skip_main_prologue (struct gdbarch *gdbarch, gdbarch_skip_main_prologue_ftype *skip_main_prologue);
2c2fa1
 
2c2fa1
+/* On some platforms, a single function may provide multiple entry points,
2c2fa1
+   e.g. one that is used for function-pointer calls and a different one
2c2fa1
+   that is used for direct function calls.
2c2fa1
+   In order to ensure that breakpoints set on the function will trigger
2c2fa1
+   no matter via which entry point the function is entered, a platform
2c2fa1
+   may provide the skip_entrypoint callback.  It is called with IP set
2c2fa1
+   to the main entry point of a function (as determined by the symbol table),
2c2fa1
+   and should return the address of the innermost entry point, where the
2c2fa1
+   actual breakpoint needs to be set.  Note that skip_entrypoint is used
2c2fa1
+   by GDB common code even when debugging optimized code, where skip_prologue
2c2fa1
+   is not used. */
2c2fa1
+
2c2fa1
+extern int gdbarch_skip_entrypoint_p (struct gdbarch *gdbarch);
2c2fa1
+
2c2fa1
+typedef CORE_ADDR (gdbarch_skip_entrypoint_ftype) (struct gdbarch *gdbarch, CORE_ADDR ip);
2c2fa1
+extern CORE_ADDR gdbarch_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR ip);
2c2fa1
+extern void set_gdbarch_skip_entrypoint (struct gdbarch *gdbarch, gdbarch_skip_entrypoint_ftype *skip_entrypoint);
2c2fa1
+
2c2fa1
 typedef int (gdbarch_inner_than_ftype) (CORE_ADDR lhs, CORE_ADDR rhs);
2c2fa1
 extern int gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs);
2c2fa1
 extern void set_gdbarch_inner_than (struct gdbarch *gdbarch, gdbarch_inner_than_ftype *inner_than);
2c2fa1
Index: gdb-7.6.1/gdb/gdbarch.sh
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/gdbarch.sh
2c2fa1
+++ gdb-7.6.1/gdb/gdbarch.sh
2c2fa1
@@ -527,6 +527,19 @@ m:int:return_in_first_hidden_param_p:str
2c2fa1
 
2c2fa1
 m:CORE_ADDR:skip_prologue:CORE_ADDR ip:ip:0:0
2c2fa1
 M:CORE_ADDR:skip_main_prologue:CORE_ADDR ip:ip
2c2fa1
+# On some platforms, a single function may provide multiple entry points,
2c2fa1
+# e.g. one that is used for function-pointer calls and a different one
2c2fa1
+# that is used for direct function calls.
2c2fa1
+# In order to ensure that breakpoints set on the function will trigger
2c2fa1
+# no matter via which entry point the function is entered, a platform
2c2fa1
+# may provide the skip_entrypoint callback.  It is called with IP set
2c2fa1
+# to the main entry point of a function (as determined by the symbol table),
2c2fa1
+# and should return the address of the innermost entry point, where the
2c2fa1
+# actual breakpoint needs to be set.  Note that skip_entrypoint is used
2c2fa1
+# by GDB common code even when debugging optimized code, where skip_prologue
2c2fa1
+# is not used.
2c2fa1
+M:CORE_ADDR:skip_entrypoint:CORE_ADDR ip:ip
2c2fa1
+
2c2fa1
 f:int:inner_than:CORE_ADDR lhs, CORE_ADDR rhs:lhs, rhs:0:0
2c2fa1
 m:const gdb_byte *:breakpoint_from_pc:CORE_ADDR *pcptr, int *lenptr:pcptr, lenptr::0:
2c2fa1
 # Return the adjusted address and kind to use for Z0/Z1 packets.
2c2fa1
Index: gdb-7.6.1/gdb/infrun.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/infrun.c
2c2fa1
+++ gdb-7.6.1/gdb/infrun.c
2c2fa1
@@ -3162,6 +3162,10 @@ fill_in_stop_func (struct gdbarch *gdbar
2c2fa1
       ecs->stop_func_start
2c2fa1
 	+= gdbarch_deprecated_function_start_offset (gdbarch);
2c2fa1
 
2c2fa1
+      if (gdbarch_skip_entrypoint_p (gdbarch))
2c2fa1
+	ecs->stop_func_start = gdbarch_skip_entrypoint (gdbarch,
2c2fa1
+							ecs->stop_func_start);
2c2fa1
+
2c2fa1
       ecs->stop_func_filled_in = 1;
2c2fa1
     }
2c2fa1
 }
2c2fa1
Index: gdb-7.6.1/gdb/ppc-linux-tdep.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/ppc-linux-tdep.c
2c2fa1
+++ gdb-7.6.1/gdb/ppc-linux-tdep.c
2c2fa1
@@ -44,6 +44,7 @@
2c2fa1
 #include "observer.h"
2c2fa1
 #include "auxv.h"
2c2fa1
 #include "elf/common.h"
2c2fa1
+#include "elf/ppc64.h"
2c2fa1
 #include "exceptions.h"
2c2fa1
 #include "arch-utils.h"
2c2fa1
 #include "spu-tdep.h"
2c2fa1
@@ -875,6 +876,55 @@ ppc_linux_core_read_description (struct
2c2fa1
     }
2c2fa1
 }
2c2fa1
 
2c2fa1
+
2c2fa1
+/* Implementation of `gdbarch_elf_make_msymbol_special', as defined in
2c2fa1
+   gdbarch.h.  This implementation is used for the ELFv2 ABI only.  */
2c2fa1
+
2c2fa1
+static void
2c2fa1
+ppc_elfv2_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym)
2c2fa1
+{
2c2fa1
+  elf_symbol_type *elf_sym = (elf_symbol_type *)sym;
2c2fa1
+
2c2fa1
+  /* If the symbol is marked as having a local entry point, set a target
2c2fa1
+     flag in the msymbol.  We currently only support local entry point
2c2fa1
+     offsets of 8 bytes, which is the only entry point offset ever used
2c2fa1
+     by current compilers.  If/when other offsets are ever used, we will
2c2fa1
+     have to use additional target flag bits to store them.  */
2c2fa1
+  switch (PPC64_LOCAL_ENTRY_OFFSET (elf_sym->internal_elf_sym.st_other))
2c2fa1
+    {
2c2fa1
+    default:
2c2fa1
+      break;
2c2fa1
+    case 8:
2c2fa1
+      MSYMBOL_TARGET_FLAG_1 (msym) = 1;
2c2fa1
+      break;
2c2fa1
+    }
2c2fa1
+}
2c2fa1
+
2c2fa1
+/* Implementation of `gdbarch_skip_entrypoint', as defined in
2c2fa1
+   gdbarch.h.  This implementation is used for the ELFv2 ABI only.  */
2c2fa1
+
2c2fa1
+static CORE_ADDR
2c2fa1
+ppc_elfv2_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR pc)
2c2fa1
+{
2c2fa1
+  struct minimal_symbol *fun;
2c2fa1
+  int local_entry_offset = 0;
2c2fa1
+
2c2fa1
+  fun = lookup_minimal_symbol_by_pc (pc);
2c2fa1
+  if (fun == NULL)
2c2fa1
+    return pc;
2c2fa1
+
2c2fa1
+  /* See ppc_elfv2_elf_make_msymbol_special for how local entry point
2c2fa1
+     offset values are encoded.  */
2c2fa1
+  if (MSYMBOL_TARGET_FLAG_1 (fun))
2c2fa1
+    local_entry_offset = 8;
2c2fa1
+
2c2fa1
+  if (SYMBOL_VALUE_ADDRESS (fun) <= pc
2c2fa1
+      && pc < SYMBOL_VALUE_ADDRESS (fun) + local_entry_offset)
2c2fa1
+    return SYMBOL_VALUE_ADDRESS (fun) + local_entry_offset;
2c2fa1
+
2c2fa1
+  return pc;
2c2fa1
+}
2c2fa1
+
2c2fa1
 /* Implementation of `gdbarch_stap_is_single_operand', as defined in
2c2fa1
    gdbarch.h.  */
2c2fa1
 
2c2fa1
@@ -1341,6 +1391,13 @@ ppc_linux_init_abi (struct gdbarch_info
2c2fa1
 	  set_gdbarch_elf_make_msymbol_special
2c2fa1
 	    (gdbarch, ppc64_elf_make_msymbol_special);
2c2fa1
 	}
2c2fa1
+      else
2c2fa1
+	{
2c2fa1
+	  set_gdbarch_elf_make_msymbol_special
2c2fa1
+	    (gdbarch, ppc_elfv2_elf_make_msymbol_special);
2c2fa1
+
2c2fa1
+	  set_gdbarch_skip_entrypoint (gdbarch, ppc_elfv2_skip_entrypoint);
2c2fa1
+	}
2c2fa1
 
2c2fa1
       /* Shared library handling.  */
2c2fa1
       set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
2c2fa1
Index: gdb-7.6.1/gdb/symtab.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/symtab.c
2c2fa1
+++ gdb-7.6.1/gdb/symtab.c
2c2fa1
@@ -2872,6 +2872,8 @@ skip_prologue_sal (struct symtab_and_lin
2c2fa1
 
2c2fa1
       /* Skip "first line" of function (which is actually its prologue).  */
2c2fa1
       pc += gdbarch_deprecated_function_start_offset (gdbarch);
2c2fa1
+      if (gdbarch_skip_entrypoint_p (gdbarch))
2c2fa1
+        pc = gdbarch_skip_entrypoint (gdbarch, pc);
2c2fa1
       if (skip)
2c2fa1
 	pc = gdbarch_skip_prologue (gdbarch, pc);
2c2fa1
 
2c2fa1
Index: gdb-7.6.1/gdb/testsuite/gdb.base/sigbpt.exp
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/testsuite/gdb.base/sigbpt.exp
2c2fa1
+++ gdb-7.6.1/gdb/testsuite/gdb.base/sigbpt.exp
2c2fa1
@@ -82,7 +82,7 @@ gdb_test "break keeper"
2c2fa1
 set bowler_addrs bowler
2c2fa1
 set segv_addr none
2c2fa1
 gdb_test {display/i $pc}
2c2fa1
-gdb_test "advance *bowler" "bowler.*" "advance to the bowler"
2c2fa1
+gdb_test "advance bowler" "bowler.*" "advance to the bowler"
2c2fa1
 set test "stepping to fault"
2c2fa1
 set signame "SIGSEGV"
2c2fa1
 gdb_test_multiple "stepi" "$test" {
2c2fa1
Index: gdb-7.6.1/gdb/testsuite/gdb.base/step-bt.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/testsuite/gdb.base/step-bt.c
2c2fa1
+++ gdb-7.6.1/gdb/testsuite/gdb.base/step-bt.c
2c2fa1
@@ -23,10 +23,19 @@ hello (void)
2c2fa1
   printf ("Hello world.\n");
2c2fa1
 }
2c2fa1
 
2c2fa1
+/* The test case uses "break *hello" to make sure to step at the very
2c2fa1
+   first instruction of the function.  This causes a problem running
2c2fa1
+   the test on powerpc64le-linux, since the first instruction belongs
2c2fa1
+   to the global entry point prologue, which is skipped when doing a
2c2fa1
+   local direct function call.  To make sure that first instruction is
2c2fa1
+   indeed being executed and the breakpoint hits, we make sure to call
2c2fa1
+   the routine via an indirect call.  */
2c2fa1
+void (*ptr) (void) = hello;
2c2fa1
+
2c2fa1
 int
2c2fa1
 main (void)
2c2fa1
 {
2c2fa1
-  hello ();
2c2fa1
+  ptr ();
2c2fa1
 
2c2fa1
   return 0;
2c2fa1
 }