* src/vm/jit/powerpc/darwin/md-abi.h (REG_ITMP12_PACKED): Added.
[cacao.git] / src / boehm-gc / dyn_load.c
index 9a530a23bf5b2105406e052e4430c190f58bf214..6d4efabdf3d2ce7aba54fdee6086dedae5e91c4a 100644 (file)
@@ -26,6 +26,9 @@
  * None of this is safe with dlclose and incremental collection.
  * But then not much of anything is safe in the presence of dlclose.
  */
+
+#include "config.h"
+
 #if defined(__linux__) && !defined(_GNU_SOURCE)
     /* Can't test LINUX, since this must be define before other includes */
 #   define _GNU_SOURCE
 #   define l_name      lm_name
 #endif
 
+#if defined(NETBSD)
+#   include <machine/elf_machdep.h>
+#   define ELFSIZE ARCH_ELFSIZE
+#endif
+
 #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
     (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
     (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
 /* Newer versions of GNU/Linux define this macro.  We
  * define it similarly for any ELF systems that don't.  */
 #  ifndef ElfW
-#    if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
-#      define ElfW(type) Elf32_##type
+#    if defined(FREEBSD)
+#      if __ELF_WORD_SIZE == 32
+#        define ElfW(type) Elf32_##type
+#      else
+#        define ElfW(type) Elf64_##type
+#      endif
 #    else
-#      define ElfW(type) Elf64_##type
+#      ifdef NETBSD
+#        if ELFSIZE == 32
+#          define ElfW(type) Elf32_##type
+#        else
+#          define ElfW(type) Elf64_##type
+#        endif
+#      else
+#        if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
+#          define ElfW(type) Elf32_##type
+#        else
+#          define ElfW(type) Elf64_##type
+#       endif
+#      endif
 #    endif
 #  endif
 
@@ -446,6 +470,16 @@ GC_bool GC_register_main_static_data()
 
 #if defined(NETBSD)
 #  include <sys/exec_elf.h>
+/* for compatibility with 1.4.x */
+#  ifndef DT_DEBUG
+#  define DT_DEBUG     21
+#  endif
+#  ifndef PT_LOAD
+#  define PT_LOAD      1
+#  endif
+#  ifndef PF_W
+#  define PF_W         2
+#  endif
 #else
 #  include <elf.h>
 #endif
@@ -462,7 +496,6 @@ static struct link_map *
 GC_FirstDLOpenedLinkMap()
 {
     ElfW(Dyn) *dp;
-    struct r_debug *r;
     static struct link_map *cachedResult = 0;
 
     if( _DYNAMIC == 0) {
@@ -471,6 +504,12 @@ GC_FirstDLOpenedLinkMap()
     if( cachedResult == 0 ) {
         int tag;
         for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
+           /* FIXME: The DT_DEBUG header is not mandated by the        */
+           /* ELF spec.  This code appears to be dependent on          */
+           /* idiosynchracies of older GNU tool chains.  If this code  */
+           /* fails for you, the real problem is probably that it is   */
+           /* being used at all.  You should be getting the            */
+           /* dl_iterate_phdr version.                                 */
             if( tag == DT_DEBUG ) {
                 struct link_map *lm
                         = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
@@ -595,7 +634,8 @@ void GC_register_dynamic_libraries()
     }
     for (i = 0; i < needed_sz; i++) {
         flags = addr_map[i].pr_mflags;
-        if ((flags & (MA_BREAK | MA_STACK | MA_PHYS)) != 0) goto irrelevant;
+        if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
+                     | MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
         if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
             goto irrelevant;
           /* The latter test is empirically useless in very old Irix   */
@@ -717,6 +757,99 @@ void GC_register_dynamic_libraries()
   
 # define HAVE_REGISTER_MAIN_STATIC_DATA
 
+  /* The frame buffer testing code is dead in this version.    */
+  /* We leave it here temporarily in case the switch to just   */
+  /* testing for MEM_IMAGE sections causes un expected                 */
+  /* problems.                                                 */
+  GC_bool GC_warn_fb = TRUE;   /* Warn about traced likely     */
+                               /* graphics memory.             */
+  GC_bool GC_disallow_ignore_fb = FALSE;
+  int GC_ignore_fb_mb; /* Ignore mappings bigger than the      */
+                       /* specified number of MB.              */
+  GC_bool GC_ignore_fb = FALSE; /* Enable frame buffer         */
+                               /* checking.            */
+  
+  /* Issue warning if tracing apparent framebuffer.            */
+  /* This limits us to one warning, and it's a back door to    */
+  /* disable that.                                             */
+  /* Should [start, start+len) be treated as a frame buffer    */
+  /* and ignored?                                              */
+  /* Unfortunately, we currently are not quite sure how to tell        */
+  /* this automatically, and rely largely on user input.       */
+  /* We expect that any mapping with type MEM_MAPPED (which    */
+  /* apparently excludes library data sections) can be safely  */
+  /* ignored.  But we're too completely remove this code in    */
+  /* this version.                                             */
+  /* Based on a very limited sample, it appears that:          */
+  /*   - Frame buffer mappings appear as mappings of large     */
+  /*     length, usually a bit less than a power of two.       */
+  /*   - The definition of "a bit less" in the above cannot    */
+  /*     be made more precise.                                 */
+  /*   - Have a starting address at best 64K aligned.          */
+  /*   - Have type == MEM_MAPPED.                              */
+  static GC_bool is_frame_buffer(ptr_t start, size_t len, DWORD tp)
+  {
+    static GC_bool initialized = FALSE;
+#   define MB (1024*1024)
+#   define DEFAULT_FB_MB 15
+#   define MIN_FB_MB 3
+
+    if (GC_disallow_ignore_fb || tp != MEM_MAPPED) return FALSE;
+    if (!initialized) {
+      char * ignore_fb_string =  GETENV("GC_IGNORE_FB");
+
+      if (0 != ignore_fb_string) {
+       while (*ignore_fb_string == ' ' || *ignore_fb_string == '\t')
+         ++ignore_fb_string;
+       if (*ignore_fb_string == '\0') {
+         GC_ignore_fb_mb = DEFAULT_FB_MB;
+       } else {
+         GC_ignore_fb_mb = atoi(ignore_fb_string);
+         if (GC_ignore_fb_mb < MIN_FB_MB) {
+           WARN("Bad GC_IGNORE_FB value.  Using %ld\n", DEFAULT_FB_MB);
+           GC_ignore_fb_mb = DEFAULT_FB_MB;
+         }
+       }
+       GC_ignore_fb = TRUE;
+      } else {
+       GC_ignore_fb_mb = DEFAULT_FB_MB;  /* For warning */
+      }
+      initialized = TRUE;
+    }
+    if (len >= ((size_t)GC_ignore_fb_mb << 20)) {
+      if (GC_ignore_fb) {
+       return TRUE;
+      } else {
+       if (GC_warn_fb) {
+         WARN("Possible frame buffer mapping at 0x%lx: \n"
+              "\tConsider setting GC_IGNORE_FB to improve performance.\n",
+              start);
+         GC_warn_fb = FALSE;
+       }
+       return FALSE;
+      }
+    } else {
+      return FALSE;
+    }
+  }
+
+# ifdef DEBUG_VIRTUALQUERY
+  void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
+  {
+    GC_printf4("BaseAddress = %lx, AllocationBase = %lx, RegionSize = %lx(%lu)\n",
+              buf -> BaseAddress, buf -> AllocationBase, buf -> RegionSize,
+              buf -> RegionSize);
+    GC_printf4("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
+              "Type = %lx\n",
+              buf -> AllocationProtect, buf -> State, buf -> Protect,
+              buf -> Type);
+  }
+# endif /* DEBUG_VIRTUALQUERY */
+
+  extern GC_bool GC_wnt;  /* Is Windows NT derivative.         */
+                         /* Defined and set in os_dep.c.       */
+
   void GC_register_dynamic_libraries()
   {
     MEMORY_BASIC_INFORMATION buf;
@@ -753,7 +886,20 @@ void GC_register_dynamic_libraries()
            if (buf.State == MEM_COMMIT
                && (protect == PAGE_EXECUTE_READWRITE
                    || protect == PAGE_READWRITE)
-               && !GC_is_heap_base(buf.AllocationBase)) {
+               && !GC_is_heap_base(buf.AllocationBase)
+               /* This used to check for
+                * !is_frame_buffer(p, buf.RegionSize, buf.Type)
+                * instead of just checking for MEM_IMAGE.
+                * If something breaks, change it back. */
+               /* There is some evidence that we cannot always
+                * ignore MEM_PRIVATE sections under Windows ME
+                * and predecessors.  Hence we now also check for
+                * that case.   */
+               && (buf.Type == MEM_IMAGE ||
+                   !GC_wnt && buf.Type == MEM_PRIVATE)) {  
+#              ifdef DEBUG_VIRTUALQUERY
+                 GC_dump_meminfo(&buf);
+#              endif
                if ((char *)p != limit) {
                    GC_cond_add_roots(base, limit);
                    base = p;
@@ -971,7 +1117,14 @@ void GC_register_dynamic_libraries()
 
 #ifdef DARWIN
 
-#include <mach-o/dyld.h>
+/* __private_extern__ hack required for pre-3.4 gcc versions.  */
+#ifndef __private_extern__
+# define __private_extern__ extern
+# include <mach-o/dyld.h>
+# undef __private_extern__
+#else
+# include <mach-o/dyld.h>
+#endif
 #include <mach-o/getsect.h>
 
 /*#define DARWIN_DEBUG*/
@@ -999,21 +1152,22 @@ static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) {
 static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) {
     unsigned long start,end,i;
     const struct section *sec;
+    if (GC_no_dls) return;
     for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
         sec = getsectbynamefromheader(
             hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
-            if(sec == NULL || sec->size == 0) continue;
-            start = slide + sec->addr;
-            end = start + sec->size;
-#              ifdef DARWIN_DEBUG
-                GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
+        if(sec == NULL || sec->size == 0) continue;
+        start = slide + sec->addr;
+        end = start + sec->size;
+#      ifdef DARWIN_DEBUG
+            GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
                 start,end,sec->size,GC_dyld_name_for_hdr(hdr));
-#                      endif
+#       endif
         GC_add_roots((char*)start,(char*)end);
-        }
-#      ifdef DARWIN_DEBUG
-    GC_print_static_roots();
-#      endif
+    }
+#   ifdef DARWIN_DEBUG
+        GC_print_static_roots();
+#   endif
 }
 
 /* This should never be called by a thread holding the lock */
@@ -1026,15 +1180,15 @@ static void GC_dyld_image_remove(struct mach_header* hdr, unsigned long slide) {
         if(sec == NULL || sec->size == 0) continue;
         start = slide + sec->addr;
         end = start + sec->size;
-#              ifdef DARWIN_DEBUG
+#      ifdef DARWIN_DEBUG
             GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
                 start,end,sec->size,GC_dyld_name_for_hdr(hdr));
 #              endif
         GC_remove_roots((char*)start,(char*)end);
     }
-#      ifdef DARWIN_DEBUG
-    GC_print_static_roots();
-#      endif
+#   ifdef DARWIN_DEBUG
+        GC_print_static_roots();
+#   endif
 }
 
 void GC_register_dynamic_libraries() {
@@ -1049,32 +1203,43 @@ void GC_register_dynamic_libraries() {
    allocation lock held. */
    
 void GC_init_dyld() {
-    static GC_bool initialized = FALSE;
-    
-    if(initialized) return;
-    
-#   ifdef DARWIN_DEBUG
-        GC_printf0("Forcing full bind of GC code...\n");
-#   endif
-    if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
-        GC_abort("_dyld_bind_fully_image_containing_addres failed");
-            
+  static GC_bool initialized = FALSE;
+  char *bind_fully_env = NULL;
+  
+  if(initialized) return;
+  
 #   ifdef DARWIN_DEBUG
-        GC_printf0("Registering dyld callbacks...\n");
+  GC_printf0("Registering dyld callbacks...\n");
 #   endif
-
-    /* Apple's Documentation:
-    When you call _dyld_register_func_for_add_image, the dynamic linker runtime
-    calls the specified callback (func) once for each of the images that is
-    currently loaded into the program. When a new image is added to the program,
-    your callback is called again with the mach_header for the new image, and the      virtual memory slide amount of the new image. 
-        
-    This WILL properly register existing and all future libraries
-    */
-        
+  
+  /* Apple's Documentation:
+     When you call _dyld_register_func_for_add_image, the dynamic linker runtime
+     calls the specified callback (func) once for each of the images that is
+     currently loaded into the program. When a new image is added to the program,
+     your callback is called again with the mach_header for the new image, and the     
+     virtual memory slide amount of the new image. 
+     
+     This WILL properly register already linked libraries and libraries 
+     linked in the future
+  */
+  
     _dyld_register_func_for_add_image(GC_dyld_image_add);
     _dyld_register_func_for_remove_image(GC_dyld_image_remove);
+
+    /* Set this early to avoid reentrancy issues. */
     initialized = TRUE;
+
+    bind_fully_env = getenv("DYLD_BIND_AT_LAUNCH");
+    
+    if (bind_fully_env == NULL) {
+#   ifdef DARWIN_DEBUG
+      GC_printf0("Forcing full bind of GC code...\n");
+#   endif
+      
+      if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
+        GC_abort("_dyld_bind_fully_image_containing_address failed");
+    }
+
 }
 
 #define HAVE_REGISTER_MAIN_STATIC_DATA