49
50
# undef GC_must_restore_redefined_dlopen
53
/* A user-supplied routine that is called to determine if a DSO must
54
be scanned by the gc. */
55
static int (*GC_has_static_roots)(const char *, void *, size_t);
52
58
#if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \
54
#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
60
#if !defined(SOLARISDL) && !defined(IRIX5) && \
55
61
!defined(MSWIN32) && !defined(MSWINCE) && \
56
62
!(defined(ALPHA) && defined(OSF1)) && \
57
63
!defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
58
!defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
64
!defined(AIX) && !defined(SCO_ELF) && !defined(DGUX) && \
59
65
!(defined(FREEBSD) && defined(__ELF__)) && \
60
66
!(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
67
!defined(DARWIN) && !defined(CYGWIN32)
62
68
--> We only know how to find data segments of dynamic libraries for the
63
69
--> above. Additional SVR4 variants might not be too
69
75
# include <sys/elf.h>
70
76
# include <dlfcn.h>
77
/* struct link_map field overrides */
78
# define l_next lm_next
79
# define l_addr lm_addr
80
# define l_name lm_name
83
80
#if defined(NETBSD)
84
81
# include <machine/elf_machdep.h>
165
160
return cachedResult;
168
#endif /* SUNOS5DL ... */
163
#endif /* SOLARISDL ... */
170
165
/* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */
171
166
# if defined(GC_must_restore_redefined_dlopen)
172
167
# define dlopen GC_dlopen
175
#if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
178
struct link_dynamic _DYNAMIC;
181
static struct link_map *
182
GC_FirstDLOpenedLinkMap()
184
extern struct link_dynamic _DYNAMIC;
186
if( &_DYNAMIC == 0) {
189
return(_DYNAMIC.ld_un.ld_1->ld_loaded);
192
/* Return the address of the ld.so allocated common symbol */
193
/* with the least address, or 0 if none. */
194
static ptr_t GC_first_common()
197
extern struct link_dynamic _DYNAMIC;
198
struct rtc_symb * curr_symbol;
200
if( &_DYNAMIC == 0) {
203
curr_symbol = _DYNAMIC.ldd -> ldd_cp;
204
for (; curr_symbol != 0; curr_symbol = curr_symbol -> rtc_next) {
206
|| (ptr_t)(curr_symbol -> rtc_sp -> n_value) < result) {
207
result = (ptr_t)(curr_symbol -> rtc_sp -> n_value);
213
#endif /* SUNOS4 ... */
215
# if defined(SUNOS4) || defined(SUNOS5DL)
170
# if defined(SOLARISDL)
216
171
/* Add dynamic library data sections to the root set. */
217
172
# if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS)
219
173
--> fix mutual exclusion with dlopen
220
# endif /* We assume M3 programs don't call dlopen for now */
223
176
# ifndef USE_PROC_FOR_LIBRARIES
304
233
/* Repeatedly read until buffer is filled, or EOF is encountered */
305
234
/* Defined in os_dep.c. */
307
char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
308
char *prot_buf, unsigned int *maj_dev);
309
word GC_apply_to_maps(word (*fn)(char *));
236
char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
237
char **prot, unsigned int *maj_dev,
238
char **mapping_name);
239
char *GC_get_maps(void);
310
240
/* From os_dep.c */
242
/* Sort an array of HeapSects by start address. */
243
/* Unfortunately at least some versions of */
244
/* Linux qsort end up calling malloc by way of sysconf, and hence can't */
245
/* be used in the colector. Hence we roll our own. Should be */
246
/* reasonably fast if the array is already mostly sorted, as we expect */
248
void sort_heap_sects(struct HeapSect *base, size_t number_of_elements)
250
signed_word n = (signed_word)number_of_elements;
251
signed_word nsorted = 1;
254
while (nsorted < n) {
255
while (nsorted < n &&
256
base[nsorted-1].hs_start < base[nsorted].hs_start)
258
if (nsorted == n) break;
259
GC_ASSERT(base[nsorted-1].hs_start > base[nsorted].hs_start);
261
while (i >= 0 && base[i].hs_start > base[i+1].hs_start) {
262
struct HeapSect tmp = base[i];
267
GC_ASSERT(base[nsorted-1].hs_start < base[nsorted].hs_start);
312
272
word GC_register_map_entries(char *maps)
315
275
char *buf_ptr = maps;
318
278
unsigned int maj_dev;
319
word least_ha, greatest_ha;
279
ptr_t least_ha, greatest_ha;
321
word datastart = (word)(DATASTART);
281
ptr_t datastart = (ptr_t)(DATASTART);
323
/* Compute heap bounds. FIXME: Should be done by add_to_heap? */
324
least_ha = (word)(-1);
326
for (i = 0; i < GC_n_heap_sects; ++i) {
327
word sect_start = (word)GC_heap_sects[i].hs_start;
328
word sect_end = sect_start + GC_heap_sects[i].hs_bytes;
329
if (sect_start < least_ha) least_ha = sect_start;
330
if (sect_end > greatest_ha) greatest_ha = sect_end;
332
if (greatest_ha < (word)GC_scratch_last_end_ptr)
333
greatest_ha = (word)GC_scratch_last_end_ptr;
283
GC_ASSERT(I_HOLD_LOCK());
284
sort_heap_sects(GC_our_memory, GC_n_memory);
285
least_ha = GC_our_memory[0].hs_start;
286
greatest_ha = GC_our_memory[GC_n_memory-1].hs_start
287
+ GC_our_memory[GC_n_memory-1].hs_bytes;
336
buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
290
buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, &prot, &maj_dev, 0);
337
291
if (buf_ptr == NULL) return 1;
338
if (prot_buf[1] == 'w') {
292
if (prot[1] == 'w') {
339
293
/* This is a writable mapping. Add it to */
340
294
/* the root set unless it is already otherwise */
341
295
/* accounted for. */
342
if (start <= (word)GC_stackbottom && end >= (word)GC_stackbottom) {
296
if (start <= GC_stackbottom && end >= GC_stackbottom) {
343
297
/* Stack mapping; discard */
301
/* This may fail, since a thread may already be */
302
/* unregistered, but its thread stack may still be there. */
303
/* That can fail because the stack may disappear while */
304
/* we're marking. Thus the marker is, and has to be */
305
/* prepared to recover from segmentation faults. */
347
307
if (GC_segment_is_thread_stack(start, end)) continue;
309
/* FIXME: NPTL squirrels */
310
/* away pointers in pieces of the stack segment that we */
311
/* don't scan. We work around this */
312
/* by treating anything allocated by libpthread as */
313
/* uncollectable, as we do in some other cases. */
314
/* A specifically identified problem is that */
315
/* thread stacks contain pointers to dynamic thread */
316
/* vectors, which may be reused due to thread caching. */
317
/* They may not be marked if the thread is still live. */
318
/* This specific instance should be addressed by */
319
/* INCLUDE_LINUX_THREAD_DESCR, but that doesn't quite */
320
/* seem to suffice. */
321
/* We currently trace entire thread stacks, if they are */
322
/* are currently cached but unused. This is */
323
/* very suboptimal for performance reasons. */
349
325
/* We no longer exclude the main data segment. */
350
if (start < least_ha && end > least_ha) {
353
if (start < greatest_ha && end > greatest_ha) {
356
if (start >= least_ha && end <= greatest_ha) continue;
357
GC_add_roots_inner((char *)start, (char *)end, TRUE);
326
if (end <= least_ha || start >= greatest_ha) {
327
/* The easy case; just trace entire segment */
328
GC_add_roots_inner((char *)start, (char *)end, TRUE);
331
/* Add sections that dont belong to us. */
333
while (GC_our_memory[i].hs_start + GC_our_memory[i].hs_bytes
336
GC_ASSERT(i < GC_n_memory);
337
if (GC_our_memory[i].hs_start <= start) {
338
start = GC_our_memory[i].hs_start
339
+ GC_our_memory[i].hs_bytes;
342
while (i < GC_n_memory && GC_our_memory[i].hs_start < end
344
if ((char *)start < GC_our_memory[i].hs_start)
345
GC_add_roots_inner((char *)start,
346
GC_our_memory[i].hs_start, TRUE);
347
start = GC_our_memory[i].hs_start
348
+ GC_our_memory[i].hs_bytes;
352
GC_add_roots_inner((char *)start, (char *)end, TRUE);
755
749
# define HAVE_REGISTER_MAIN_STATIC_DATA
757
/* The frame buffer testing code is dead in this version. */
758
/* We leave it here temporarily in case the switch to just */
759
/* testing for MEM_IMAGE sections causes un expected */
761
GC_bool GC_warn_fb = TRUE; /* Warn about traced likely */
762
/* graphics memory. */
763
GC_bool GC_disallow_ignore_fb = FALSE;
764
int GC_ignore_fb_mb; /* Ignore mappings bigger than the */
765
/* specified number of MB. */
766
GC_bool GC_ignore_fb = FALSE; /* Enable frame buffer */
769
/* Issue warning if tracing apparent framebuffer. */
770
/* This limits us to one warning, and it's a back door to */
773
/* Should [start, start+len) be treated as a frame buffer */
775
/* Unfortunately, we currently are not quite sure how to tell */
776
/* this automatically, and rely largely on user input. */
777
/* We expect that any mapping with type MEM_MAPPED (which */
778
/* apparently excludes library data sections) can be safely */
779
/* ignored. But we're too completely remove this code in */
781
/* Based on a very limited sample, it appears that: */
782
/* - Frame buffer mappings appear as mappings of large */
783
/* length, usually a bit less than a power of two. */
784
/* - The definition of "a bit less" in the above cannot */
785
/* be made more precise. */
786
/* - Have a starting address at best 64K aligned. */
787
/* - Have type == MEM_MAPPED. */
788
static GC_bool is_frame_buffer(ptr_t start, size_t len, DWORD tp)
790
static GC_bool initialized = FALSE;
791
# define MB (1024*1024)
792
# define DEFAULT_FB_MB 15
795
if (GC_disallow_ignore_fb || tp != MEM_MAPPED) return FALSE;
797
char * ignore_fb_string = GETENV("GC_IGNORE_FB");
799
if (0 != ignore_fb_string) {
800
while (*ignore_fb_string == ' ' || *ignore_fb_string == '\t')
802
if (*ignore_fb_string == '\0') {
803
GC_ignore_fb_mb = DEFAULT_FB_MB;
805
GC_ignore_fb_mb = atoi(ignore_fb_string);
806
if (GC_ignore_fb_mb < MIN_FB_MB) {
807
WARN("Bad GC_IGNORE_FB value. Using %ld\n", DEFAULT_FB_MB);
808
GC_ignore_fb_mb = DEFAULT_FB_MB;
813
GC_ignore_fb_mb = DEFAULT_FB_MB; /* For warning */
817
if (len >= ((size_t)GC_ignore_fb_mb << 20)) {
822
WARN("Possible frame buffer mapping at 0x%lx: \n"
823
"\tConsider setting GC_IGNORE_FB to improve performance.\n",
834
751
# ifdef DEBUG_VIRTUALQUERY
835
752
void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
837
GC_printf4("BaseAddress = %lx, AllocationBase = %lx, RegionSize = %lx(%lu)\n",
754
GC_printf("BaseAddress = %lx, AllocationBase = %lx, RegionSize = %lx(%lu)\n",
838
755
buf -> BaseAddress, buf -> AllocationBase, buf -> RegionSize,
839
756
buf -> RegionSize);
840
GC_printf4("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
757
GC_printf("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
842
759
buf -> AllocationProtect, buf -> State, buf -> Protect,
884
801
&& (protect == PAGE_EXECUTE_READWRITE
885
802
|| protect == PAGE_READWRITE)
886
803
&& !GC_is_heap_base(buf.AllocationBase)
887
/* This used to check for
888
* !is_frame_buffer(p, buf.RegionSize, buf.Type)
889
* instead of just checking for MEM_IMAGE.
890
* If something breaks, change it back. */
891
/* There is some evidence that we cannot always
892
* ignore MEM_PRIVATE sections under Windows ME
893
* and predecessors. Hence we now also check for
895
&& (buf.Type == MEM_IMAGE ||
896
!GC_wnt && buf.Type == MEM_PRIVATE)) {
804
/* There is some evidence that we cannot always
805
* ignore MEM_PRIVATE sections under Windows ME
806
* and predecessors. Hence we now also check for
808
&& (buf.Type == MEM_IMAGE ||
809
!GC_wnt && buf.Type == MEM_PRIVATE)) {
897
810
# ifdef DEBUG_VIRTUALQUERY
898
811
GC_dump_meminfo(&buf);
1048
960
break; /* Moved past end of shared library list --> finished */
1050
962
if (errno <= sys_nerr) {
1051
GC_printf1("dynamic_load: %s\n", (long) sys_errlist[errno]);
963
GC_printf("dynamic_load: %s\n", sys_errlist[errno]);
1053
GC_printf1("dynamic_load: %d\n", (long) errno);
965
GC_printf("dynamic_load: %d\n", errno);
1055
967
ABORT("shl_get failed");
1061
GC_printf0("---Shared library---\n");
1062
GC_printf1("\tfilename = \"%s\"\n", shl_desc->filename);
1063
GC_printf1("\tindex = %d\n", index);
1064
GC_printf1("\thandle = %08x\n",
973
GC_printf("---Shared library---\n");
974
GC_printf("\tfilename = \"%s\"\n", shl_desc->filename);
975
GC_printf("\tindex = %d\n", index);
976
GC_printf("\thandle = %08x\n",
1065
977
(unsigned long) shl_desc->handle);
1066
GC_printf1("\ttext seg. start = %08x\n", shl_desc->tstart);
1067
GC_printf1("\ttext seg. end = %08x\n", shl_desc->tend);
1068
GC_printf1("\tdata seg. start = %08x\n", shl_desc->dstart);
1069
GC_printf1("\tdata seg. end = %08x\n", shl_desc->dend);
1070
GC_printf1("\tref. count = %lu\n", shl_desc->ref_count);
978
GC_printf("\ttext seg. start = %08x\n", shl_desc->tstart);
979
GC_printf("\ttext seg. end = %08x\n", shl_desc->tend);
980
GC_printf("\tdata seg. start = %08x\n", shl_desc->dstart);
981
GC_printf("\tdata seg. end = %08x\n", shl_desc->dend);
982
GC_printf("\tref. count = %lu\n", shl_desc->ref_count);
1073
985
/* register shared library's data segment as a garbage collection root */
1148
1060
/* This should never be called by a thread holding the lock */
1149
static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) {
1061
static void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr, intptr_t slide)
1150
1063
unsigned long start,end,i;
1151
const struct section *sec;
1064
const struct GC_MACH_SECTION *sec;
1152
1065
if (GC_no_dls) return;
1153
1066
for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
1154
sec = getsectbynamefromheader(
1155
hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
1156
if(sec == NULL || sec->size == 0) continue;
1157
start = slide + sec->addr;
1158
end = start + sec->size;
1159
# ifdef DARWIN_DEBUG
1160
GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
1161
start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1163
GC_add_roots((char*)start,(char*)end);
1067
sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
1068
GC_dyld_sections[i].sect);
1069
if(sec == NULL || sec->size == 0) continue;
1070
start = slide + sec->addr;
1071
end = start + sec->size;
1072
# ifdef DARWIN_DEBUG
1073
GC_printf("Adding section at %p-%p (%lu bytes) from image %s\n",
1074
start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1076
GC_add_roots((char*)start,(char*)end);
1165
1078
# ifdef DARWIN_DEBUG
1166
GC_print_static_roots();
1079
GC_print_static_roots();
1170
1083
/* This should never be called by a thread holding the lock */
1171
static void GC_dyld_image_remove(struct mach_header* hdr, unsigned long slide) {
1084
static void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
1172
1087
unsigned long start,end,i;
1173
const struct section *sec;
1088
const struct GC_MACH_SECTION *sec;
1174
1089
for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
1175
sec = getsectbynamefromheader(
1176
hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
1177
if(sec == NULL || sec->size == 0) continue;
1178
start = slide + sec->addr;
1179
end = start + sec->size;
1180
# ifdef DARWIN_DEBUG
1181
GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
1182
start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1184
GC_remove_roots((char*)start,(char*)end);
1090
sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
1091
GC_dyld_sections[i].sect);
1092
if(sec == NULL || sec->size == 0) continue;
1093
start = slide + sec->addr;
1094
end = start + sec->size;
1095
# ifdef DARWIN_DEBUG
1096
GC_printf("Removing section at %p-%p (%lu bytes) from image %s\n",
1097
start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1099
GC_remove_roots((char*)start,(char*)end);
1186
1101
# ifdef DARWIN_DEBUG
1187
GC_print_static_roots();
1102
GC_print_static_roots();