# 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
+/* An user-supplied routine that is called to dtermine if a DSO must
+ be scanned by the gc. */
+static int (*GC_has_static_roots)(const char *, void *, size_t);
+/* Register the routine. */
+void
+GC_register_has_static_roots_callback
+ (int (*callback)(const char *, void *, size_t))
+{
+ GC_has_static_roots = callback;
+}
+
#if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
#ifdef LINT
{
return FALSE;
}
-
+
# define HAVE_REGISTER_MAIN_STATIC_DATA
#endif /* USE_PROC_FOR_LIBRARIES */
{
if( !(p->p_flags & PF_W) ) break;
start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
+
+ if (GC_has_static_roots
+ && !GC_has_static_roots(info->dlpi_name, start, p->p_memsz))
+ break;
+
GC_add_roots_inner(start, start + p->p_memsz, TRUE);
}
break;
GC_FirstDLOpenedLinkMap()
{
ElfW(Dyn) *dp;
- struct r_debug *r;
static struct link_map *cachedResult = 0;
if( _DYNAMIC == 0) {
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;
/* The type is a lie, since the real type doesn't make sense here, */
/* and we only test for NULL. */
+
/* We use /proc to track down all parts of the address space that are */
/* mapped by the process, and throw out regions we know we shouldn't */
/* worry about. This may also work under other SVR4 variants. */
}
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 */
# 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 chicken to do that 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 */
+
void GC_register_dynamic_libraries()
{
MEMORY_BASIC_INFORMATION buf;
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. */
+ && buf.Type == MEM_IMAGE) {
+# ifdef DEBUG_VIRTUALQUERY
+ GC_dump_meminfo(&buf);
+# endif
if ((char *)p != limit) {
GC_cond_add_roots(base, limit);
base = p;
#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*/
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 */
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() {