[PATCH] Use dl_iterate_phdr for IA-64 fde-glibc

Jakub Jelinek jakub@redhat.com
Wed Aug 8 07:01:00 GMT 2001


Hi!

This is updated version of the IA-64 unwinder fix.
Unlike the previous one, it will allow you to compile gcc with pre-2.2.4
glibc on IA-64, though I would not recommend it.
Tested both with glibc 2.2.3 and 2.2.4pre2 (the latter has already
dl_iterate_phdr).
Ok to commit to branch and head?

2001-08-08  Jakub Jelinek  <jakub@redhat.com>

	* config/ia64/fde-glibc.c (find_fde_for_dso): Remove.
	(_Unwind_IteratePhdrCallback): New.
	(_Unwind_FindTableEntry): Two different implementations,
	one for glibc 2.2.4+, another for older glibcs.
	* config/ia64/crtbegin.asm: Only add __ia64_app_header
	if glibc does not have dl_iterate_phdr.
	* config/ia64/t-ia64: Pass -I$(objdir) for crtbegin.asm
	assembly.
	* configure.in: Check for dl_iterate_phdr.
	* configure: Rebuilt.
	* config.in (HAVE_DL_ITERATE_PHDR): Add.

--- gcc/config/ia64/fde-glibc.c.jj	Fri Jun  8 09:41:20 2001
+++ gcc/config/ia64/fde-glibc.c	Wed Aug  8 05:38:42 2001
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@cygnus.com>.
 
    This file is part of GNU CC.
@@ -28,57 +28,71 @@
 /* Locate the FDE entry for a given address, using glibc ld.so routines
    to avoid register/deregister calls at DSO load/unload.  */
 
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include "config.h"
+#include <stddef.h>
 #include <stdlib.h>
 #include <link.h>
 #include <bits/libc-lock.h>
 #include "unwind-ia64.h"
 
+#ifndef HAVE_DL_ITERATE_PHDR
 
-/* Initialized by crtbegin from the main application.  */
-extern Elf64_Ehdr *__ia64_app_header;
+#define dl_phdr_info dl_phdr_info_
 
-/* ??? A redeclaration of the lock in ld.so.  Perhaps this should
-   appear in <link.h> in a new glibc version.  */
-__libc_lock_define (extern, _dl_load_lock)
+struct dl_phdr_info
+{
+  Elf64_Addr dlpi_addr;
+  const char *dlpi_name;
+  const Elf64_Phdr *dlpi_phdr;
+  Elf64_Half dlpi_phnum;
+};
 
-/* This always exists, even in a static application.  */
-extern struct link_map *_dl_loaded;
+#endif
 
-static struct unw_table_entry *
-find_fde_for_dso (Elf64_Addr pc, Elf64_Ehdr *ehdr,
-		  unsigned long *pseg_base, unsigned long *pgp)
+struct unw_ia64_callback_data
 {
-  Elf64_Phdr *phdr, *p_unwind, *p_dynamic;
+  Elf64_Addr pc;
+  unsigned long *segment_base;
+  unsigned long *gp;
+  struct unw_table_entry *ret;
+};
+
+static int
+_Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
+{
+  struct unw_ia64_callback_data *data = (struct unw_ia64_callback_data *) ptr;
+  const Elf64_Phdr *phdr, *p_unwind, *p_dynamic;
   long n, match;
   Elf64_Addr load_base, seg_base;
   struct unw_table_entry *f_base, *f;
   size_t lo, hi;
 
-  /* Verify that we are looking at an ELF header.  */
-  if (ehdr->e_ident[0] != 0x7f
-      || ehdr->e_ident[1] != 'E'
-      || ehdr->e_ident[2] != 'L'
-      || ehdr->e_ident[3] != 'F'
-      || ehdr->e_ident[EI_CLASS] != ELFCLASS64
-      || ehdr->e_ident[EI_DATA] != ELFDATA2LSB
-      || ehdr->e_machine != EM_IA_64)
-    abort ();
+  /* Make sure struct dl_phdr_info is at least as big as we need.  */
+  if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
+	     + sizeof (info->dlpi_phnum))
+    return -1;
 
   match = 0;
-  phdr = (Elf64_Phdr *)((char *)ehdr + ehdr->e_phoff);
-  load_base = (ehdr->e_type == ET_DYN ? (Elf64_Addr)ehdr : 0);
+  phdr = info->dlpi_phdr;
+  load_base = info->dlpi_addr;
   p_unwind = NULL;
   p_dynamic = NULL;
+  seg_base = ~(Elf64_Addr) 0;
 
   /* See if PC falls into one of the loaded segments.  Find the unwind
      segment at the same time.  */
-  for (n = ehdr->e_phnum; --n >= 0; phdr++)
+  for (n = info->dlpi_phnum; --n >= 0; phdr++)
     {
       if (phdr->p_type == PT_LOAD)
 	{
 	  Elf64_Addr vaddr = phdr->p_vaddr + load_base;
-	  if (pc >= vaddr && pc < vaddr + phdr->p_memsz)
+	  if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
 	    match = 1;
+	  if (vaddr < seg_base)
+	    seg_base = vaddr;
 	}
       else if (phdr->p_type == PT_IA_64_UNWIND)
 	p_unwind = phdr;
@@ -86,12 +100,11 @@ find_fde_for_dso (Elf64_Addr pc, Elf64_E
 	p_dynamic = phdr;
     }
   if (!match || !p_unwind)
-    return NULL;
+    return 0;
 
   /* Search for the FDE within the unwind segment.  */
 
   f_base = (struct unw_table_entry *) (p_unwind->p_vaddr + load_base);
-  seg_base = (Elf64_Addr) ehdr;
   lo = 0;
   hi = p_unwind->p_memsz / sizeof (struct unw_table_entry);
 
@@ -100,18 +113,19 @@ find_fde_for_dso (Elf64_Addr pc, Elf64_E
       size_t mid = (lo + hi) / 2;
 
       f = f_base + mid;
-      if (pc < f->start_offset + seg_base)
+      if (data->pc < f->start_offset + seg_base)
 	hi = mid;
-      else if (pc >= f->end_offset + seg_base)
+      else if (data->pc >= f->end_offset + seg_base)
 	lo = mid + 1;
       else
         goto found;
     }
-  return NULL;
+  return 0;
 
  found:
-  *pseg_base = seg_base;
-  *pgp = 0;
+  *data->segment_base = seg_base;
+  *data->gp = 0;
+  data->ret = f;
 
   if (p_dynamic)
     {
@@ -121,8 +135,8 @@ find_fde_for_dso (Elf64_Addr pc, Elf64_E
       for (; dyn->d_tag != DT_NULL ; dyn++)
 	if (dyn->d_tag == DT_PLTGOT)
 	  {
-	    /* ??? Glibc seems to have relocated this already.  */
-	    *pgp = dyn->d_un.d_ptr;
+	    /* On IA-64, _DYNAMIC is writable and GLIBC has relocated it.  */
+	    *data->gp = dyn->d_un.d_ptr;
 	    break;
 	  }
     }
@@ -131,12 +145,14 @@ find_fde_for_dso (Elf64_Addr pc, Elf64_E
       /* Otherwise this is a static executable with no _DYNAMIC.
 	 The gp is constant program-wide.  */
       register unsigned long gp __asm__("gp");
-      *pgp = gp;
+      *data->gp = gp;
     }
 
-  return f;
+  return 1;
 }
 
+#ifdef HAVE_DL_ITERATE_PHDR
+
 /* Return a pointer to the unwind table entry for the function
    containing PC.  */
 
@@ -144,34 +160,99 @@ struct unw_table_entry *
 _Unwind_FindTableEntry (void *pc, unsigned long *segment_base,
                         unsigned long *gp)
 {
-  struct unw_table_entry *ret;
+  struct unw_ia64_callback_data data;
+
+  data.pc = (Elf64_Addr) pc;
+  data.segment_base = segment_base;
+  data.gp = gp;
+  data.ret = NULL;
+
+  if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0)
+    return NULL;
+
+  return data.ret;
+}
+
+#else /* !HAVE_DL_ITERATE_PHDR */
+
+/* ??? A redeclaration of the lock in ld.so.  Perhaps this should
+   appear in <link.h> in a new glibc version.  */
+__libc_lock_define (extern, _dl_load_lock)
+   
+/* This always exists, even in a static application.  */
+extern struct link_map *_dl_loaded;
+
+/* Return a pointer to the unwind table entry for the function
+   containing PC.  */
+
+struct unw_table_entry *
+_Unwind_FindTableEntry (void *pc, unsigned long *segment_base,
+                        unsigned long *gp)
+{
+  struct unw_ia64_callback_data data;
+  Elf64_Ehdr *ehdr;
+  struct dl_phdr_info info;
   struct link_map *map;
+  int ret;
+  extern Elf64_Ehdr *__ia64_app_header __attribute__ ((weak));
+        
+  data.pc = (Elf64_Addr) pc;
+  data.segment_base = segment_base;
+  data.gp = gp;
+  data.ret = NULL;
 
-  /* Check the main application first, hoping that most of the user's
-     code is there instead of in some library.  */
-  ret = find_fde_for_dso ((Elf64_Addr)pc, __ia64_app_header,
-			  segment_base, gp);
-  if (ret)
-    return ret;
-
-  /* Glibc is probably unique in that we can (with certain restrictions)
-     dynamicly load libraries into staticly linked applications.  Thus
-     we _always_ check _dl_loaded.  */
+  if (&__ia64_app_header)
+    {
+      ehdr = __ia64_app_header;
 
-  __libc_lock_lock (_dl_load_lock);
+      if (ehdr->e_ident[0] != 0x7f
+	  || ehdr->e_ident[1] != 'E'
+	  || ehdr->e_ident[2] != 'L'
+	  || ehdr->e_ident[3] != 'F'
+	  || ehdr->e_ident[EI_CLASS] != ELFCLASS64
+	  || ehdr->e_ident[EI_DATA] != ELFDATA2LSB
+	  || ehdr->e_machine != EM_IA_64)
+	abort ();
+
+      info.dlpi_addr = 0;
+      info.dlpi_name = NULL;
+      info.dlpi_phdr = (ElfW(Phdr) *) ((char *) ehdr + ehdr->e_phoff);
+      info.dlpi_phnum = ehdr->e_phnum;
+
+      ret = _Unwind_IteratePhdrCallback (&info, sizeof (info), &data);
+      if (ret)
+	return data.ret;
+    }
 
+  __libc_lock_lock (_dl_load_lock);
+  
   for (map = _dl_loaded; map ; map = map->l_next)
     {
-      /* Skip the main application's entry.  */
-      if (map->l_name[0] == 0)
+      if (map->l_addr == 0)
 	continue;
-      ret = find_fde_for_dso ((Elf64_Addr)pc, (Elf64_Ehdr *)map->l_addr,
-			      segment_base, gp);
+      info.dlpi_addr = map->l_addr;
+      info.dlpi_name = map->l_name;
+      /* This is very wrong, Elf64_Ehdr may be located completely
+	 elsewhere if first PT_LOAD segment's p_vaddr is non-zero.  */
+      ehdr = (Elf64_Ehdr *) map->l_addr;
+      if (ehdr->e_ident[0] != 0x7f
+	  || ehdr->e_ident[1] != 'E'
+	  || ehdr->e_ident[2] != 'L'
+	  || ehdr->e_ident[3] != 'F'
+	  || ehdr->e_ident[EI_CLASS] != ELFCLASS64
+	  || ehdr->e_ident[EI_DATA] != ELFDATA2LSB
+	  || ehdr->e_machine != EM_IA_64)
+	abort ();
+      info.dlpi_phdr = (Elf64_Phdr *) ((char *)ehdr + ehdr->e_phoff);
+      info.dlpi_phnum = ehdr->e_phnum;
+      ret = _Unwind_IteratePhdrCallback (&info, sizeof (info), &data);
       if (ret)
-	break;
+        break;
     }
 
   __libc_lock_unlock (_dl_load_lock);
-
-  return ret;
+    
+  return data.ret;
 }
+
+#endif /* !HAVE_DL_ITERATE_PHDR */
--- gcc/config/ia64/crtbegin.asm.jj	Tue Feb 27 08:19:39 2001
+++ gcc/config/ia64/crtbegin.asm	Wed Aug  8 05:31:08 2001
@@ -16,6 +16,8 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include "auto-host.h"
+
 .section .ctors,"aw","progbits"
 	.align	8
 __CTOR_LIST__:
@@ -32,7 +34,7 @@ __DTOR_LIST__:
 dtor_ptr:
 	data8	__DTOR_LIST__# + 8
 
-#ifndef SHARED
+#if !defined(SHARED) && !defined(HAVE_DL_ITERATE_PHDR)
 	.type __ia64_app_header#,@object
 	.size __ia64_app_header#,8
 	.global __ia64_app_header
@@ -85,7 +87,7 @@ __dso_handle:
 	  ;;
 	}
 
-#ifndef SHARED
+#if !defined(SHARED) && !defined(HAVE_DL_ITERATE_PHDR)
 /*
  * Fragment of the ELF _init routine that sets up __ia64_app_header
  */
--- gcc/config/ia64/t-ia64.jj	Fri Jun  8 09:41:30 2001
+++ gcc/config/ia64/t-ia64	Wed Aug  8 05:45:32 2001
@@ -32,11 +32,11 @@ T = disable
 
 # Assemble startup files.
 crtbegin.o: $(srcdir)/config/ia64/crtbegin.asm $(GCC_PASSES)
-	$(GCC_FOR_TARGET) -c -o crtbegin.o -x assembler-with-cpp $(srcdir)/config/ia64/crtbegin.asm
+	$(GCC_FOR_TARGET) -I$(objdir) -c -o crtbegin.o -x assembler-with-cpp $(srcdir)/config/ia64/crtbegin.asm
 crtend.o: $(srcdir)/config/ia64/crtend.asm $(GCC_PASSES)
 	$(GCC_FOR_TARGET) -c -o crtend.o -x assembler-with-cpp $(srcdir)/config/ia64/crtend.asm
 crtbeginS.o: $(srcdir)/config/ia64/crtbegin.asm $(GCC_PASSES)
-	$(GCC_FOR_TARGET) -DSHARED -c -o crtbeginS.o -x assembler-with-cpp $(srcdir)/config/ia64/crtbegin.asm
+	$(GCC_FOR_TARGET) -I$(objdir) -DSHARED -c -o crtbeginS.o -x assembler-with-cpp $(srcdir)/config/ia64/crtbegin.asm
 crtendS.o: $(srcdir)/config/ia64/crtend.asm $(GCC_PASSES)
 	$(GCC_FOR_TARGET) -DSHARED -c -o crtendS.o -x assembler-with-cpp $(srcdir)/config/ia64/crtend.asm
 
--- gcc/configure.in.jj	Mon Aug  6 15:43:12 2001
+++ gcc/configure.in	Mon Aug  6 15:46:37 2001
@@ -545,7 +545,7 @@ fi
 AC_CHECK_FUNCS(strtoul bsearch putenv popen bcopy \
 	strchr strrchr kill getrlimit setrlimit atoll atoq \
 	sysconf isascii gettimeofday strsignal putc_unlocked fputc_unlocked \
-	fputs_unlocked getrusage nl_langinfo lstat)
+	fputs_unlocked getrusage nl_langinfo lstat dl_iterate_phdr)
 
 AC_CHECK_TYPE(ssize_t, int)
 
--- gcc/configure.jj	Mon Aug  6 15:43:12 2001
+++ gcc/configure	Tue Aug  7 16:28:18 2001
@@ -2645,7 +2645,7 @@ fi
 for ac_func in strtoul bsearch putenv popen bcopy \
 	strchr strrchr kill getrlimit setrlimit atoll atoq \
 	sysconf isascii gettimeofday strsignal putc_unlocked fputc_unlocked \
-	fputs_unlocked getrusage nl_langinfo lstat
+	fputs_unlocked getrusage nl_langinfo lstat dl_iterate_phdr
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
 echo "configure:2652: checking for $ac_func" >&5
--- gcc/config.in.jj	Mon Aug  6 15:43:12 2001
+++ gcc/config.in	Mon Aug  6 15:46:37 2001
@@ -126,6 +126,9 @@
 /* Define if you have the dcgettext function.  */
 #undef HAVE_DCGETTEXT
 
+/* Define if you have the dl_iterate_phdr function.  */
+#undef HAVE_DL_ITERATE_PHDR
+
 /* Define if you have the fputc_unlocked function.  */
 #undef HAVE_FPUTC_UNLOCKED
 

	Jakub



More information about the Gcc-patches mailing list