Source: gcc-4.9
Version: 4.9.2-3
Severity: wishlist
Tags: patch
User: debian-powerpc...@breakpoint.cc
Usertags: powerpcspe

Hi,

on powerpcspe, processes with pthreads fail at pthread_exit() with SIGABRT:

$ cat thread_p.c
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

pthread_t tid[2];
int ret1;

void* doSomeThing(void *arg)
{
    unsigned long i = 0;
    printf("\n First thread processing done\n");
    ret1  = 100;
    pthread_exit(&ret1);

    return NULL;
}

int main(void)
{
    int i = 0;  
    int err;
    int *ptr[2];

    err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL);
    if (err != 0)
        printf("\ncan't create thread :[%s]", strerror(err));
    else
        printf("\n Thread created successfully\n");

    pthread_join(tid[0], (void**)&(ptr[0]));

    printf("\n return value from first thread is [%d]\n", *ptr[0]);

    return 0;
}
$ gcc -O0 -g -o thread_p -lpthread thread_p.c
$ gdb ./thread_p
GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "powerpc-linux-gnuspe".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./thread_p...done.
(gdb) run
Starting program: /home/ernie/thread_p
warning: Could not load shared library symbols for linux-vdso32.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/powerpc-linux-gnuspe/libthread_db.so.1".
b[New Thread 0x48832470 (LWP 3291)]

 First thread processing done

 Thread created successfully

Program received signal SIGABRT, Aborted.
[Switching to Thread 0x48832470 (LWP 3291)]
0x0fe5f680 in __GI_raise (sig=sig@entry=6) at 
../nptl/sysdeps/unix/sysv/linux/raise.c:56
56        return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig);
(gdb) bt
#0  0x0fe5f680 in __GI_raise (sig=sig@entry=6) at 
../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x0fe61220 in __GI_abort () at abort.c:89
#2  0x0fdffbd0 in uw_init_context_1 (context=context@entry=0x48831968, 
outer_cfa=outer_cfa@entry=0x48831d20,
    outer_ra=0xffd70e8 <_Unwind_ForcedUnwind+148>) at 
../../../src/libgcc/unwind-dw2.c:1567
#3  0x0fe00550 in _Unwind_ForcedUnwind (exc=0x488326c0, stop=0xffd3f84 
<unwind_stop>, stop_argument=0x48831db0)
    at ../../../src/libgcc/unwind.inc:201
#4  0x0ffd70e8 in _Unwind_ForcedUnwind (exc=<optimized out>, stop=<optimized 
out>, stop_argument=<optimized out>)
    at ../nptl/sysdeps/pthread/unwind-forcedunwind.c:137
#5  0x0ffd4130 in __GI___pthread_unwind (buf=<optimized out>) at unwind.c:129
#6  0x0ffcbc94 in __do_cancel () at pthreadP.h:280
#7  __pthread_exit (value=<optimized out>) at pthread_exit.c:29
#8  0x1000060c in doSomeThing (arg=0x0) at thread_p.c:15
#9  0x0ffcab74 in start_thread (arg=0x48832470) at pthread_create.c:311
#10 0x0ff1a508 in clone () at 
../sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S:102
(gdb)

After some discussion with upstream (where a similar fix is currently being
integrated / pending), I came up with the attached patch for Debian's gcc-4.9.

See also the upstream patches:

https://gcc.gnu.org/ml/gcc-patches/2014-10/msg02605.html
https://gcc.gnu.org/ml/gcc-patches/2014-09/msg02625.html

Thanks in advance,

Roland


-- System Information:
Debian Release: 7.0
  APT prefers unreleased
  APT policy: (500, 'unreleased'), (500, 'unstable')
Architecture: powerpcspe (ppc)

Kernel: Linux 3.9.0-dirty (SMP w/2 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) (ignored: LC_ALL 
set to en_GB.UTF-8)
Shell: /bin/sh linked to /bin/dash
--- a/src/gcc/config/rs6000/rs6000.c	2014-11-28 13:37:46.330028430 +0100
+++ b/src/gcc/config/rs6000/rs6000.c	2014-11-28 13:39:15.634789216 +0100
@@ -1703,7 +1703,7 @@ rs6000_hard_regno_nregs_internal (int re
      SCmode so as to pass the value correctly in a pair of
      registers.  */
   else if (TARGET_E500_DOUBLE && FLOAT_MODE_P (mode) && mode != SCmode
-	   && !DECIMAL_FLOAT_MODE_P (mode))
+	   && !DECIMAL_FLOAT_MODE_P (mode) && SPE_SIMD_REGNO_P (regno))
     reg_size = UNITS_PER_FP_WORD;
 
   else
--- a/src/gcc/defaults.h	2014-11-28 13:37:11.173728954 +0100
+++ b/src/gcc/defaults.h	2014-11-28 13:37:56.326113532 +0100
@@ -438,6 +438,11 @@
 #define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
 #endif
 
+/* The mapping from dwarf CFA reg number to internal dwarf reg numbers.  */
+#ifndef DWARF_REG_TO_UNWIND_COLUMN
+#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
+#endif
+
 /* Map register numbers held in the call frame info that gcc has
    collected using DWARF_FRAME_REGNUM to those that should be output in
    .debug_frame and .eh_frame.  */
--- a/src/gcc/dwarf2cfi.c	2014-11-28 13:37:16.549775962 +0100
+++ b/src/gcc/dwarf2cfi.c	2014-11-28 13:37:56.330113659 +0100
@@ -252,7 +252,66 @@
 		  gen_int_mode (size, mode));
 }
 
-/* Generate code to initialize the register size table.  */
+/* Datastructure used by expand_builtin_init_dwarf_reg_sizes and
+   init_one_dwarf_reg_size to communicate on what has been done by the
+   latter.  */
+
+typedef struct
+{
+  /* Whether the dwarf return column was initialized.  */
+  bool wrote_return_column;
+
+  /* For each hard register REGNO, whether init_one_dwarf_reg_size
+     was given REGNO to process already.  */
+  bool processed_regno [FIRST_PSEUDO_REGISTER];
+
+} init_one_dwarf_reg_state;
+
+/* Helper for expand_builtin_init_dwarf_reg_sizes.  Generate code to
+   initialize the dwarf register size table entry corresponding to register
+   REGNO in REGMODE.  TABLE is the table base address, SLOTMODE is the mode to
+   use for the size entry to initialize, and INIT_STATE is the communication
+   datastructure conveying what we're doing to our caller.  */
+
+static
+void init_one_dwarf_reg_size (int regno, enum machine_mode regmode,
+			      rtx table, enum machine_mode slotmode,
+			      init_one_dwarf_reg_state *init_state)
+{
+  const unsigned int dnum = DWARF_FRAME_REGNUM (regno);
+  const unsigned int rnum = DWARF2_FRAME_REG_OUT (dnum, 1);
+  const unsigned int dcol = DWARF_REG_TO_UNWIND_COLUMN (rnum);
+  
+  const HOST_WIDE_INT slotoffset = dcol * GET_MODE_SIZE (slotmode);
+  const HOST_WIDE_INT regsize = GET_MODE_SIZE (regmode);
+
+  /* No point in redoing things if we have processed this register already.
+     This could happen with register spans, e.g. when regno is first processed
+     as a piece of a span, then as a register on its own later on.  */
+
+  if (init_state->processed_regno[regno])
+    return;
+  init_state->processed_regno[regno] = true;
+
+  if (rnum >= DWARF_FRAME_REGISTERS)
+    return;
+
+  if (dnum == DWARF_FRAME_RETURN_COLUMN)
+    {
+      if (regmode == VOIDmode)
+	return;
+      init_state->wrote_return_column = true;
+    }
+
+  if (slotoffset < 0)
+    return;
+
+  emit_move_insn (adjust_address (table, slotmode, slotoffset),
+		  gen_int_mode (regsize, slotmode));
+}
+
+/* Generate code to initialize the dwarf register size table located
+   at the provided ADDRESS.  */
 
 void
 expand_builtin_init_dwarf_reg_sizes (tree address)
@@ -261,37 +320,35 @@
   enum machine_mode mode = TYPE_MODE (char_type_node);
   rtx addr = expand_normal (address);
   rtx mem = gen_rtx_MEM (BLKmode, addr);
-  bool wrote_return_column = false;
+
+  init_one_dwarf_reg_state init_state;
+
+  memset ((char *)&init_state, 0, sizeof (init_state));
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
-      unsigned int dnum = DWARF_FRAME_REGNUM (i);
-      unsigned int rnum = DWARF2_FRAME_REG_OUT (dnum, 1);
+      enum machine_mode save_mode = reg_raw_mode[i];
+      rtx span;
 
-      if (rnum < DWARF_FRAME_REGISTERS)
+      if (HARD_REGNO_CALL_PART_CLOBBERED (i, save_mode))
+	save_mode = choose_hard_reg_mode (i, 1, true);
+      
+      span = targetm.dwarf_register_span (gen_rtx_REG (save_mode, i));
+      if (!span)
+	init_one_dwarf_reg_size (i, save_mode, mem, mode, &init_state);
+      else
 	{
-	  HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (mode);
-	  enum machine_mode save_mode = reg_raw_mode[i];
-	  HOST_WIDE_INT size;
-
-	  if (HARD_REGNO_CALL_PART_CLOBBERED (i, save_mode))
-	    save_mode = choose_hard_reg_mode (i, 1, true);
-	  if (dnum == DWARF_FRAME_RETURN_COLUMN)
+	  for (int si = 0; si < XVECLEN (span, 0); si++)
 	    {
-	      if (save_mode == VOIDmode)
-		continue;
-	      wrote_return_column = true;
-	    }
-	  size = GET_MODE_SIZE (save_mode);
-	  if (offset < 0)
-	    continue;
+	      rtx reg = XVECEXP (span, 0, si);
 
-	  emit_move_insn (adjust_address (mem, mode, offset),
-			  gen_int_mode (size, mode));
+	      init_one_dwarf_reg_size
+		(REGNO (reg), GET_MODE (reg), mem, mode, &init_state);
+	    }
 	}
     }
 
-  if (!wrote_return_column)
+  if (!init_state.wrote_return_column)
     init_return_column_size (mode, mem, DWARF_FRAME_RETURN_COLUMN);
 
 #ifdef DWARF_ALT_FRAME_RETURN_COLUMN
--- a/src/libgcc/unwind-dw2.c	2014-11-28 13:37:22.765829633 +0100
+++ b/src/libgcc/unwind-dw2.c	2014-11-28 13:37:56.334113765 +0100
@@ -55,10 +55,6 @@
 #define PRE_GCC3_DWARF_FRAME_REGISTERS DWARF_FRAME_REGISTERS
 #endif
 
-#ifndef DWARF_REG_TO_UNWIND_COLUMN
-#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
-#endif
-
 /* ??? For the public function interfaces, we tend to gcc_assert that the
    column numbers are in range.  For the dwarf2 unwind info this does happen,
    although so far in a case that doesn't actually matter.

Reply via email to