summaryrefslogtreecommitdiff
path: root/boehm-gc/dyn_load.c
diff options
context:
space:
mode:
Diffstat (limited to 'boehm-gc/dyn_load.c')
-rw-r--r--boehm-gc/dyn_load.c278
1 files changed, 163 insertions, 115 deletions
diff --git a/boehm-gc/dyn_load.c b/boehm-gc/dyn_load.c
index 71ad5fb1d78..5ae0e0dcccd 100644
--- a/boehm-gc/dyn_load.c
+++ b/boehm-gc/dyn_load.c
@@ -55,9 +55,10 @@
!defined(MSWIN32) && !defined(MSWINCE) && \
!(defined(ALPHA) && defined(OSF1)) && \
!defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
- !defined(RS6000) && !defined(SCO_ELF) && \
+ !defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
!(defined(FREEBSD) && defined(__ELF__)) && \
- !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD)
+ !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
+ !defined(DARWIN)
--> We only know how to find data segments of dynamic libraries for the
--> above. Additional SVR4 variants might not be too
--> hard to add.
@@ -80,7 +81,7 @@
#endif
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
- (defined(FREEBSD) && defined(__ELF__)) || \
+ (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
# include <stddef.h>
# include <elf.h>
@@ -264,7 +265,7 @@ void GC_register_dynamic_libraries()
# endif /* SUNOS */
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
- (defined(FREEBSD) && defined(__ELF__)) || \
+ (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
@@ -282,56 +283,23 @@ extern ssize_t GC_repeat_read(int fd, char *buf, size_t count);
/* Repeatedly read until buffer is filled, or EOF is encountered */
/* Defined in os_dep.c. */
-static char *parse_map_entry(char *buf_ptr, word *start, word *end,
- char *prot_buf, unsigned int *maj_dev);
+char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
+ char *prot_buf, unsigned int *maj_dev);
+word GC_apply_to_maps(word (*fn)(char *));
+ /* From os_dep.c */
-void GC_register_dynamic_libraries()
+word GC_register_map_entries(char *maps)
{
- int f;
- int result;
char prot_buf[5];
- int maps_size;
- char maps_temp[32768];
- char *maps_buf;
- char *buf_ptr;
+ char *buf_ptr = maps;
int count;
word start, end;
- unsigned int maj_dev, min_dev;
+ unsigned int maj_dev;
word least_ha, greatest_ha;
unsigned i;
word datastart = (word)(DATASTART);
- /* Read /proc/self/maps */
- /* Note that we may not allocate, and thus can't use stdio. */
- f = open("/proc/self/maps", O_RDONLY);
- if (-1 == f) ABORT("Couldn't open /proc/self/maps");
- /* stat() doesn't work for /proc/self/maps, so we have to
- read it to find out how large it is... */
- maps_size = 0;
- do {
- result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
- if (result <= 0) ABORT("Couldn't read /proc/self/maps");
- maps_size += result;
- } while (result == sizeof(maps_temp));
-
- if (maps_size > sizeof(maps_temp)) {
- /* If larger than our buffer, close and re-read it. */
- close(f);
- f = open("/proc/self/maps", O_RDONLY);
- if (-1 == f) ABORT("Couldn't open /proc/self/maps");
- maps_buf = alloca(maps_size);
- if (NULL == maps_buf) ABORT("/proc/self/maps alloca failed");
- result = GC_repeat_read(f, maps_buf, maps_size);
- if (result <= 0) ABORT("Couldn't read /proc/self/maps");
- } else {
- /* Otherwise use the fixed size buffer */
- maps_buf = maps_temp;
- }
-
- close(f);
- maps_buf[result] = '\0';
- buf_ptr = maps_buf;
- /* Compute heap bounds. Should be done by add_to_heap? */
+ /* Compute heap bounds. FIXME: Should be done by add_to_heap? */
least_ha = (word)(-1);
greatest_ha = 0;
for (i = 0; i < GC_n_heap_sects; ++i) {
@@ -342,11 +310,10 @@ void GC_register_dynamic_libraries()
}
if (greatest_ha < (word)GC_scratch_last_end_ptr)
greatest_ha = (word)GC_scratch_last_end_ptr;
- for (;;) {
-
- buf_ptr = parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
- if (buf_ptr == NULL) return;
+ for (;;) {
+ buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
+ if (buf_ptr == NULL) return 1;
if (prot_buf[1] == 'w') {
/* This is a writable mapping. Add it to */
/* the root set unless it is already otherwise */
@@ -358,16 +325,7 @@ void GC_register_dynamic_libraries()
# ifdef THREADS
if (GC_segment_is_thread_stack(start, end)) continue;
# endif
- /* The rest of this assumes that there is no mapping */
- /* spanning the beginning of the data segment, or extending */
- /* beyond the entire heap at both ends. */
- /* Empirically these assumptions hold. */
-
- if (start < (word)DATAEND && end > (word)DATAEND) {
- /* Rld may use space at the end of the main data */
- /* segment. Thus we add that in. */
- start = (word)DATAEND;
- }
+ /* We no longer exclude the main data segment. */
if (start < least_ha && end > least_ha) {
end = least_ha;
}
@@ -377,7 +335,14 @@ void GC_register_dynamic_libraries()
if (start >= least_ha && end <= greatest_ha) continue;
GC_add_roots_inner((char *)start, (char *)end, TRUE);
}
- }
+ }
+ return 1;
+}
+
+void GC_register_dynamic_libraries()
+{
+ if (!GC_apply_to_maps(GC_register_map_entries))
+ ABORT("Failed to read /proc for library registration.");
}
/* We now take care of the main data segment ourselves: */
@@ -387,60 +352,6 @@ GC_bool GC_register_main_static_data()
}
# define HAVE_REGISTER_MAIN_STATIC_DATA
-//
-// parse_map_entry parses an entry from /proc/self/maps so we can
-// locate all writable data segments that belong to shared libraries.
-// The format of one of these entries and the fields we care about
-// is as follows:
-// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
-// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
-// start end prot maj_dev
-// 0 9 18 32
-//
-// The parser is called with a pointer to the entry and the return value
-// is either NULL or is advanced to the next entry(the byte after the
-// trailing '\n'.)
-//
-#define OFFSET_MAP_START 0
-#define OFFSET_MAP_END 9
-#define OFFSET_MAP_PROT 18
-#define OFFSET_MAP_MAJDEV 32
-
-static char *parse_map_entry(char *buf_ptr, word *start, word *end,
- char *prot_buf, unsigned int *maj_dev)
-{
- int i;
- unsigned int val;
- char *tok;
-
- if (buf_ptr == NULL || *buf_ptr == '\0') {
- return NULL;
- }
-
- memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4); // do the protections first
- prot_buf[4] = '\0';
-
- if (prot_buf[1] == 'w') { // we can skip all of this if it's not writable
-
- tok = buf_ptr;
- buf_ptr[OFFSET_MAP_START+8] = '\0';
- *start = strtoul(tok, NULL, 16);
-
- tok = buf_ptr+OFFSET_MAP_END;
- buf_ptr[OFFSET_MAP_END+8] = '\0';
- *end = strtoul(tok, NULL, 16);
-
- buf_ptr += OFFSET_MAP_MAJDEV;
- tok = buf_ptr;
- while (*buf_ptr != ':') buf_ptr++;
- *buf_ptr++ = '\0';
- *maj_dev = strtoul(tok, NULL, 16);
- }
-
- while (*buf_ptr && *buf_ptr++ != '\n');
-
- return buf_ptr;
-}
#endif /* USE_PROC_FOR_LIBRARIES */
@@ -508,6 +419,7 @@ GC_bool GC_register_dynamic_libraries_dl_iterate_phdr()
GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
# endif
}
+
return TRUE;
} else {
return FALSE;
@@ -534,6 +446,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
@@ -1048,7 +970,7 @@ void GC_register_dynamic_libraries()
len = ldi->ldinfo_next;
GC_add_roots_inner(
ldi->ldinfo_dataorg,
- (unsigned long)ldi->ldinfo_dataorg
+ (ptr_t)(unsigned long)ldi->ldinfo_dataorg
+ ldi->ldinfo_datasize,
TRUE);
ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
@@ -1056,7 +978,133 @@ void GC_register_dynamic_libraries()
}
#endif /* RS6000 */
+#ifdef DARWIN
+
+#include <mach-o/dyld.h>
+#include <mach-o/getsect.h>
+
+/*#define DARWIN_DEBUG*/
+
+const static struct {
+ const char *seg;
+ const char *sect;
+} GC_dyld_sections[] = {
+ { SEG_DATA, SECT_DATA },
+ { SEG_DATA, SECT_BSS },
+ { SEG_DATA, SECT_COMMON }
+};
+
+#ifdef DARWIN_DEBUG
+static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) {
+ unsigned long i,c;
+ c = _dyld_image_count();
+ for(i=0;i<c;i++) if(_dyld_get_image_header(i) == hdr)
+ return _dyld_get_image_name(i);
+ return NULL;
+}
+#endif
+
+/* This should never be called by a thread holding the lock */
+static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) {
+ unsigned long start,end,i;
+ const struct section *sec;
+ 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",
+ start,end,sec->size,GC_dyld_name_for_hdr(hdr));
+# endif
+ GC_add_roots((char*)start,(char*)end);
+ }
+# ifdef DARWIN_DEBUG
+ GC_print_static_roots();
+# endif
+}
+
+/* This should never be called by a thread holding the lock */
+static void GC_dyld_image_remove(struct mach_header* hdr, unsigned long slide) {
+ unsigned long start,end,i;
+ const struct section *sec;
+ 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("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
+}
+
+void GC_register_dynamic_libraries() {
+ /* Currently does nothing. The callbacks are setup by GC_init_dyld()
+ The dyld library takes it from there. */
+}
+
+/* The _dyld_* functions have an internal lock so no _dyld functions
+ can be called while the world is stopped without the risk of a deadlock.
+ Because of this we MUST setup callbacks BEFORE we ever stop the world.
+ This should be called BEFORE any thread in created and WITHOUT the
+ allocation lock held. */
+
+void GC_init_dyld() {
+ static GC_bool initialized = FALSE;
+ char *bind_fully_env = NULL;
+
+ if(initialized) return;
+
+# ifdef DARWIN_DEBUG
+ 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 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
+GC_bool GC_register_main_static_data()
+{
+ /* Already done through dyld callbacks */
+ return FALSE;
+}
+#endif /* DARWIN */
#else /* !DYNAMIC_LOADING */