codeowners update
[mono.git] / libgc / dyn_load.c
index 7111a874a7bb5d330952050c1b3d4cae4ecfdd61..5db3503aacbaf3b68ce53ddc427cb1069cccce04 100644 (file)
@@ -26,7 +26,7 @@
  * None of this is safe with dlclose and incremental collection.
  * But then not much of anything is safe in the presence of dlclose.
  */
-#if defined(__linux__) && !defined(_GNU_SOURCE)
+#if (defined(__linux__) || defined(__GLIBC__) || defined(__native_client__)) && !defined(_GNU_SOURCE)
     /* Can't test LINUX, since this must be define before other includes */
 #   define _GNU_SOURCE
 #endif
 #if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
     !defined(MSWIN32) && !defined(MSWINCE) && \
     !(defined(ALPHA) && defined(OSF1)) && \
-    !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
+    !defined(HPUX) && !((defined(LINUX) || defined(NACL)) && defined(__ELF__)) && \
     !defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
     !(defined(FREEBSD) && defined(__ELF__)) && \
+    !(defined(OPENBSD) && (defined(__ELF__) || defined(M68K))) && \
     !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
     !defined(DARWIN)
  --> We only know how to find data segments of dynamic libraries for the
 
 #include <stdio.h>
 #ifdef SUNOS5DL
+/* Avoid  #error "large files are not supported by libelf" errors */
+#if defined(_ILP32) && (_FILE_OFFSET_BITS != 32)
+#undef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 32
+#endif
 #   include <sys/elf.h>
 #   include <dlfcn.h>
 #   include <link.h>
 #   define ELFSIZE ARCH_ELFSIZE
 #endif
 
-#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
+#if (defined(LINUX) || defined(NACL)) && defined(__ELF__) || defined(SCO_ELF) || \
     (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
+    (defined(OPENBSD) && defined(__ELF__)) || \
     (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
 #   include <stddef.h>
+# if !defined(OPENBSD)
 #   include <elf.h>
+# endif
 #   include <link.h>
 #endif
 
 /* Newer versions of GNU/Linux define this macro.  We
  * define it similarly for any ELF systems that don't.  */
 #  ifndef ElfW
-#    ifdef FREEBSD
+#    if defined(FREEBSD)
 #      if __ELF_WORD_SIZE == 32
 #        define ElfW(type) Elf32_##type
 #      else
 #          define ElfW(type) Elf32_##type
 #        else
 #          define ElfW(type) Elf64_##type
-#        endif
+#       endif
 #      endif
 #    endif
 #  endif 
@@ -245,7 +254,10 @@ void GC_register_dynamic_libraries()
         char * start;
         register int i;
         
-       e = (ElfW(Ehdr) *) lm->l_addr;
+        e = (ElfW(Ehdr) *) lm->l_addr;
+        if (e == NULL)
+          continue;
+
         p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
         offset = ((unsigned long)(lm->l_addr));
         for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
@@ -285,8 +297,9 @@ void GC_register_dynamic_libraries()
 # endif /* !USE_PROC ... */
 # endif /* SUNOS */
 
-#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
+#if (defined(LINUX) || defined(NACL)) && defined(__ELF__) || defined(SCO_ELF) || \
     (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
+    (defined(OPENBSD) && defined(__ELF__)) || \
     (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
 
 
@@ -381,7 +394,7 @@ GC_bool GC_register_main_static_data()
 /* For glibc 2.2.4+.  Unfortunately, it doesn't work for older */
 /* versions.  Thanks to Jakub Jelinek for most of the code.    */
 
-# if defined(LINUX) /* Are others OK here, too? */ \
+# if (defined(LINUX) || defined (__GLIBC__) || defined(NACL)) /* Are others OK here, too? */ \
      && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
          || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG))) 
 
@@ -465,8 +478,10 @@ GC_bool GC_register_main_static_data()
 /* This doesn't necessarily work in all cases, e.g. with preloaded
  * dynamic libraries.                                          */
 
-#if defined(NETBSD)
+#if defined(NETBSD) || defined(OPENBSD)
+# if !defined(OPENBSD)
 #  include <sys/exec_elf.h>
+# endif
 /* for compatibility with 1.4.x */
 #  ifndef DT_DEBUG
 #  define DT_DEBUG     21
@@ -493,7 +508,6 @@ static struct link_map *
 GC_FirstDLOpenedLinkMap()
 {
     ElfW(Dyn) *dp;
-    struct r_debug *r;
     static struct link_map *cachedResult = 0;
 
     if( _DYNAMIC == 0) {
@@ -502,6 +516,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;
@@ -534,7 +554,10 @@ void GC_register_dynamic_libraries()
         char * start;
         register int i;
         
-       e = (ElfW(Ehdr) *) lm->l_addr;
+        e = (ElfW(Ehdr) *) lm->l_addr;
+        if (e == NULL)
+          continue;
+
         p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
         offset = ((unsigned long)(lm->l_addr));
         for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
@@ -626,7 +649,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   */
@@ -748,6 +772,10 @@ 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;
@@ -762,25 +790,27 @@ void GC_register_dynamic_libraries()
  
   /* Should [start, start+len) be treated as a frame buffer    */
   /* and ignored?                                              */
-  /* Unfortunately, we currently have no real way to tell      */
-  /* automatically, and rely largely on user input.            */
-  /* FIXME: If we had more data on this phenomenon (e.g.       */
-  /* is start aligned to a MB multiple?) we should be able to  */
-  /* do better.                                                        */
+  /* 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 chicken to do that in this        */
+  /* version.                                                  */
   /* Based on a very limited sample, it appears that:          */
-  /*   - Frame buffer mappings appear as mappings of length    */
-  /*     2**n MB - 192K.  (We guess the 192K can vary a bit.)  */
-  /*   - Have a stating address at best 64K aligned.           */
-  /* I'd love more information about the mapping, since I      */
-  /* can't reproduce the problem.                              */
-  static GC_bool is_frame_buffer(ptr_t start, size_t len)
+  /*   - 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) return FALSE;
+    if (GC_disallow_ignore_fb || tp != MEM_MAPPED) return FALSE;
     if (!initialized) {
       char * ignore_fb_string =  GETENV("GC_IGNORE_FB");
 
@@ -869,7 +899,11 @@ void GC_register_dynamic_libraries()
                && (protect == PAGE_EXECUTE_READWRITE
                    || protect == PAGE_READWRITE)
                && !GC_is_heap_base(buf.AllocationBase)
-               && !is_frame_buffer(p, buf.RegionSize)) {  
+               /* 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. */
+               && buf.Type == MEM_IMAGE) {  
 #              ifdef DEBUG_VIRTUALQUERY
                  GC_dump_meminfo(&buf);
 #              endif
@@ -1125,21 +1159,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 */
@@ -1152,15 +1187,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() {