1 /*
2 * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3 * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
4 * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
5 * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
6 *
7 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
9 *
10 * Permission is hereby granted to use or copy this program
11 * for any purpose, provided the above notices are retained on all copies.
12 * Permission to modify the code and to distribute modified code is granted,
13 * provided the above notices are retained, and a notice that the code was
14 * modified is included with the above copyright notice.
15 */
16
17 #include "private/gc_priv.h"
18
19 #if defined(LINUX) && !defined(POWERPC)
20 # include <linux/version.h>
21 # if (LINUX_VERSION_CODE <= 0x10400)
22 /* Ugly hack to get struct sigcontext_struct definition. Required */
23 /* for some early 1.3.X releases. Will hopefully go away soon. */
24 /* in some later Linux releases, asm/sigcontext.h may have to */
25 /* be included instead. */
26 # define __KERNEL__
27 # include <asm/signal.h>
28 # undef __KERNEL__
29 # else
30 /* Kernels prior to 2.1.1 defined struct sigcontext_struct instead of */
31 /* struct sigcontext. libc6 (glibc2) uses "struct sigcontext" in */
32 /* prototypes, so we have to include the top-level sigcontext.h to */
33 /* make sure the former gets defined to be the latter if appropriate. */
34 # include <features.h>
35 # if 2 <= __GLIBC__
36 # if 2 == __GLIBC__ && 0 == __GLIBC_MINOR__
37 /* glibc 2.1 no longer has sigcontext.h. But signal.h */
38 /* has the right declaration for glibc 2.1. */
39 # include <sigcontext.h>
40 # endif /* 0 == __GLIBC_MINOR__ */
41 # else /* not 2 <= __GLIBC__ */
42 /* libc5 doesn't have <sigcontext.h>: go directly with the kernel */
43 /* one. Check LINUX_VERSION_CODE to see which we should reference. */
44 # include <asm/sigcontext.h>
45 # endif /* 2 <= __GLIBC__ */
46 # endif
47 #endif
48
49 #if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \
50 && !defined(MSWINCE) && !defined(__CC_ARM)
51 # include <sys/types.h>
52 # if !defined(MSWIN32)
53 # include <unistd.h>
54 # endif
55 #endif
56
57 #include <stdio.h>
58 #if defined(MSWINCE) || defined(SN_TARGET_PS3)
59 # define SIGSEGV 0 /* value is irrelevant */
60 #else
61 # include <signal.h>
62 #endif
63
64 #if defined(UNIX_LIKE) || defined(CYGWIN32) || defined(NACL)
65 # include <fcntl.h>
66 #endif
67
68 #if defined(LINUX) || defined(LINUX_STACKBOTTOM)
69 # include <ctype.h>
70 #endif
71
72 /* Blatantly OS dependent routines, except for those that are related */
73 /* to dynamic loading. */
74
75 #ifdef AMIGA
76 # define GC_AMIGA_DEF
77 # include "extra/AmigaOS.c"
78 # undef GC_AMIGA_DEF
79 #endif
80
81 #if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
82 # ifndef WIN32_LEAN_AND_MEAN
83 # define WIN32_LEAN_AND_MEAN 1
84 # endif
85 # define NOSERVICE
86 # include <windows.h>
87 /* It's not clear this is completely kosher under Cygwin. But it */
88 /* allows us to get a working GC_get_stack_base. */
89 #endif
90
91 #ifdef MACOS
92 # include <Processes.h>
93 #endif
94
95 #ifdef IRIX5
96 # include <sys/uio.h>
97 # include <malloc.h> /* for locking */
98 #endif
99
100 #if defined(LINUX) || defined(FREEBSD) || defined(SOLARIS) || defined(IRIX5) \
101 || ((defined(USE_MMAP) || defined(USE_MUNMAP)) \
102 && !defined(MSWIN32) && !defined(MSWINCE))
103 # define MMAP_SUPPORTED
104 #endif
105
106 #if defined(MMAP_SUPPORTED) || defined(ADD_HEAP_GUARD_PAGES)
107 # if defined(USE_MUNMAP) && !defined(USE_MMAP)
108 # error "invalid config - USE_MUNMAP requires USE_MMAP"
109 # endif
110 # include <sys/types.h>
111 # include <sys/mman.h>
112 # include <sys/stat.h>
113 # include <errno.h>
114 #endif
115
116 #ifdef DARWIN
117 /* for get_etext and friends */
118 # include <mach-o/getsect.h>
119 #endif
120
121 #ifdef DJGPP
122 /* Apparently necessary for djgpp 2.01. May cause problems with */
123 /* other versions. */
124 typedef long unsigned int caddr_t;
125 #endif
126
127 #ifdef PCR
128 # include "il/PCR_IL.h"
129 # include "th/PCR_ThCtl.h"
130 # include "mm/PCR_MM.h"
131 #endif
132
133 #if !defined(NO_EXECUTE_PERMISSION)
134 STATIC GC_bool GC_pages_executable = TRUE;
135 #else
136 STATIC GC_bool GC_pages_executable = FALSE;
137 #endif
138 #define IGNORE_PAGES_EXECUTABLE 1
139 /* Undefined on GC_pages_executable real use. */
140
141 #if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) \
142 || !defined(SMALL_CONFIG))
143 # define NEED_PROC_MAPS
144 #endif
145
146 #ifdef NEED_PROC_MAPS
147 /* We need to parse /proc/self/maps, either to find dynamic libraries, */
148 /* and/or to find the register backing store base (IA64). Do it once */
149 /* here. */
150
151 #define READ read
152
153 /* Repeatedly perform a read call until the buffer is filled or */
154 /* we encounter EOF. */
GC_repeat_read(int fd,char * buf,size_t count)155 STATIC ssize_t GC_repeat_read(int fd, char *buf, size_t count)
156 {
157 ssize_t num_read = 0;
158 ssize_t result;
159
160 ASSERT_CANCEL_DISABLED();
161 while (num_read < count) {
162 result = READ(fd, buf + num_read, count - num_read);
163 if (result < 0) return result;
164 if (result == 0) break;
165 num_read += result;
166 }
167 return num_read;
168 }
169
170 #ifdef THREADS
171 /* Determine the length of a file by incrementally reading it into a */
172 /* This would be silly to use on a file supporting lseek, but Linux */
173 /* /proc files usually do not. */
GC_get_file_len(int f)174 STATIC size_t GC_get_file_len(int f)
175 {
176 size_t total = 0;
177 ssize_t result;
178 # define GET_FILE_LEN_BUF_SZ 500
179 char buf[GET_FILE_LEN_BUF_SZ];
180
181 do {
182 result = read(f, buf, GET_FILE_LEN_BUF_SZ);
183 if (result == -1) return 0;
184 total += result;
185 } while (result > 0);
186 return total;
187 }
188
GC_get_maps_len(void)189 STATIC size_t GC_get_maps_len(void)
190 {
191 int f = open("/proc/self/maps", O_RDONLY);
192 size_t result;
193 if (f < 0) return 0; /* treat missing file as empty */
194 result = GC_get_file_len(f);
195 close(f);
196 return result;
197 }
198 #endif /* THREADS */
199
200 /* Copy the contents of /proc/self/maps to a buffer in our address */
201 /* space. Return the address of the buffer, or zero on failure. */
202 /* This code could be simplified if we could determine its size ahead */
203 /* of time. */
GC_get_maps(void)204 GC_INNER char * GC_get_maps(void)
205 {
206 int f;
207 int result;
208 static char init_buf[1];
209 static char *maps_buf = init_buf;
210 static size_t maps_buf_sz = 1;
211 size_t maps_size, old_maps_size = 0;
212
213 /* The buffer is essentially static, so there must be a single client. */
214 GC_ASSERT(I_HOLD_LOCK());
215
216 /* Note that in the presence of threads, the maps file can */
217 /* essentially shrink asynchronously and unexpectedly as */
218 /* threads that we already think of as dead release their */
219 /* stacks. And there is no easy way to read the entire */
220 /* file atomically. This is arguably a misfeature of the */
221 /* /proc/.../maps interface. */
222
223 /* Since we don't believe the file can grow */
224 /* asynchronously, it should suffice to first determine */
225 /* the size (using lseek or read), and then to reread the */
226 /* file. If the size is inconsistent we have to retry. */
227 /* This only matters with threads enabled, and if we use */
228 /* this to locate roots (not the default). */
229
230 # ifdef THREADS
231 /* Determine the initial size of /proc/self/maps. */
232 /* Note that lseek doesn't work, at least as of 2.6.15. */
233 maps_size = GC_get_maps_len();
234 if (0 == maps_size) return 0;
235 # else
236 maps_size = 4000; /* Guess */
237 # endif
238
239 /* Read /proc/self/maps, growing maps_buf as necessary. */
240 /* Note that we may not allocate conventionally, and */
241 /* thus can't use stdio. */
242 do {
243 while (maps_size >= maps_buf_sz) {
244 /* Grow only by powers of 2, since we leak "too small" buffers.*/
245 while (maps_size >= maps_buf_sz) maps_buf_sz *= 2;
246 maps_buf = GC_scratch_alloc(maps_buf_sz);
247 # ifdef THREADS
248 /* Recompute initial length, since we allocated. */
249 /* This can only happen a few times per program */
250 /* execution. */
251 maps_size = GC_get_maps_len();
252 if (0 == maps_size) return 0;
253 # endif
254 if (maps_buf == 0) return 0;
255 }
256 GC_ASSERT(maps_buf_sz >= maps_size + 1);
257 f = open("/proc/self/maps", O_RDONLY);
258 if (-1 == f) return 0;
259 # ifdef THREADS
260 old_maps_size = maps_size;
261 # endif
262 maps_size = 0;
263 do {
264 result = GC_repeat_read(f, maps_buf, maps_buf_sz-1);
265 if (result <= 0)
266 break;
267 maps_size += result;
268 } while (result == maps_buf_sz-1);
269 close(f);
270 if (result <= 0)
271 return 0;
272 # ifdef THREADS
273 if (maps_size > old_maps_size) {
274 if (GC_print_stats)
275 GC_log_printf(
276 "Unexpected maps size growth from %lu to %lu\n",
277 (unsigned long)old_maps_size,
278 (unsigned long)maps_size);
279 ABORT("Unexpected asynchronous /proc/self/maps growth: "
280 "unregistered thread?");
281 }
282 # endif
283 } while (maps_size >= maps_buf_sz || maps_size < old_maps_size);
284 /* In the single-threaded case, the second clause is false. */
285 maps_buf[maps_size] = '\0';
286
287 /* Apply fn to result. */
288 return maps_buf;
289 }
290
291 /*
292 * GC_parse_map_entry parses an entry from /proc/self/maps so we can
293 * locate all writable data segments that belong to shared libraries.
294 * The format of one of these entries and the fields we care about
295 * is as follows:
296 * XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
297 * ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
298 * start end prot maj_dev
299 *
300 * Note that since about august 2003 kernels, the columns no longer have
301 * fixed offsets on 64-bit kernels. Hence we no longer rely on fixed offsets
302 * anywhere, which is safer anyway.
303 */
304
305 /* Assign various fields of the first line in buf_ptr to (*start), */
306 /* (*end), (*prot), (*maj_dev) and (*mapping_name). mapping_name may */
307 /* be NULL. (*prot) and (*mapping_name) are assigned pointers into the */
308 /* original buffer. */
GC_parse_map_entry(char * buf_ptr,ptr_t * start,ptr_t * end,char ** prot,unsigned int * maj_dev,char ** mapping_name)309 GC_INNER char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
310 char **prot, unsigned int *maj_dev,
311 char **mapping_name)
312 {
313 char *start_start, *end_start, *maj_dev_start;
314 char *p;
315 char *endp;
316
317 if (buf_ptr == NULL || *buf_ptr == '\0') {
318 return NULL;
319 }
320
321 p = buf_ptr;
322 while (isspace(*p)) ++p;
323 start_start = p;
324 GC_ASSERT(isxdigit(*start_start));
325 *start = (ptr_t)strtoul(start_start, &endp, 16); p = endp;
326 GC_ASSERT(*p=='-');
327
328 ++p;
329 end_start = p;
330 GC_ASSERT(isxdigit(*end_start));
331 *end = (ptr_t)strtoul(end_start, &endp, 16); p = endp;
332 GC_ASSERT(isspace(*p));
333
334 while (isspace(*p)) ++p;
335 GC_ASSERT(*p == 'r' || *p == '-');
336 *prot = p;
337 /* Skip past protection field to offset field */
338 while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
339 GC_ASSERT(isxdigit(*p));
340 /* Skip past offset field, which we ignore */
341 while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
342 maj_dev_start = p;
343 GC_ASSERT(isxdigit(*maj_dev_start));
344 *maj_dev = strtoul(maj_dev_start, NULL, 16);
345
346 if (mapping_name == 0) {
347 while (*p && *p++ != '\n');
348 } else {
349 while (*p && *p != '\n' && *p != '/' && *p != '[') p++;
350 *mapping_name = p;
351 while (*p && *p++ != '\n');
352 }
353
354 return p;
355 }
356
357 /* Try to read the backing store base from /proc/self/maps. */
358 /* Return the bounds of the writable mapping with a 0 major device, */
359 /* which includes the address passed as data. */
360 /* Return FALSE if there is no such mapping. */
GC_enclosing_mapping(ptr_t addr,ptr_t * startp,ptr_t * endp)361 GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp, ptr_t *endp)
362 {
363 char *prot;
364 ptr_t my_start, my_end;
365 unsigned int maj_dev;
366 char *maps = GC_get_maps();
367 char *buf_ptr = maps;
368
369 if (0 == maps) return(FALSE);
370 for (;;) {
371 buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,
372 &prot, &maj_dev, 0);
373
374 if (buf_ptr == NULL) return FALSE;
375 if (prot[1] == 'w' && maj_dev == 0) {
376 if (my_end > addr && my_start <= addr) {
377 *startp = my_start;
378 *endp = my_end;
379 return TRUE;
380 }
381 }
382 }
383 return FALSE;
384 }
385
386 #if defined(REDIRECT_MALLOC)
387 /* Find the text(code) mapping for the library whose name, after */
388 /* stripping the directory part, starts with nm. */
GC_text_mapping(char * nm,ptr_t * startp,ptr_t * endp)389 GC_INNER GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp)
390 {
391 size_t nm_len = strlen(nm);
392 char *prot;
393 char *map_path;
394 ptr_t my_start, my_end;
395 unsigned int maj_dev;
396 char *maps = GC_get_maps();
397 char *buf_ptr = maps;
398
399 if (0 == maps) return(FALSE);
400 for (;;) {
401 buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,
402 &prot, &maj_dev, &map_path);
403
404 if (buf_ptr == NULL) return FALSE;
405 if (prot[0] == 'r' && prot[1] == '-' && prot[2] == 'x') {
406 char *p = map_path;
407 /* Set p to point just past last slash, if any. */
408 while (*p != '\0' && *p != '\n' && *p != ' ' && *p != '\t') ++p;
409 while (*p != '/' && p >= map_path) --p;
410 ++p;
411 if (strncmp(nm, p, nm_len) == 0) {
412 *startp = my_start;
413 *endp = my_end;
414 return TRUE;
415 }
416 }
417 }
418 return FALSE;
419 }
420 #endif /* REDIRECT_MALLOC */
421
422 #ifdef IA64
backing_store_base_from_proc(void)423 static ptr_t backing_store_base_from_proc(void)
424 {
425 ptr_t my_start, my_end;
426 if (!GC_enclosing_mapping(GC_save_regs_in_stack(), &my_start, &my_end)) {
427 if (GC_print_stats) {
428 GC_log_printf("Failed to find backing store base from /proc\n");
429 }
430 return 0;
431 }
432 return my_start;
433 }
434 #endif
435
436 #endif /* NEED_PROC_MAPS */
437
438 #if defined(SEARCH_FOR_DATA_START)
439 /* The I386 case can be handled without a search. The Alpha case */
440 /* used to be handled differently as well, but the rules changed */
441 /* for recent Linux versions. This seems to be the easiest way to */
442 /* cover all versions. */
443
444 # if defined(LINUX) || defined(HURD)
445 /* Some Linux distributions arrange to define __data_start. Some */
446 /* define data_start as a weak symbol. The latter is technically */
447 /* broken, since the user program may define data_start, in which */
448 /* case we lose. Nonetheless, we try both, preferring __data_start.*/
449 /* We assume gcc-compatible pragmas. */
450 # pragma weak __data_start
451 extern int __data_start[];
452 # pragma weak data_start
453 extern int data_start[];
454 # endif /* LINUX */
455 extern int _end[];
456
457 ptr_t GC_data_start = NULL;
458
459 ptr_t GC_find_limit(ptr_t, GC_bool);
460
GC_init_linux_data_start(void)461 GC_INNER void GC_init_linux_data_start(void)
462 {
463
464 # if defined(LINUX) || defined(HURD)
465 /* Try the easy approaches first: */
466 if ((ptr_t)__data_start != 0) {
467 GC_data_start = (ptr_t)(__data_start);
468 return;
469 }
470 if ((ptr_t)data_start != 0) {
471 GC_data_start = (ptr_t)(data_start);
472 return;
473 }
474 # endif /* LINUX */
475 GC_data_start = GC_find_limit((ptr_t)(_end), FALSE);
476 }
477 #endif
478
479 #ifdef ECOS
480
481 # ifndef ECOS_GC_MEMORY_SIZE
482 # define ECOS_GC_MEMORY_SIZE (448 * 1024)
483 # endif /* ECOS_GC_MEMORY_SIZE */
484
485 /* FIXME: This is a simple way of allocating memory which is */
486 /* compatible with ECOS early releases. Later releases use a more */
487 /* sophisticated means of allocating memory than this simple static */
488 /* allocator, but this method is at least bound to work. */
489 static char ecos_gc_memory[ECOS_GC_MEMORY_SIZE];
490 static char *ecos_gc_brk = ecos_gc_memory;
491
tiny_sbrk(ptrdiff_t increment)492 static void *tiny_sbrk(ptrdiff_t increment)
493 {
494 void *p = ecos_gc_brk;
495 ecos_gc_brk += increment;
496 if (ecos_gc_brk > ecos_gc_memory + sizeof(ecos_gc_memory)) {
497 ecos_gc_brk -= increment;
498 return NULL;
499 }
500 return p;
501 }
502 # define sbrk tiny_sbrk
503 #endif /* ECOS */
504
505 #if defined(NETBSD) && defined(__ELF__)
506 ptr_t GC_data_start = NULL;
507 ptr_t GC_find_limit(ptr_t, GC_bool);
508
509 extern char **environ;
510
GC_init_netbsd_elf(void)511 GC_INNER void GC_init_netbsd_elf(void)
512 {
513 /* This may need to be environ, without the underscore, for */
514 /* some versions. */
515 GC_data_start = GC_find_limit((ptr_t)&environ, FALSE);
516 }
517 #endif /* NETBSD */
518
519 #ifdef OPENBSD
520 static struct sigaction old_segv_act;
521 STATIC sigjmp_buf GC_jmp_buf_openbsd;
522
523 # ifdef THREADS
524 # include <sys/syscall.h>
525 extern sigset_t __syscall(quad_t, ...);
526 # endif
527
528 /* Don't use GC_find_limit() because siglongjmp() outside of the */
529 /* signal handler by-passes our userland pthreads lib, leaving */
530 /* SIGSEGV and SIGPROF masked. Instead, use this custom one that */
531 /* works-around the issues. */
532
533 /*ARGSUSED*/
GC_fault_handler_openbsd(int sig)534 STATIC void GC_fault_handler_openbsd(int sig)
535 {
536 siglongjmp(GC_jmp_buf_openbsd, 1);
537 }
538
539 /* Return the first non-addressible location > p or bound. */
540 /* Requires the allocation lock. */
GC_find_limit_openbsd(ptr_t p,ptr_t bound)541 STATIC ptr_t GC_find_limit_openbsd(ptr_t p, ptr_t bound)
542 {
543 static volatile ptr_t result;
544 /* Safer if static, since otherwise it may not be */
545 /* preserved across the longjmp. Can safely be */
546 /* static since it's only called with the */
547 /* allocation lock held. */
548
549 struct sigaction act;
550 size_t pgsz = (size_t)sysconf(_SC_PAGESIZE);
551 GC_ASSERT(I_HOLD_LOCK());
552
553 act.sa_handler = GC_fault_handler_openbsd;
554 sigemptyset(&act.sa_mask);
555 act.sa_flags = SA_NODEFER | SA_RESTART;
556 sigaction(SIGSEGV, &act, &old_segv_act);
557
558 if (sigsetjmp(GC_jmp_buf_openbsd, 1) == 0) {
559 result = (ptr_t)((word)p & ~(pgsz-1));
560 for (;;) {
561 result += pgsz;
562 if (result >= bound) {
563 result = bound;
564 break;
565 }
566 GC_noop1((word)(*result));
567 }
568 }
569
570 # ifdef THREADS
571 /* Due to the siglongjump we need to manually unmask SIGPROF. */
572 __syscall(SYS_sigprocmask, SIG_UNBLOCK, sigmask(SIGPROF));
573 # endif
574
575 sigaction(SIGSEGV, &old_segv_act, 0);
576 return(result);
577 }
578
579 /* Return first addressable location > p or bound. */
580 /* Requires the allocation lock. */
GC_skip_hole_openbsd(ptr_t p,ptr_t bound)581 STATIC ptr_t GC_skip_hole_openbsd(ptr_t p, ptr_t bound)
582 {
583 static volatile ptr_t result;
584 static volatile int firstpass;
585
586 struct sigaction act;
587 size_t pgsz = (size_t)sysconf(_SC_PAGESIZE);
588 GC_ASSERT(I_HOLD_LOCK());
589
590 act.sa_handler = GC_fault_handler_openbsd;
591 sigemptyset(&act.sa_mask);
592 act.sa_flags = SA_NODEFER | SA_RESTART;
593 sigaction(SIGSEGV, &act, &old_segv_act);
594
595 firstpass = 1;
596 result = (ptr_t)((word)p & ~(pgsz-1));
597 if (sigsetjmp(GC_jmp_buf_openbsd, 1) != 0 || firstpass) {
598 firstpass = 0;
599 result += pgsz;
600 if (result >= bound) {
601 result = bound;
602 } else {
603 GC_noop1((word)(*result));
604 }
605 }
606
607 sigaction(SIGSEGV, &old_segv_act, 0);
608 return(result);
609 }
610 #endif /* OPENBSD */
611
612 # ifdef OS2
613
614 # include <stddef.h>
615
616 # if !defined(__IBMC__) && !defined(__WATCOMC__) /* e.g. EMX */
617
618 struct exe_hdr {
619 unsigned short magic_number;
620 unsigned short padding[29];
621 long new_exe_offset;
622 };
623
624 #define E_MAGIC(x) (x).magic_number
625 #define EMAGIC 0x5A4D
626 #define E_LFANEW(x) (x).new_exe_offset
627
628 struct e32_exe {
629 unsigned char magic_number[2];
630 unsigned char byte_order;
631 unsigned char word_order;
632 unsigned long exe_format_level;
633 unsigned short cpu;
634 unsigned short os;
635 unsigned long padding1[13];
636 unsigned long object_table_offset;
637 unsigned long object_count;
638 unsigned long padding2[31];
639 };
640
641 #define E32_MAGIC1(x) (x).magic_number[0]
642 #define E32MAGIC1 'L'
643 #define E32_MAGIC2(x) (x).magic_number[1]
644 #define E32MAGIC2 'X'
645 #define E32_BORDER(x) (x).byte_order
646 #define E32LEBO 0
647 #define E32_WORDER(x) (x).word_order
648 #define E32LEWO 0
649 #define E32_CPU(x) (x).cpu
650 #define E32CPU286 1
651 #define E32_OBJTAB(x) (x).object_table_offset
652 #define E32_OBJCNT(x) (x).object_count
653
654 struct o32_obj {
655 unsigned long size;
656 unsigned long base;
657 unsigned long flags;
658 unsigned long pagemap;
659 unsigned long mapsize;
660 unsigned long reserved;
661 };
662
663 #define O32_FLAGS(x) (x).flags
664 #define OBJREAD 0x0001L
665 #define OBJWRITE 0x0002L
666 #define OBJINVALID 0x0080L
667 #define O32_SIZE(x) (x).size
668 #define O32_BASE(x) (x).base
669
670 # else /* IBM's compiler */
671
672 /* A kludge to get around what appears to be a header file bug */
673 # ifndef WORD
674 # define WORD unsigned short
675 # endif
676 # ifndef DWORD
677 # define DWORD unsigned long
678 # endif
679
680 # define EXE386 1
681 # include <newexe.h>
682 # include <exe386.h>
683
684 # endif /* __IBMC__ */
685
686 # define INCL_DOSEXCEPTIONS
687 # define INCL_DOSPROCESS
688 # define INCL_DOSERRORS
689 # define INCL_DOSMODULEMGR
690 # define INCL_DOSMEMMGR
691 # include <os2.h>
692
693 # endif /* OS/2 */
694
695 /* Find the page size */
696 GC_INNER word GC_page_size = 0;
697
698 #if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
699 # ifndef VER_PLATFORM_WIN32_CE
700 # define VER_PLATFORM_WIN32_CE 3
701 # endif
702
703 # if defined(MSWINCE) && defined(THREADS)
704 GC_INNER GC_bool GC_dont_query_stack_min = FALSE;
705 # endif
706
GC_setpagesize(void)707 GC_INNER void GC_setpagesize(void)
708 {
709 GetSystemInfo(&GC_sysinfo);
710 GC_page_size = GC_sysinfo.dwPageSize;
711 # if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
712 {
713 OSVERSIONINFO verInfo;
714 /* Check the current WinCE version. */
715 verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
716 if (!GetVersionEx(&verInfo))
717 ABORT("GetVersionEx failed");
718 if (verInfo.dwPlatformId == VER_PLATFORM_WIN32_CE &&
719 verInfo.dwMajorVersion < 6) {
720 /* Only the first 32 MB of address space belongs to the */
721 /* current process (unless WinCE 6.0+ or emulation). */
722 GC_sysinfo.lpMaximumApplicationAddress = (LPVOID)((word)32 << 20);
723 # ifdef THREADS
724 /* On some old WinCE versions, it's observed that */
725 /* VirtualQuery calls don't work properly when used to */
726 /* get thread current stack committed minimum. */
727 if (verInfo.dwMajorVersion < 5)
728 GC_dont_query_stack_min = TRUE;
729 # endif
730 }
731 }
732 # endif
733 }
734
735 # ifndef CYGWIN32
736 # define is_writable(prot) ((prot) == PAGE_READWRITE \
737 || (prot) == PAGE_WRITECOPY \
738 || (prot) == PAGE_EXECUTE_READWRITE \
739 || (prot) == PAGE_EXECUTE_WRITECOPY)
740 /* Return the number of bytes that are writable starting at p. */
741 /* The pointer p is assumed to be page aligned. */
742 /* If base is not 0, *base becomes the beginning of the */
743 /* allocation region containing p. */
GC_get_writable_length(ptr_t p,ptr_t * base)744 STATIC word GC_get_writable_length(ptr_t p, ptr_t *base)
745 {
746 MEMORY_BASIC_INFORMATION buf;
747 word result;
748 word protect;
749
750 result = VirtualQuery(p, &buf, sizeof(buf));
751 if (result != sizeof(buf)) ABORT("Weird VirtualQuery result");
752 if (base != 0) *base = (ptr_t)(buf.AllocationBase);
753 protect = (buf.Protect & ~(PAGE_GUARD | PAGE_NOCACHE));
754 if (!is_writable(protect)) {
755 return(0);
756 }
757 if (buf.State != MEM_COMMIT) return(0);
758 return(buf.RegionSize);
759 }
760
GC_get_stack_base(struct GC_stack_base * sb)761 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
762 {
763 int dummy;
764 ptr_t sp = (ptr_t)(&dummy);
765 ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_page_size - 1));
766 /* FIXME: This won't work if called from a deeply recursive */
767 /* client code (and the committed stack space has grown). */
768 word size = GC_get_writable_length(trunc_sp, 0);
769 GC_ASSERT(size != 0);
770 sb -> mem_base = trunc_sp + size;
771 return GC_SUCCESS;
772 }
773 # else /* CYGWIN32 */
774 /* An alternate version for Cygwin (adapted from Dave Korn's */
775 /* gcc version of boehm-gc). */
GC_get_stack_base(struct GC_stack_base * sb)776 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
777 {
778 extern void * _tlsbase __asm__ ("%fs:4");
779 sb -> mem_base = _tlsbase;
780 return GC_SUCCESS;
781 }
782 # endif /* CYGWIN32 */
783 # define HAVE_GET_STACK_BASE
784
785 #else /* !MSWIN32 */
GC_setpagesize(void)786 GC_INNER void GC_setpagesize(void)
787 {
788 # if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP)
789 GC_page_size = GETPAGESIZE();
790 if (!GC_page_size) ABORT("getpagesize() failed");
791 # else
792 /* It's acceptable to fake it. */
793 GC_page_size = HBLKSIZE;
794 # endif
795 }
796 #endif /* !MSWIN32 */
797
798 #ifdef BEOS
799 # include <kernel/OS.h>
800
GC_get_stack_base(struct GC_stack_base * sb)801 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
802 {
803 thread_info th;
804 get_thread_info(find_thread(NULL),&th);
805 sb->mem_base = th.stack_end;
806 return GC_SUCCESS;
807 }
808 # define HAVE_GET_STACK_BASE
809 #endif /* BEOS */
810
811 #ifdef OS2
GC_get_stack_base(struct GC_stack_base * sb)812 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
813 {
814 PTIB ptib; /* thread information block */
815 PPIB ppib;
816 if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
817 ABORT("DosGetInfoBlocks failed");
818 }
819 sb->mem_base = ptib->tib_pstacklimit;
820 return GC_SUCCESS;
821 }
822 # define HAVE_GET_STACK_BASE
823 #endif /* OS2 */
824
825 # ifdef AMIGA
826 # define GC_AMIGA_SB
827 # include "extra/AmigaOS.c"
828 # undef GC_AMIGA_SB
829 # endif /* AMIGA */
830
831 # if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
832
833 typedef void (*GC_fault_handler_t)(int);
834
835 # if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
836 || defined(HURD) || defined(NETBSD)
837 static struct sigaction old_segv_act;
838 # if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) \
839 || defined(HURD) || defined(NETBSD) || defined(FREEBSD)
840 static struct sigaction old_bus_act;
841 # endif
842 # else
843 static GC_fault_handler_t old_segv_handler, old_bus_handler;
844 # endif
845
GC_set_and_save_fault_handler(GC_fault_handler_t h)846 GC_INNER void GC_set_and_save_fault_handler(GC_fault_handler_t h)
847 {
848 # if defined(SUNOS5SIGS) || defined(IRIX5) \
849 || defined(OSF1) || defined(HURD) || defined(NETBSD)
850 struct sigaction act;
851
852 act.sa_handler = h;
853 # ifdef SIGACTION_FLAGS_NODEFER_HACK
854 /* Was necessary for Solaris 2.3 and very temporary */
855 /* NetBSD bugs. */
856 act.sa_flags = SA_RESTART | SA_NODEFER;
857 # else
858 act.sa_flags = SA_RESTART;
859 # endif
860
861 (void) sigemptyset(&act.sa_mask);
862 # ifdef GC_IRIX_THREADS
863 /* Older versions have a bug related to retrieving and */
864 /* and setting a handler at the same time. */
865 (void) sigaction(SIGSEGV, 0, &old_segv_act);
866 (void) sigaction(SIGSEGV, &act, 0);
867 # else
868 (void) sigaction(SIGSEGV, &act, &old_segv_act);
869 # if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
870 || defined(HPUX) || defined(HURD) || defined(NETBSD) \
871 || defined(FREEBSD)
872 /* Under Irix 5.x or HP/UX, we may get SIGBUS. */
873 /* Pthreads doesn't exist under Irix 5.x, so we */
874 /* don't have to worry in the threads case. */
875 (void) sigaction(SIGBUS, &act, &old_bus_act);
876 # endif
877 # endif /* GC_IRIX_THREADS */
878 # else
879 old_segv_handler = signal(SIGSEGV, h);
880 # ifdef SIGBUS
881 old_bus_handler = signal(SIGBUS, h);
882 # endif
883 # endif
884 }
885 # endif /* NEED_FIND_LIMIT || UNIX_LIKE */
886
887 # if defined(NEED_FIND_LIMIT) \
888 || (defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS))
889 /* Some tools to implement HEURISTIC2 */
890 # define MIN_PAGE_SIZE 256 /* Smallest conceivable page size, bytes */
891
892 GC_INNER JMP_BUF GC_jmp_buf;
893
894 /*ARGSUSED*/
GC_fault_handler(int sig)895 STATIC void GC_fault_handler(int sig)
896 {
897 LONGJMP(GC_jmp_buf, 1);
898 }
899
GC_setup_temporary_fault_handler(void)900 GC_INNER void GC_setup_temporary_fault_handler(void)
901 {
902 /* Handler is process-wide, so this should only happen in */
903 /* one thread at a time. */
904 GC_ASSERT(I_HOLD_LOCK());
905 GC_set_and_save_fault_handler(GC_fault_handler);
906 }
907
GC_reset_fault_handler(void)908 GC_INNER void GC_reset_fault_handler(void)
909 {
910 # if defined(SUNOS5SIGS) || defined(IRIX5) \
911 || defined(OSF1) || defined(HURD) || defined(NETBSD)
912 (void) sigaction(SIGSEGV, &old_segv_act, 0);
913 # if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
914 || defined(HPUX) || defined(HURD) || defined(NETBSD) \
915 || defined(FREEBSD)
916 (void) sigaction(SIGBUS, &old_bus_act, 0);
917 # endif
918 # else
919 (void) signal(SIGSEGV, old_segv_handler);
920 # ifdef SIGBUS
921 (void) signal(SIGBUS, old_bus_handler);
922 # endif
923 # endif
924 }
925
926 /* Return the first non-addressable location > p (up) or */
927 /* the smallest location q s.t. [q,p) is addressable (!up). */
928 /* We assume that p (up) or p-1 (!up) is addressable. */
929 /* Requires allocation lock. */
GC_find_limit_with_bound(ptr_t p,GC_bool up,ptr_t bound)930 STATIC ptr_t GC_find_limit_with_bound(ptr_t p, GC_bool up, ptr_t bound)
931 {
932 static volatile ptr_t result;
933 /* Safer if static, since otherwise it may not be */
934 /* preserved across the longjmp. Can safely be */
935 /* static since it's only called with the */
936 /* allocation lock held. */
937
938 GC_ASSERT(I_HOLD_LOCK());
939 GC_setup_temporary_fault_handler();
940 if (SETJMP(GC_jmp_buf) == 0) {
941 result = (ptr_t)(((word)(p))
942 & ~(MIN_PAGE_SIZE-1));
943 for (;;) {
944 if (up) {
945 result += MIN_PAGE_SIZE;
946 if (result >= bound) return bound;
947 } else {
948 result -= MIN_PAGE_SIZE;
949 if (result <= bound) return bound;
950 }
951 GC_noop1((word)(*result));
952 }
953 }
954 GC_reset_fault_handler();
955 if (!up) {
956 result += MIN_PAGE_SIZE;
957 }
958 return(result);
959 }
960
GC_find_limit(ptr_t p,GC_bool up)961 ptr_t GC_find_limit(ptr_t p, GC_bool up)
962 {
963 return GC_find_limit_with_bound(p, up, up ? (ptr_t)(word)(-1) : 0);
964 }
965 # endif /* NEED_FIND_LIMIT || USE_PROC_FOR_LIBRARIES */
966
967 #ifdef HPUX_STACKBOTTOM
968
969 #include <sys/param.h>
970 #include <sys/pstat.h>
971
GC_get_register_stack_base(void)972 GC_INNER ptr_t GC_get_register_stack_base(void)
973 {
974 struct pst_vm_status vm_status;
975
976 int i = 0;
977 while (pstat_getprocvm(&vm_status, sizeof(vm_status), 0, i++) == 1) {
978 if (vm_status.pst_type == PS_RSESTACK) {
979 return (ptr_t) vm_status.pst_vaddr;
980 }
981 }
982
983 /* old way to get the register stackbottom */
984 return (ptr_t)(((word)GC_stackbottom - BACKING_STORE_DISPLACEMENT - 1)
985 & ~(BACKING_STORE_ALIGNMENT - 1));
986 }
987
988 #endif /* HPUX_STACK_BOTTOM */
989
990 #ifdef LINUX_STACKBOTTOM
991
992 # include <sys/types.h>
993 # include <sys/stat.h>
994
995 # define STAT_SKIP 27 /* Number of fields preceding startstack */
996 /* field in /proc/self/stat */
997
998 # ifdef USE_LIBC_PRIVATES
999 # pragma weak __libc_stack_end
1000 extern ptr_t __libc_stack_end;
1001 # endif
1002
1003 # ifdef IA64
1004 # ifdef USE_LIBC_PRIVATES
1005 # pragma weak __libc_ia64_register_backing_store_base
1006 extern ptr_t __libc_ia64_register_backing_store_base;
1007 # endif
1008
GC_get_register_stack_base(void)1009 GC_INNER ptr_t GC_get_register_stack_base(void)
1010 {
1011 ptr_t result;
1012
1013 # ifdef USE_LIBC_PRIVATES
1014 if (0 != &__libc_ia64_register_backing_store_base
1015 && 0 != __libc_ia64_register_backing_store_base) {
1016 /* Glibc 2.2.4 has a bug such that for dynamically linked */
1017 /* executables __libc_ia64_register_backing_store_base is */
1018 /* defined but uninitialized during constructor calls. */
1019 /* Hence we check for both nonzero address and value. */
1020 return __libc_ia64_register_backing_store_base;
1021 }
1022 # endif
1023 result = backing_store_base_from_proc();
1024 if (0 == result) {
1025 result = GC_find_limit(GC_save_regs_in_stack(), FALSE);
1026 /* Now seems to work better than constant displacement */
1027 /* heuristic used in 6.X versions. The latter seems to */
1028 /* fail for 2.6 kernels. */
1029 }
1030 return result;
1031 }
1032 # endif /* IA64 */
1033
GC_linux_main_stack_base(void)1034 STATIC ptr_t GC_linux_main_stack_base(void)
1035 {
1036 /* We read the stack base value from /proc/self/stat. We do this */
1037 /* using direct I/O system calls in order to avoid calling malloc */
1038 /* in case REDIRECT_MALLOC is defined. */
1039 # ifndef STAT_READ
1040 /* Also defined in pthread_support.c. */
1041 # define STAT_BUF_SIZE 4096
1042 # define STAT_READ read
1043 # endif
1044 /* Should probably call the real read, if read is wrapped. */
1045 char stat_buf[STAT_BUF_SIZE];
1046 int f;
1047 word result;
1048 int i, buf_offset = 0, len;
1049
1050 /* First try the easy way. This should work for glibc 2.2 */
1051 /* This fails in a prelinked ("prelink" command) executable */
1052 /* since the correct value of __libc_stack_end never */
1053 /* becomes visible to us. The second test works around */
1054 /* this. */
1055 # ifdef USE_LIBC_PRIVATES
1056 if (0 != &__libc_stack_end && 0 != __libc_stack_end ) {
1057 # if defined(IA64)
1058 /* Some versions of glibc set the address 16 bytes too */
1059 /* low while the initialization code is running. */
1060 if (((word)__libc_stack_end & 0xfff) + 0x10 < 0x1000) {
1061 return __libc_stack_end + 0x10;
1062 } /* Otherwise it's not safe to add 16 bytes and we fall */
1063 /* back to using /proc. */
1064 # elif defined(SPARC)
1065 /* Older versions of glibc for 64-bit Sparc do not set
1066 * this variable correctly, it gets set to either zero
1067 * or one.
1068 */
1069 if (__libc_stack_end != (ptr_t) (unsigned long)0x1)
1070 return __libc_stack_end;
1071 # else
1072 return __libc_stack_end;
1073 # endif
1074 }
1075 # endif
1076 f = open("/proc/self/stat", O_RDONLY);
1077 if (f < 0)
1078 ABORT("Couldn't read /proc/self/stat");
1079 len = STAT_READ(f, stat_buf, STAT_BUF_SIZE);
1080 close(f);
1081
1082 /* Skip the required number of fields. This number is hopefully */
1083 /* constant across all Linux implementations. */
1084 for (i = 0; i < STAT_SKIP; ++i) {
1085 while (buf_offset < len && isspace(stat_buf[buf_offset++])) {
1086 /* empty */
1087 }
1088 while (buf_offset < len && !isspace(stat_buf[buf_offset++])) {
1089 /* empty */
1090 }
1091 }
1092 /* Skip spaces. */
1093 while (buf_offset < len && isspace(stat_buf[buf_offset])) {
1094 buf_offset++;
1095 }
1096 /* Find the end of the number and cut the buffer there. */
1097 for (i = 0; buf_offset + i < len; i++) {
1098 if (!isdigit(stat_buf[buf_offset + i])) break;
1099 }
1100 if (buf_offset + i >= len) ABORT("Could not parse /proc/self/stat");
1101 stat_buf[buf_offset + i] = '\0';
1102
1103 result = (word)STRTOULL(&stat_buf[buf_offset], NULL, 10);
1104 if (result < 0x100000 || (result & (sizeof(word) - 1)) != 0)
1105 ABORT("Absurd stack bottom value");
1106 return (ptr_t)result;
1107 }
1108 #endif /* LINUX_STACKBOTTOM */
1109
1110 #ifdef FREEBSD_STACKBOTTOM
1111 /* This uses an undocumented sysctl call, but at least one expert */
1112 /* believes it will stay. */
1113
1114 # include <unistd.h>
1115 # include <sys/types.h>
1116 # include <sys/sysctl.h>
1117
GC_freebsd_main_stack_base(void)1118 STATIC ptr_t GC_freebsd_main_stack_base(void)
1119 {
1120 int nm[2] = {CTL_KERN, KERN_USRSTACK};
1121 ptr_t base;
1122 size_t len = sizeof(ptr_t);
1123 int r = sysctl(nm, 2, &base, &len, NULL, 0);
1124 if (r) ABORT("Error getting main stack base");
1125 return base;
1126 }
1127 #endif /* FREEBSD_STACKBOTTOM */
1128
1129 #if defined(ECOS) || defined(NOSYS)
GC_get_main_stack_base(void)1130 ptr_t GC_get_main_stack_base(void)
1131 {
1132 return STACKBOTTOM;
1133 }
1134 # define GET_MAIN_STACKBASE_SPECIAL
1135 #elif !defined(BEOS) && !defined(AMIGA) && !defined(OS2) \
1136 && !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) \
1137 && !defined(GC_OPENBSD_THREADS) \
1138 && (!defined(GC_SOLARIS_THREADS) || defined(_STRICT_STDC))
1139
1140 # if defined(LINUX) && defined(USE_GET_STACKBASE_FOR_MAIN)
1141 # include <pthread.h>
1142 # elif defined(DARWIN) && !defined(NO_PTHREAD_GET_STACKADDR_NP)
1143 /* We could use pthread_get_stackaddr_np even in case of a */
1144 /* single-threaded gclib (there is no -lpthread on Darwin). */
1145 # include <pthread.h>
1146 # undef STACKBOTTOM
1147 # define STACKBOTTOM (ptr_t)pthread_get_stackaddr_np(pthread_self())
1148 # endif
1149
GC_get_main_stack_base(void)1150 ptr_t GC_get_main_stack_base(void)
1151 {
1152 ptr_t result; /* also used as "dummy" to get the approx. sp value */
1153 # if defined(LINUX) && !defined(NACL) \
1154 && (defined(USE_GET_STACKBASE_FOR_MAIN) || defined(THREADS))
1155 pthread_attr_t attr;
1156 void *stackaddr;
1157 size_t size;
1158 if (pthread_getattr_np(pthread_self(), &attr) == 0) {
1159 if (pthread_attr_getstack(&attr, &stackaddr, &size) == 0
1160 && stackaddr != NULL) {
1161 pthread_attr_destroy(&attr);
1162 # ifdef STACK_GROWS_DOWN
1163 stackaddr = (char *)stackaddr + size;
1164 # endif
1165 return (ptr_t)stackaddr;
1166 }
1167 pthread_attr_destroy(&attr);
1168 }
1169 WARN("pthread_getattr_np or pthread_attr_getstack failed"
1170 " for main thread\n", 0);
1171 # endif
1172 # ifdef STACKBOTTOM
1173 result = STACKBOTTOM;
1174 # else
1175 # define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
1176 # ifdef HEURISTIC1
1177 # ifdef STACK_GROWS_DOWN
1178 result = (ptr_t)((((word)(&result)) + STACKBOTTOM_ALIGNMENT_M1)
1179 & ~STACKBOTTOM_ALIGNMENT_M1);
1180 # else
1181 result = (ptr_t)(((word)(&result)) & ~STACKBOTTOM_ALIGNMENT_M1);
1182 # endif
1183 # endif /* HEURISTIC1 */
1184 # ifdef LINUX_STACKBOTTOM
1185 result = GC_linux_main_stack_base();
1186 # endif
1187 # ifdef FREEBSD_STACKBOTTOM
1188 result = GC_freebsd_main_stack_base();
1189 # endif
1190 # ifdef HEURISTIC2
1191 # ifdef STACK_GROWS_DOWN
1192 result = GC_find_limit((ptr_t)(&result), TRUE);
1193 # ifdef HEURISTIC2_LIMIT
1194 if (result > HEURISTIC2_LIMIT
1195 && (ptr_t)(&result) < HEURISTIC2_LIMIT) {
1196 result = HEURISTIC2_LIMIT;
1197 }
1198 # endif
1199 # else
1200 result = GC_find_limit((ptr_t)(&result), FALSE);
1201 # ifdef HEURISTIC2_LIMIT
1202 if (result < HEURISTIC2_LIMIT
1203 && (ptr_t)(&result) > HEURISTIC2_LIMIT) {
1204 result = HEURISTIC2_LIMIT;
1205 }
1206 # endif
1207 # endif
1208 # endif /* HEURISTIC2 */
1209 # ifdef STACK_GROWS_DOWN
1210 if (result == 0)
1211 result = (ptr_t)(signed_word)(-sizeof(ptr_t));
1212 # endif
1213 # endif
1214 GC_ASSERT((ptr_t)(&result) HOTTER_THAN result);
1215 return(result);
1216 }
1217 # define GET_MAIN_STACKBASE_SPECIAL
1218 #endif /* !AMIGA, !BEOS, !OPENBSD, !OS2, !Windows */
1219
1220 #if (defined(GC_LINUX_THREADS) || defined(PLATFORM_ANDROID)) && !defined(NACL)
1221
1222 # include <pthread.h>
1223 /* extern int pthread_getattr_np(pthread_t, pthread_attr_t *); */
1224
1225 # ifdef IA64
1226 GC_INNER ptr_t GC_greatest_stack_base_below(ptr_t bound);
1227 /* From pthread_support.c */
1228 # endif
1229
GC_get_stack_base(struct GC_stack_base * b)1230 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
1231 {
1232 pthread_attr_t attr;
1233 size_t size;
1234 # ifdef IA64
1235 DCL_LOCK_STATE;
1236 # endif
1237
1238 if (pthread_getattr_np(pthread_self(), &attr) != 0) {
1239 WARN("pthread_getattr_np failed\n", 0);
1240 return GC_UNIMPLEMENTED;
1241 }
1242 if (pthread_attr_getstack(&attr, &(b -> mem_base), &size) != 0) {
1243 ABORT("pthread_attr_getstack failed");
1244 }
1245 pthread_attr_destroy(&attr);
1246 # ifdef STACK_GROWS_DOWN
1247 b -> mem_base = (char *)(b -> mem_base) + size;
1248 # endif
1249 # ifdef IA64
1250 /* We could try backing_store_base_from_proc, but that's safe */
1251 /* only if no mappings are being asynchronously created. */
1252 /* Subtracting the size from the stack base doesn't work for at */
1253 /* least the main thread. */
1254 LOCK();
1255 {
1256 IF_CANCEL(int cancel_state;)
1257 ptr_t bsp;
1258 ptr_t next_stack;
1259
1260 DISABLE_CANCEL(cancel_state);
1261 bsp = GC_save_regs_in_stack();
1262 next_stack = GC_greatest_stack_base_below(bsp);
1263 if (0 == next_stack) {
1264 b -> reg_base = GC_find_limit(bsp, FALSE);
1265 } else {
1266 /* Avoid walking backwards into preceding memory stack and */
1267 /* growing it. */
1268 b -> reg_base = GC_find_limit_with_bound(bsp, FALSE, next_stack);
1269 }
1270 RESTORE_CANCEL(cancel_state);
1271 }
1272 UNLOCK();
1273 # endif
1274 return GC_SUCCESS;
1275 }
1276 # define HAVE_GET_STACK_BASE
1277 #endif /* GC_LINUX_THREADS */
1278
1279 #if defined(GC_DARWIN_THREADS) && !defined(NO_PTHREAD_GET_STACKADDR_NP)
1280 # include <pthread.h>
1281
GC_get_stack_base(struct GC_stack_base * b)1282 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
1283 {
1284 # ifdef GC_ASSERTIONS
1285 int dummy;
1286 # endif
1287 /* pthread_get_stackaddr_np() should return stack bottom (highest */
1288 /* stack address plus 1). */
1289 b->mem_base = pthread_get_stackaddr_np(pthread_self());
1290 GC_ASSERT((void *)&dummy HOTTER_THAN b->mem_base);
1291 return GC_SUCCESS;
1292 }
1293 # define HAVE_GET_STACK_BASE
1294 #endif /* GC_DARWIN_THREADS */
1295
1296 #ifdef GC_OPENBSD_THREADS
1297 # include <sys/signal.h>
1298 # include <pthread.h>
1299 # include <pthread_np.h>
1300
1301 /* Find the stack using pthread_stackseg_np(). */
GC_get_stack_base(struct GC_stack_base * sb)1302 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
1303 {
1304 stack_t stack;
1305 pthread_stackseg_np(pthread_self(), &stack);
1306 sb->mem_base = stack.ss_sp;
1307 return GC_SUCCESS;
1308 }
1309 # define HAVE_GET_STACK_BASE
1310 #endif /* GC_OPENBSD_THREADS */
1311
1312 #if defined(GC_SOLARIS_THREADS) && !defined(_STRICT_STDC)
1313
1314 # include <thread.h>
1315 # include <signal.h>
1316 # include <pthread.h>
1317
1318 /* These variables are used to cache ss_sp value for the primordial */
1319 /* thread (it's better not to call thr_stksegment() twice for this */
1320 /* thread - see JDK bug #4352906). */
1321 static pthread_t stackbase_main_self = 0;
1322 /* 0 means stackbase_main_ss_sp value is unset. */
1323 static void *stackbase_main_ss_sp = NULL;
1324
GC_get_stack_base(struct GC_stack_base * b)1325 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
1326 {
1327 stack_t s;
1328 pthread_t self = pthread_self();
1329 if (self == stackbase_main_self)
1330 {
1331 /* If the client calls GC_get_stack_base() from the main thread */
1332 /* then just return the cached value. */
1333 b -> mem_base = stackbase_main_ss_sp;
1334 GC_ASSERT(b -> mem_base != NULL);
1335 return GC_SUCCESS;
1336 }
1337
1338 if (thr_stksegment(&s)) {
1339 /* According to the manual, the only failure error code returned */
1340 /* is EAGAIN meaning "the information is not available due to the */
1341 /* thread is not yet completely initialized or it is an internal */
1342 /* thread" - this shouldn't happen here. */
1343 ABORT("thr_stksegment failed");
1344 }
1345 /* s.ss_sp holds the pointer to the stack bottom. */
1346 GC_ASSERT((void *)&s HOTTER_THAN s.ss_sp);
1347
1348 if (!stackbase_main_self && thr_main() != 0)
1349 {
1350 /* Cache the stack base value for the primordial thread (this */
1351 /* is done during GC_init, so there is no race). */
1352 stackbase_main_ss_sp = s.ss_sp;
1353 stackbase_main_self = self;
1354 }
1355
1356 b -> mem_base = s.ss_sp;
1357 return GC_SUCCESS;
1358 }
1359 # define HAVE_GET_STACK_BASE
1360 #endif /* GC_SOLARIS_THREADS */
1361
1362 #ifndef HAVE_GET_STACK_BASE
1363 /* Retrieve stack base. */
1364 /* Using the GC_find_limit version is risky. */
1365 /* On IA64, for example, there is no guard page between the */
1366 /* stack of one thread and the register backing store of the */
1367 /* next. Thus this is likely to identify way too large a */
1368 /* "stack" and thus at least result in disastrous performance. */
1369 /* FIXME - Implement better strategies here. */
GC_get_stack_base(struct GC_stack_base * b)1370 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
1371 {
1372 # ifdef NEED_FIND_LIMIT
1373 int dummy;
1374 IF_CANCEL(int cancel_state;)
1375 DCL_LOCK_STATE;
1376
1377 LOCK();
1378 DISABLE_CANCEL(cancel_state); /* May be unnecessary? */
1379 # ifdef STACK_GROWS_DOWN
1380 b -> mem_base = GC_find_limit((ptr_t)(&dummy), TRUE);
1381 # ifdef IA64
1382 b -> reg_base = GC_find_limit(GC_save_regs_in_stack(), FALSE);
1383 # endif
1384 # else
1385 b -> mem_base = GC_find_limit(&dummy, FALSE);
1386 # endif
1387 RESTORE_CANCEL(cancel_state);
1388 UNLOCK();
1389 return GC_SUCCESS;
1390 # else
1391 return GC_UNIMPLEMENTED;
1392 # endif
1393 }
1394 #endif /* !HAVE_GET_STACK_BASE */
1395
1396 #ifndef GET_MAIN_STACKBASE_SPECIAL
1397 /* This is always called from the main thread. Default implementation. */
GC_get_main_stack_base(void)1398 ptr_t GC_get_main_stack_base(void)
1399 {
1400 struct GC_stack_base sb;
1401 if (GC_get_stack_base(&sb) != GC_SUCCESS)
1402 ABORT("GC_get_stack_base failed");
1403 GC_ASSERT((void *)&sb HOTTER_THAN sb.mem_base);
1404 return (ptr_t)sb.mem_base;
1405 }
1406 #endif /* !GET_MAIN_STACKBASE_SPECIAL */
1407
1408 /* Register static data segment(s) as roots. If more data segments are */
1409 /* added later then they need to be registered at that point (as we do */
1410 /* with SunOS dynamic loading), or GC_mark_roots needs to check for */
1411 /* them (as we do with PCR). Called with allocator lock held. */
1412 # ifdef OS2
1413
GC_register_data_segments(void)1414 void GC_register_data_segments(void)
1415 {
1416 PTIB ptib;
1417 PPIB ppib;
1418 HMODULE module_handle;
1419 # define PBUFSIZ 512
1420 UCHAR path[PBUFSIZ];
1421 FILE * myexefile;
1422 struct exe_hdr hdrdos; /* MSDOS header. */
1423 struct e32_exe hdr386; /* Real header for my executable */
1424 struct o32_obj seg; /* Currrent segment */
1425 int nsegs;
1426
1427
1428 if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
1429 ABORT("DosGetInfoBlocks failed");
1430 }
1431 module_handle = ppib -> pib_hmte;
1432 if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) {
1433 GC_err_printf("DosQueryModuleName failed\n");
1434 ABORT("DosGetInfoBlocks failed");
1435 }
1436 myexefile = fopen(path, "rb");
1437 if (myexefile == 0) {
1438 if (GC_print_stats) {
1439 GC_err_puts("Couldn't open executable ");
1440 GC_err_puts(path);
1441 GC_err_puts("\n");
1442 }
1443 ABORT("Failed to open executable");
1444 }
1445 if (fread((char *)(&hdrdos), 1, sizeof(hdrdos), myexefile)
1446 < sizeof(hdrdos)) {
1447 if (GC_print_stats) {
1448 GC_err_puts("Couldn't read MSDOS header from ");
1449 GC_err_puts(path);
1450 GC_err_puts("\n");
1451 }
1452 ABORT("Couldn't read MSDOS header");
1453 }
1454 if (E_MAGIC(hdrdos) != EMAGIC) {
1455 if (GC_print_stats) {
1456 GC_err_puts("Executable has wrong DOS magic number: ");
1457 GC_err_puts(path);
1458 GC_err_puts("\n");
1459 }
1460 ABORT("Bad DOS magic number");
1461 }
1462 if (fseek(myexefile, E_LFANEW(hdrdos), SEEK_SET) != 0) {
1463 if (GC_print_stats) {
1464 GC_err_puts("Seek to new header failed in ");
1465 GC_err_puts(path);
1466 GC_err_puts("\n");
1467 }
1468 ABORT("Bad DOS magic number");
1469 }
1470 if (fread((char *)(&hdr386), 1, sizeof(hdr386), myexefile)
1471 < sizeof(hdr386)) {
1472 if (GC_print_stats) {
1473 GC_err_puts("Couldn't read MSDOS header from ");
1474 GC_err_puts(path);
1475 GC_err_puts("\n");
1476 }
1477 ABORT("Couldn't read OS/2 header");
1478 }
1479 if (E32_MAGIC1(hdr386) != E32MAGIC1 || E32_MAGIC2(hdr386) != E32MAGIC2) {
1480 if (GC_print_stats) {
1481 GC_err_puts("Executable has wrong OS/2 magic number: ");
1482 GC_err_puts(path);
1483 GC_err_puts("\n");
1484 }
1485 ABORT("Bad OS/2 magic number");
1486 }
1487 if (E32_BORDER(hdr386) != E32LEBO || E32_WORDER(hdr386) != E32LEWO) {
1488 if (GC_print_stats) {
1489 GC_err_puts("Executable has wrong byte order: ");
1490 GC_err_puts(path);
1491 GC_err_puts("\n");
1492 }
1493 ABORT("Bad byte order");
1494 }
1495 if (E32_CPU(hdr386) == E32CPU286) {
1496 if (GC_print_stats) {
1497 GC_err_puts("GC can't handle 80286 executables: ");
1498 GC_err_puts(path);
1499 GC_err_puts("\n");
1500 }
1501 ABORT("Intel 80286 executables are unsupported");
1502 }
1503 if (fseek(myexefile, E_LFANEW(hdrdos) + E32_OBJTAB(hdr386),
1504 SEEK_SET) != 0) {
1505 if (GC_print_stats) {
1506 GC_err_puts("Seek to object table failed: ");
1507 GC_err_puts(path);
1508 GC_err_puts("\n");
1509 }
1510 ABORT("Seek to object table failed");
1511 }
1512 for (nsegs = E32_OBJCNT(hdr386); nsegs > 0; nsegs--) {
1513 int flags;
1514 if (fread((char *)(&seg), 1, sizeof(seg), myexefile) < sizeof(seg)) {
1515 if (GC_print_stats) {
1516 GC_err_puts("Couldn't read obj table entry from ");
1517 GC_err_puts(path);
1518 GC_err_puts("\n");
1519 }
1520 ABORT("Couldn't read obj table entry");
1521 }
1522 flags = O32_FLAGS(seg);
1523 if (!(flags & OBJWRITE)) continue;
1524 if (!(flags & OBJREAD)) continue;
1525 if (flags & OBJINVALID) {
1526 GC_err_printf("Object with invalid pages?\n");
1527 continue;
1528 }
1529 GC_add_roots_inner((ptr_t)O32_BASE(seg),
1530 (ptr_t)(O32_BASE(seg)+O32_SIZE(seg)), FALSE);
1531 }
1532 }
1533
1534 # else /* !OS2 */
1535
1536 # if defined(GWW_VDB)
1537 # ifndef MEM_WRITE_WATCH
1538 # define MEM_WRITE_WATCH 0x200000
1539 # endif
1540 # ifndef WRITE_WATCH_FLAG_RESET
1541 # define WRITE_WATCH_FLAG_RESET 1
1542 # endif
1543
1544 /* Since we can't easily check whether ULONG_PTR and SIZE_T are */
1545 /* defined in Win32 basetsd.h, we define own ULONG_PTR. */
1546 # define GC_ULONG_PTR word
1547
1548 typedef UINT (WINAPI * GetWriteWatch_type)(
1549 DWORD, PVOID, GC_ULONG_PTR /* SIZE_T */,
1550 PVOID *, GC_ULONG_PTR *, PULONG);
1551 static GetWriteWatch_type GetWriteWatch_func;
1552 static DWORD GetWriteWatch_alloc_flag;
1553
1554 # define GC_GWW_AVAILABLE() (GetWriteWatch_func != NULL)
1555
detect_GetWriteWatch(void)1556 static void detect_GetWriteWatch(void)
1557 {
1558 static GC_bool done;
1559 HMODULE hK32;
1560 if (done)
1561 return;
1562
1563 # if defined(MPROTECT_VDB)
1564 {
1565 char * str = GETENV("GC_USE_GETWRITEWATCH");
1566 # if defined(GC_PREFER_MPROTECT_VDB)
1567 if (str == NULL || (*str == '0' && *(str + 1) == '\0')) {
1568 /* GC_USE_GETWRITEWATCH is unset or set to "0". */
1569 done = TRUE; /* falling back to MPROTECT_VDB strategy. */
1570 /* This should work as if GWW_VDB is undefined. */
1571 return;
1572 }
1573 # else
1574 if (str != NULL && *str == '0' && *(str + 1) == '\0') {
1575 /* GC_USE_GETWRITEWATCH is set "0". */
1576 done = TRUE; /* falling back to MPROTECT_VDB strategy. */
1577 return;
1578 }
1579 # endif
1580 }
1581 # endif
1582
1583 hK32 = GetModuleHandle(TEXT("kernel32.dll"));
1584 if (hK32 != (HMODULE)0 &&
1585 (GetWriteWatch_func = (GetWriteWatch_type)GetProcAddress(hK32,
1586 "GetWriteWatch")) != NULL) {
1587 /* Also check whether VirtualAlloc accepts MEM_WRITE_WATCH, */
1588 /* as some versions of kernel32.dll have one but not the */
1589 /* other, making the feature completely broken. */
1590 void * page = VirtualAlloc(NULL, GC_page_size,
1591 MEM_WRITE_WATCH | MEM_RESERVE,
1592 PAGE_READWRITE);
1593 if (page != NULL) {
1594 PVOID pages[16];
1595 GC_ULONG_PTR count = 16;
1596 DWORD page_size;
1597 /* Check that it actually works. In spite of some */
1598 /* documentation it actually seems to exist on W2K. */
1599 /* This test may be unnecessary, but ... */
1600 if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
1601 page, GC_page_size,
1602 pages,
1603 &count,
1604 &page_size) != 0) {
1605 /* GetWriteWatch always fails. */
1606 GetWriteWatch_func = NULL;
1607 } else {
1608 GetWriteWatch_alloc_flag = MEM_WRITE_WATCH;
1609 }
1610 VirtualFree(page, GC_page_size, MEM_RELEASE);
1611 } else {
1612 /* GetWriteWatch will be useless. */
1613 GetWriteWatch_func = NULL;
1614 }
1615 }
1616 if (GC_print_stats) {
1617 if (GetWriteWatch_func == NULL) {
1618 GC_log_printf("Did not find a usable GetWriteWatch()\n");
1619 } else {
1620 GC_log_printf("Using GetWriteWatch()\n");
1621 }
1622 }
1623 done = TRUE;
1624 }
1625
1626 # else
1627 # define GetWriteWatch_alloc_flag 0
1628 # endif /* !GWW_VDB */
1629
1630 # if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
1631
1632 # ifdef MSWIN32
1633 /* Unfortunately, we have to handle win32s very differently from NT, */
1634 /* Since VirtualQuery has very different semantics. In particular, */
1635 /* under win32s a VirtualQuery call on an unmapped page returns an */
1636 /* invalid result. Under NT, GC_register_data_segments is a no-op */
1637 /* and all real work is done by GC_register_dynamic_libraries. Under */
1638 /* win32s, we cannot find the data segments associated with dll's. */
1639 /* We register the main data segment here. */
1640 GC_INNER GC_bool GC_no_win32_dlls = FALSE;
1641 /* This used to be set for gcc, to avoid dealing with */
1642 /* the structured exception handling issues. But we now have */
1643 /* assembly code to do that right. */
1644
1645 GC_INNER GC_bool GC_wnt = FALSE;
1646 /* This is a Windows NT derivative, i.e. NT, W2K, XP or later. */
1647
GC_init_win32(void)1648 GC_INNER void GC_init_win32(void)
1649 {
1650 /* Set GC_wnt. If we're running under win32s, assume that no DLLs */
1651 /* will be loaded. I doubt anyone still runs win32s, but... */
1652 DWORD v = GetVersion();
1653 GC_wnt = !(v & 0x80000000);
1654 GC_no_win32_dlls |= ((!GC_wnt) && (v & 0xff) <= 3);
1655 # ifdef USE_MUNMAP
1656 if (GC_no_win32_dlls) {
1657 /* Turn off unmapping for safety (since may not work well with */
1658 /* GlobalAlloc). */
1659 GC_unmap_threshold = 0;
1660 }
1661 # endif
1662 }
1663
1664 /* Return the smallest address a such that VirtualQuery */
1665 /* returns correct results for all addresses between a and start. */
1666 /* Assumes VirtualQuery returns correct information for start. */
GC_least_described_address(ptr_t start)1667 STATIC ptr_t GC_least_described_address(ptr_t start)
1668 {
1669 MEMORY_BASIC_INFORMATION buf;
1670 size_t result;
1671 LPVOID limit;
1672 ptr_t p;
1673 LPVOID q;
1674
1675 limit = GC_sysinfo.lpMinimumApplicationAddress;
1676 p = (ptr_t)((word)start & ~(GC_page_size - 1));
1677 for (;;) {
1678 q = (LPVOID)(p - GC_page_size);
1679 if ((ptr_t)q > (ptr_t)p /* underflow */ || q < limit) break;
1680 result = VirtualQuery(q, &buf, sizeof(buf));
1681 if (result != sizeof(buf) || buf.AllocationBase == 0) break;
1682 p = (ptr_t)(buf.AllocationBase);
1683 }
1684 return p;
1685 }
1686 # endif /* MSWIN32 */
1687
1688 # ifndef REDIRECT_MALLOC
1689 /* We maintain a linked list of AllocationBase values that we know */
1690 /* correspond to malloc heap sections. Currently this is only called */
1691 /* during a GC. But there is some hope that for long running */
1692 /* programs we will eventually see most heap sections. */
1693
1694 /* In the long run, it would be more reliable to occasionally walk */
1695 /* the malloc heap with HeapWalk on the default heap. But that */
1696 /* apparently works only for NT-based Windows. */
1697
1698 STATIC size_t GC_max_root_size = 100000; /* Appr. largest root size. */
1699
1700 # ifndef CYGWIN32
1701 /* In the long run, a better data structure would also be nice ... */
1702 STATIC struct GC_malloc_heap_list {
1703 void * allocation_base;
1704 struct GC_malloc_heap_list *next;
1705 } *GC_malloc_heap_l = 0;
1706
1707 /* Is p the base of one of the malloc heap sections we already know */
1708 /* about? */
GC_is_malloc_heap_base(ptr_t p)1709 STATIC GC_bool GC_is_malloc_heap_base(ptr_t p)
1710 {
1711 struct GC_malloc_heap_list *q = GC_malloc_heap_l;
1712
1713 while (0 != q) {
1714 if (q -> allocation_base == p) return TRUE;
1715 q = q -> next;
1716 }
1717 return FALSE;
1718 }
1719
GC_get_allocation_base(void * p)1720 STATIC void *GC_get_allocation_base(void *p)
1721 {
1722 MEMORY_BASIC_INFORMATION buf;
1723 size_t result = VirtualQuery(p, &buf, sizeof(buf));
1724 if (result != sizeof(buf)) {
1725 ABORT("Weird VirtualQuery result");
1726 }
1727 return buf.AllocationBase;
1728 }
1729
GC_add_current_malloc_heap(void)1730 GC_INNER void GC_add_current_malloc_heap(void)
1731 {
1732 struct GC_malloc_heap_list *new_l =
1733 malloc(sizeof(struct GC_malloc_heap_list));
1734 void * candidate = GC_get_allocation_base(new_l);
1735
1736 if (new_l == 0) return;
1737 if (GC_is_malloc_heap_base(candidate)) {
1738 /* Try a little harder to find malloc heap. */
1739 size_t req_size = 10000;
1740 do {
1741 void *p = malloc(req_size);
1742 if (0 == p) {
1743 free(new_l);
1744 return;
1745 }
1746 candidate = GC_get_allocation_base(p);
1747 free(p);
1748 req_size *= 2;
1749 } while (GC_is_malloc_heap_base(candidate)
1750 && req_size < GC_max_root_size/10 && req_size < 500000);
1751 if (GC_is_malloc_heap_base(candidate)) {
1752 free(new_l);
1753 return;
1754 }
1755 }
1756 if (GC_print_stats)
1757 GC_log_printf("Found new system malloc AllocationBase at %p\n",
1758 candidate);
1759 new_l -> allocation_base = candidate;
1760 new_l -> next = GC_malloc_heap_l;
1761 GC_malloc_heap_l = new_l;
1762 }
1763 # endif /* !CYGWIN32 */
1764
1765 # endif /* !REDIRECT_MALLOC */
1766
1767 STATIC word GC_n_heap_bases = 0; /* See GC_heap_bases. */
1768
1769 /* Is p the start of either the malloc heap, or of one of our */
1770 /* heap sections? */
GC_is_heap_base(ptr_t p)1771 GC_INNER GC_bool GC_is_heap_base(ptr_t p)
1772 {
1773 unsigned i;
1774 # ifndef REDIRECT_MALLOC
1775 if (GC_root_size > GC_max_root_size) GC_max_root_size = GC_root_size;
1776 # ifndef CYGWIN32
1777 if (GC_is_malloc_heap_base(p)) return TRUE;
1778 # endif
1779 # endif
1780 for (i = 0; i < GC_n_heap_bases; i++) {
1781 if (GC_heap_bases[i] == p) return TRUE;
1782 }
1783 return FALSE;
1784 }
1785
1786 #ifdef MSWIN32
GC_register_root_section(ptr_t static_root)1787 STATIC void GC_register_root_section(ptr_t static_root)
1788 {
1789 MEMORY_BASIC_INFORMATION buf;
1790 size_t result;
1791 DWORD protect;
1792 LPVOID p;
1793 char * base;
1794 char * limit, * new_limit;
1795
1796 if (!GC_no_win32_dlls) return;
1797 p = base = limit = GC_least_described_address(static_root);
1798 while (p < GC_sysinfo.lpMaximumApplicationAddress) {
1799 result = VirtualQuery(p, &buf, sizeof(buf));
1800 if (result != sizeof(buf) || buf.AllocationBase == 0
1801 || GC_is_heap_base(buf.AllocationBase)) break;
1802 new_limit = (char *)p + buf.RegionSize;
1803 protect = buf.Protect;
1804 if (buf.State == MEM_COMMIT
1805 && is_writable(protect)) {
1806 if ((char *)p == limit) {
1807 limit = new_limit;
1808 } else {
1809 if (base != limit) GC_add_roots_inner(base, limit, FALSE);
1810 base = p;
1811 limit = new_limit;
1812 }
1813 }
1814 if (p > (LPVOID)new_limit /* overflow */) break;
1815 p = (LPVOID)new_limit;
1816 }
1817 if (base != limit) GC_add_roots_inner(base, limit, FALSE);
1818 }
1819 #endif /* MSWIN32 */
1820
GC_register_data_segments(void)1821 void GC_register_data_segments(void)
1822 {
1823 # ifdef MSWIN32
1824 static char dummy;
1825 GC_register_root_section((ptr_t)(&dummy));
1826 # endif
1827 }
1828
1829 # else /* !OS2 && !Windows */
1830
1831 # if (defined(SVR4) || defined(AUX) || defined(DGUX) \
1832 || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
GC_SysVGetDataStart(size_t max_page_size,ptr_t etext_addr)1833 ptr_t GC_SysVGetDataStart(size_t max_page_size, ptr_t etext_addr)
1834 {
1835 word text_end = ((word)(etext_addr) + sizeof(word) - 1)
1836 & ~(sizeof(word) - 1);
1837 /* etext rounded to word boundary */
1838 word next_page = ((text_end + (word)max_page_size - 1)
1839 & ~((word)max_page_size - 1));
1840 word page_offset = (text_end & ((word)max_page_size - 1));
1841 volatile char * result = (char *)(next_page + page_offset);
1842 /* Note that this isn't equivalent to just adding */
1843 /* max_page_size to &etext if &etext is at a page boundary */
1844
1845 GC_setup_temporary_fault_handler();
1846 if (SETJMP(GC_jmp_buf) == 0) {
1847 /* Try writing to the address. */
1848 *result = *result;
1849 GC_reset_fault_handler();
1850 } else {
1851 GC_reset_fault_handler();
1852 /* We got here via a longjmp. The address is not readable. */
1853 /* This is known to happen under Solaris 2.4 + gcc, which place */
1854 /* string constants in the text segment, but after etext. */
1855 /* Use plan B. Note that we now know there is a gap between */
1856 /* text and data segments, so plan A bought us something. */
1857 result = (char *)GC_find_limit((ptr_t)(DATAEND), FALSE);
1858 }
1859 return((ptr_t)result);
1860 }
1861 # endif
1862
1863 # if defined(FREEBSD) && !defined(PCR) && (defined(I386) || defined(X86_64) \
1864 || defined(powerpc) || defined(__powerpc__))
1865
1866 /* Its unclear whether this should be identical to the above, or */
1867 /* whether it should apply to non-X86 architectures. */
1868 /* For now we don't assume that there is always an empty page after */
1869 /* etext. But in some cases there actually seems to be slightly more. */
1870 /* This also deals with holes between read-only data and writable data. */
GC_FreeBSDGetDataStart(size_t max_page_size,ptr_t etext_addr)1871 ptr_t GC_FreeBSDGetDataStart(size_t max_page_size, ptr_t etext_addr)
1872 {
1873 word text_end = ((word)(etext_addr) + sizeof(word) - 1)
1874 & ~(sizeof(word) - 1);
1875 /* etext rounded to word boundary */
1876 volatile word next_page = (text_end + (word)max_page_size - 1)
1877 & ~((word)max_page_size - 1);
1878 volatile ptr_t result = (ptr_t)text_end;
1879 GC_setup_temporary_fault_handler();
1880 if (SETJMP(GC_jmp_buf) == 0) {
1881 /* Try reading at the address. */
1882 /* This should happen before there is another thread. */
1883 for (; next_page < (word)(DATAEND); next_page += (word)max_page_size)
1884 *(volatile char *)next_page;
1885 GC_reset_fault_handler();
1886 } else {
1887 GC_reset_fault_handler();
1888 /* As above, we go to plan B */
1889 result = GC_find_limit((ptr_t)(DATAEND), FALSE);
1890 }
1891 return(result);
1892 }
1893
1894 # endif /* FREEBSD */
1895
1896
1897 #ifdef AMIGA
1898
1899 # define GC_AMIGA_DS
1900 # include "extra/AmigaOS.c"
1901 # undef GC_AMIGA_DS
1902
1903 #elif defined(OPENBSD)
1904
1905 /* Depending on arch alignment, there can be multiple holes */
1906 /* between DATASTART and DATAEND. Scan in DATASTART .. DATAEND */
1907 /* and register each region. */
GC_register_data_segments(void)1908 void GC_register_data_segments(void)
1909 {
1910 ptr_t region_start = DATASTART;
1911 ptr_t region_end;
1912
1913 for (;;) {
1914 region_end = GC_find_limit_openbsd(region_start, DATAEND);
1915 GC_add_roots_inner(region_start, region_end, FALSE);
1916 if (region_end >= DATAEND)
1917 break;
1918 region_start = GC_skip_hole_openbsd(region_end, DATAEND);
1919 }
1920 }
1921
1922 # else /* !OS2 && !Windows && !AMIGA && !OPENBSD */
1923
GC_register_data_segments(void)1924 void GC_register_data_segments(void)
1925 {
1926 # if !defined(PCR) && !defined(MACOS)
1927 # if defined(REDIRECT_MALLOC) && defined(GC_SOLARIS_THREADS)
1928 /* As of Solaris 2.3, the Solaris threads implementation */
1929 /* allocates the data structure for the initial thread with */
1930 /* sbrk at process startup. It needs to be scanned, so that */
1931 /* we don't lose some malloc allocated data structures */
1932 /* hanging from it. We're on thin ice here ... */
1933 extern caddr_t sbrk(int);
1934
1935 GC_add_roots_inner(DATASTART, (ptr_t)sbrk(0), FALSE);
1936 # else
1937 GC_add_roots_inner(DATASTART, (ptr_t)(DATAEND), FALSE);
1938 # if defined(DATASTART2)
1939 GC_add_roots_inner(DATASTART2, (ptr_t)(DATAEND2), FALSE);
1940 # endif
1941 # endif
1942 # endif
1943 # if defined(MACOS)
1944 {
1945 # if defined(THINK_C)
1946 extern void* GC_MacGetDataStart(void);
1947 /* globals begin above stack and end at a5. */
1948 GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
1949 (ptr_t)LMGetCurrentA5(), FALSE);
1950 # else
1951 # if defined(__MWERKS__)
1952 # if !__POWERPC__
1953 extern void* GC_MacGetDataStart(void);
1954 /* MATTHEW: Function to handle Far Globals (CW Pro 3) */
1955 # if __option(far_data)
1956 extern void* GC_MacGetDataEnd(void);
1957 # endif
1958 /* globals begin above stack and end at a5. */
1959 GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
1960 (ptr_t)LMGetCurrentA5(), FALSE);
1961 /* MATTHEW: Handle Far Globals */
1962 # if __option(far_data)
1963 /* Far globals follow he QD globals: */
1964 GC_add_roots_inner((ptr_t)LMGetCurrentA5(),
1965 (ptr_t)GC_MacGetDataEnd(), FALSE);
1966 # endif
1967 # else
1968 extern char __data_start__[], __data_end__[];
1969 GC_add_roots_inner((ptr_t)&__data_start__,
1970 (ptr_t)&__data_end__, FALSE);
1971 # endif /* __POWERPC__ */
1972 # endif /* __MWERKS__ */
1973 # endif /* !THINK_C */
1974 }
1975 # endif /* MACOS */
1976
1977 /* Dynamic libraries are added at every collection, since they may */
1978 /* change. */
1979 }
1980
1981 # endif /* ! AMIGA */
1982 # endif /* ! MSWIN32 && ! MSWINCE*/
1983 # endif /* ! OS2 */
1984
1985 /*
1986 * Auxiliary routines for obtaining memory from OS.
1987 */
1988
1989 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \
1990 && !defined(MSWINCE) && !defined(MACOS) && !defined(DOS4GW) \
1991 && !defined(NONSTOP) && !defined(SN_TARGET_PS3) && !defined(RTEMS) \
1992 && !defined(__CC_ARM)
1993
1994 # define SBRK_ARG_T ptrdiff_t
1995
1996 #if defined(MMAP_SUPPORTED)
1997
1998 #ifdef USE_MMAP_FIXED
1999 # define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
2000 /* Seems to yield better performance on Solaris 2, but can */
2001 /* be unreliable if something is already mapped at the address. */
2002 #else
2003 # define GC_MMAP_FLAGS MAP_PRIVATE
2004 #endif
2005
2006 #ifdef USE_MMAP_ANON
2007 # define zero_fd -1
2008 # if defined(MAP_ANONYMOUS)
2009 # define OPT_MAP_ANON MAP_ANONYMOUS
2010 # else
2011 # define OPT_MAP_ANON MAP_ANON
2012 # endif
2013 #else
2014 static int zero_fd;
2015 # define OPT_MAP_ANON 0
2016 #endif
2017
2018 #ifndef HEAP_START
2019 # define HEAP_START ((ptr_t)0)
2020 #endif
2021
GC_unix_mmap_get_mem(word bytes)2022 STATIC ptr_t GC_unix_mmap_get_mem(word bytes)
2023 {
2024 void *result;
2025 static ptr_t last_addr = HEAP_START;
2026
2027 # ifndef USE_MMAP_ANON
2028 static GC_bool initialized = FALSE;
2029
2030 if (!initialized) {
2031 zero_fd = open("/dev/zero", O_RDONLY);
2032 fcntl(zero_fd, F_SETFD, FD_CLOEXEC);
2033 initialized = TRUE;
2034 }
2035 # endif
2036
2037 if (bytes & (GC_page_size - 1)) ABORT("Bad GET_MEM arg");
2038 result = mmap(last_addr, bytes, (PROT_READ | PROT_WRITE)
2039 | (GC_pages_executable ? PROT_EXEC : 0),
2040 GC_MMAP_FLAGS | OPT_MAP_ANON, zero_fd, 0/* offset */);
2041 # undef IGNORE_PAGES_EXECUTABLE
2042
2043 if (result == MAP_FAILED) return(0);
2044 last_addr = (ptr_t)result + bytes + GC_page_size - 1;
2045 last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
2046 # if !defined(LINUX)
2047 if (last_addr == 0) {
2048 /* Oops. We got the end of the address space. This isn't */
2049 /* usable by arbitrary C code, since one-past-end pointers */
2050 /* don't work, so we discard it and try again. */
2051 munmap(result, (size_t)(-GC_page_size) - (size_t)result);
2052 /* Leave last page mapped, so we can't repeat. */
2053 return GC_unix_mmap_get_mem(bytes);
2054 }
2055 # else
2056 GC_ASSERT(last_addr != 0);
2057 # endif
2058 return((ptr_t)result);
2059 }
2060
2061 # endif /* MMAP_SUPPORTED */
2062
2063 #if defined(USE_MMAP)
GC_unix_get_mem(word bytes)2064 ptr_t GC_unix_get_mem(word bytes)
2065 {
2066 return GC_unix_mmap_get_mem(bytes);
2067 }
2068 #else /* !USE_MMAP */
2069
GC_unix_sbrk_get_mem(word bytes)2070 STATIC ptr_t GC_unix_sbrk_get_mem(word bytes)
2071 {
2072 ptr_t result;
2073 # ifdef IRIX5
2074 /* Bare sbrk isn't thread safe. Play by malloc rules. */
2075 /* The equivalent may be needed on other systems as well. */
2076 __LOCK_MALLOC();
2077 # endif
2078 {
2079 ptr_t cur_brk = (ptr_t)sbrk(0);
2080 SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
2081
2082 if ((SBRK_ARG_T)bytes < 0) {
2083 result = 0; /* too big */
2084 goto out;
2085 }
2086 if (lsbs != 0) {
2087 if((ptr_t)sbrk(GC_page_size - lsbs) == (ptr_t)(-1)) {
2088 result = 0;
2089 goto out;
2090 }
2091 }
2092 # ifdef ADD_HEAP_GUARD_PAGES
2093 /* This is useful for catching severe memory overwrite problems that */
2094 /* span heap sections. It shouldn't otherwise be turned on. */
2095 {
2096 ptr_t guard = (ptr_t)sbrk((SBRK_ARG_T)GC_page_size);
2097 if (mprotect(guard, GC_page_size, PROT_NONE) != 0)
2098 ABORT("ADD_HEAP_GUARD_PAGES: mprotect failed");
2099 }
2100 # endif /* ADD_HEAP_GUARD_PAGES */
2101 result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
2102 if (result == (ptr_t)(-1)) result = 0;
2103 }
2104 out:
2105 # ifdef IRIX5
2106 __UNLOCK_MALLOC();
2107 # endif
2108 return(result);
2109 }
2110
GC_unix_get_mem(word bytes)2111 ptr_t GC_unix_get_mem(word bytes)
2112 {
2113 # if defined(MMAP_SUPPORTED)
2114 /* By default, we try both sbrk and mmap, in that order. */
2115 static GC_bool sbrk_failed = FALSE;
2116 ptr_t result = 0;
2117
2118 if (!sbrk_failed) result = GC_unix_sbrk_get_mem(bytes);
2119 if (0 == result) {
2120 sbrk_failed = TRUE;
2121 result = GC_unix_mmap_get_mem(bytes);
2122 }
2123 if (0 == result) {
2124 /* Try sbrk again, in case sbrk memory became available. */
2125 result = GC_unix_sbrk_get_mem(bytes);
2126 }
2127 return result;
2128 # else /* !MMAP_SUPPORTED */
2129 return GC_unix_sbrk_get_mem(bytes);
2130 # endif
2131 }
2132
2133 #endif /* !USE_MMAP */
2134
2135 # endif /* UN*X */
2136
2137 # ifdef OS2
2138
os2_alloc(size_t bytes)2139 void * os2_alloc(size_t bytes)
2140 {
2141 void * result;
2142
2143 if (DosAllocMem(&result, bytes, (PAG_READ | PAG_WRITE | PAG_COMMIT)
2144 | (GC_pages_executable ? PAG_EXECUTE : 0))
2145 != NO_ERROR) {
2146 return(0);
2147 }
2148 /* FIXME: What's the purpose of this recursion? (Probably, if */
2149 /* DosAllocMem returns memory at 0 address then just retry once.) */
2150 if (result == 0) return(os2_alloc(bytes));
2151 return(result);
2152 }
2153
2154 # endif /* OS2 */
2155
2156 # if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
2157 GC_INNER SYSTEM_INFO GC_sysinfo;
2158 # endif
2159
2160 #ifdef MSWIN32
2161
2162 # ifdef USE_GLOBAL_ALLOC
2163 # define GLOBAL_ALLOC_TEST 1
2164 # else
2165 # define GLOBAL_ALLOC_TEST GC_no_win32_dlls
2166 # endif
2167
2168 # ifdef GC_USE_MEM_TOP_DOWN
2169 STATIC DWORD GC_mem_top_down = MEM_TOP_DOWN;
2170 /* Use GC_USE_MEM_TOP_DOWN for better 64-bit */
2171 /* testing. Otherwise all addresses tend to */
2172 /* end up in first 4GB, hiding bugs. */
2173 # else
2174 STATIC DWORD GC_mem_top_down = 0;
2175 # endif
2176
2177 #endif /* MSWIN32 */
2178
2179 #if defined(MSWIN32) || defined(CYGWIN32)
GC_win32_get_mem(word bytes)2180 ptr_t GC_win32_get_mem(word bytes)
2181 {
2182 ptr_t result;
2183
2184 # ifdef CYGWIN32
2185 result = GC_unix_get_mem(bytes);
2186 # else
2187 if (GLOBAL_ALLOC_TEST) {
2188 /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE. */
2189 /* There are also unconfirmed rumors of other */
2190 /* problems, so we dodge the issue. */
2191 result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);
2192 result = (ptr_t)(((word)result + HBLKSIZE - 1) & ~(HBLKSIZE-1));
2193 } else {
2194 /* VirtualProtect only works on regions returned by a */
2195 /* single VirtualAlloc call. Thus we allocate one */
2196 /* extra page, which will prevent merging of blocks */
2197 /* in separate regions, and eliminate any temptation */
2198 /* to call VirtualProtect on a range spanning regions. */
2199 /* This wastes a small amount of memory, and risks */
2200 /* increased fragmentation. But better alternatives */
2201 /* would require effort. */
2202 # ifdef MPROTECT_VDB
2203 /* We can't check for GC_incremental here (because */
2204 /* GC_enable_incremental() might be called some time */
2205 /* later after the GC initialization). */
2206 # ifdef GWW_VDB
2207 # define VIRTUAL_ALLOC_PAD (GC_GWW_AVAILABLE() ? 0 : 1)
2208 # else
2209 # define VIRTUAL_ALLOC_PAD 1
2210 # endif
2211 # else
2212 # define VIRTUAL_ALLOC_PAD 0
2213 # endif
2214 /* Pass the MEM_WRITE_WATCH only if GetWriteWatch-based */
2215 /* VDBs are enabled and the GetWriteWatch function is */
2216 /* available. Otherwise we waste resources or possibly */
2217 /* cause VirtualAlloc to fail (observed in Windows 2000 */
2218 /* SP2). */
2219 result = (ptr_t) VirtualAlloc(NULL, bytes + VIRTUAL_ALLOC_PAD,
2220 GetWriteWatch_alloc_flag
2221 | (MEM_COMMIT | MEM_RESERVE)
2222 | GC_mem_top_down,
2223 GC_pages_executable ? PAGE_EXECUTE_READWRITE :
2224 PAGE_READWRITE);
2225 # undef IGNORE_PAGES_EXECUTABLE
2226 }
2227 # endif /* !CYGWIN32 */
2228 if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
2229 /* If I read the documentation correctly, this can */
2230 /* only happen if HBLKSIZE > 64k or not a power of 2. */
2231 if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
2232 if (0 != result) GC_heap_bases[GC_n_heap_bases++] = result;
2233 return(result);
2234 }
2235
GC_win32_free_heap(void)2236 GC_API void GC_CALL GC_win32_free_heap(void)
2237 {
2238 # ifndef CYGWIN32
2239 if (GC_no_win32_dlls)
2240 # endif
2241 {
2242 while (GC_n_heap_bases-- > 0) {
2243 # ifdef CYGWIN32
2244 /* FIXME: Is it ok to use non-GC free() here? */
2245 # else
2246 GlobalFree(GC_heap_bases[GC_n_heap_bases]);
2247 # endif
2248 GC_heap_bases[GC_n_heap_bases] = 0;
2249 }
2250 }
2251 }
2252 #endif /* MSWIN32 || CYGWIN32 */
2253
2254 #ifdef AMIGA
2255 # define GC_AMIGA_AM
2256 # include "extra/AmigaOS.c"
2257 # undef GC_AMIGA_AM
2258 #endif
2259
2260
2261 #ifdef MSWINCE
GC_wince_get_mem(word bytes)2262 ptr_t GC_wince_get_mem(word bytes)
2263 {
2264 ptr_t result = 0; /* initialized to prevent warning. */
2265 word i;
2266
2267 /* Round up allocation size to multiple of page size */
2268 bytes = (bytes + GC_page_size-1) & ~(GC_page_size-1);
2269
2270 /* Try to find reserved, uncommitted pages */
2271 for (i = 0; i < GC_n_heap_bases; i++) {
2272 if (((word)(-(signed_word)GC_heap_lengths[i])
2273 & (GC_sysinfo.dwAllocationGranularity-1))
2274 >= bytes) {
2275 result = GC_heap_bases[i] + GC_heap_lengths[i];
2276 break;
2277 }
2278 }
2279
2280 if (i == GC_n_heap_bases) {
2281 /* Reserve more pages */
2282 word res_bytes = (bytes + GC_sysinfo.dwAllocationGranularity-1)
2283 & ~(GC_sysinfo.dwAllocationGranularity-1);
2284 /* If we ever support MPROTECT_VDB here, we will probably need to */
2285 /* ensure that res_bytes is strictly > bytes, so that VirtualProtect */
2286 /* never spans regions. It seems to be OK for a VirtualFree */
2287 /* argument to span regions, so we should be OK for now. */
2288 result = (ptr_t) VirtualAlloc(NULL, res_bytes,
2289 MEM_RESERVE | MEM_TOP_DOWN,
2290 GC_pages_executable ? PAGE_EXECUTE_READWRITE :
2291 PAGE_READWRITE);
2292 if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
2293 /* If I read the documentation correctly, this can */
2294 /* only happen if HBLKSIZE > 64k or not a power of 2. */
2295 if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
2296 if (result == NULL) return NULL;
2297 GC_heap_bases[GC_n_heap_bases] = result;
2298 GC_heap_lengths[GC_n_heap_bases] = 0;
2299 GC_n_heap_bases++;
2300 }
2301
2302 /* Commit pages */
2303 result = (ptr_t) VirtualAlloc(result, bytes, MEM_COMMIT,
2304 GC_pages_executable ? PAGE_EXECUTE_READWRITE :
2305 PAGE_READWRITE);
2306 # undef IGNORE_PAGES_EXECUTABLE
2307
2308 if (result != NULL) {
2309 if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
2310 GC_heap_lengths[i] += bytes;
2311 }
2312
2313 return(result);
2314 }
2315 #endif
2316
2317 #ifdef USE_MUNMAP
2318
2319 /* For now, this only works on Win32/WinCE and some Unix-like */
2320 /* systems. If you have something else, don't define */
2321 /* USE_MUNMAP. */
2322
2323 #if !defined(MSWIN32) && !defined(MSWINCE)
2324
2325 #include <unistd.h>
2326 #include <sys/mman.h>
2327 #include <sys/stat.h>
2328 #include <sys/types.h>
2329
2330 #endif
2331
2332 /* Compute a page aligned starting address for the unmap */
2333 /* operation on a block of size bytes starting at start. */
2334 /* Return 0 if the block is too small to make this feasible. */
GC_unmap_start(ptr_t start,size_t bytes)2335 STATIC ptr_t GC_unmap_start(ptr_t start, size_t bytes)
2336 {
2337 ptr_t result;
2338 /* Round start to next page boundary. */
2339 result = (ptr_t)((word)(start + GC_page_size - 1) & ~(GC_page_size - 1));
2340 if (result + GC_page_size > start + bytes) return 0;
2341 return result;
2342 }
2343
2344 /* Compute end address for an unmap operation on the indicated */
2345 /* block. */
GC_unmap_end(ptr_t start,size_t bytes)2346 STATIC ptr_t GC_unmap_end(ptr_t start, size_t bytes)
2347 {
2348 return (ptr_t)((word)(start + bytes) & ~(GC_page_size - 1));
2349 }
2350
2351 /* Under Win32/WinCE we commit (map) and decommit (unmap) */
2352 /* memory using VirtualAlloc and VirtualFree. These functions */
2353 /* work on individual allocations of virtual memory, made */
2354 /* previously using VirtualAlloc with the MEM_RESERVE flag. */
2355 /* The ranges we need to (de)commit may span several of these */
2356 /* allocations; therefore we use VirtualQuery to check */
2357 /* allocation lengths, and split up the range as necessary. */
2358
2359 /* We assume that GC_remap is called on exactly the same range */
2360 /* as a previous call to GC_unmap. It is safe to consistently */
2361 /* round the endpoints in both places. */
GC_unmap(ptr_t start,size_t bytes)2362 GC_INNER void GC_unmap(ptr_t start, size_t bytes)
2363 {
2364 ptr_t start_addr = GC_unmap_start(start, bytes);
2365 ptr_t end_addr = GC_unmap_end(start, bytes);
2366 word len = end_addr - start_addr;
2367 if (0 == start_addr) return;
2368 # if defined(MSWIN32) || defined(MSWINCE)
2369 while (len != 0) {
2370 MEMORY_BASIC_INFORMATION mem_info;
2371 GC_word free_len;
2372 if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
2373 != sizeof(mem_info))
2374 ABORT("Weird VirtualQuery result");
2375 free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
2376 if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
2377 ABORT("VirtualFree failed");
2378 GC_unmapped_bytes += free_len;
2379 start_addr += free_len;
2380 len -= free_len;
2381 }
2382 # else
2383 /* We immediately remap it to prevent an intervening mmap from */
2384 /* accidentally grabbing the same address space. */
2385 {
2386 void * result;
2387 result = mmap(start_addr, len, PROT_NONE,
2388 MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
2389 zero_fd, 0/* offset */);
2390 if (result != (void *)start_addr)
2391 ABORT("mmap(PROT_NONE) failed");
2392 }
2393 GC_unmapped_bytes += len;
2394 # endif
2395 }
2396
GC_remap(ptr_t start,size_t bytes)2397 GC_INNER void GC_remap(ptr_t start, size_t bytes)
2398 {
2399 ptr_t start_addr = GC_unmap_start(start, bytes);
2400 ptr_t end_addr = GC_unmap_end(start, bytes);
2401 word len = end_addr - start_addr;
2402
2403 /* FIXME: Handle out-of-memory correctly (at least for Win32) */
2404 # if defined(MSWIN32) || defined(MSWINCE)
2405 ptr_t result;
2406
2407 if (0 == start_addr) return;
2408 while (len != 0) {
2409 MEMORY_BASIC_INFORMATION mem_info;
2410 GC_word alloc_len;
2411 if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
2412 != sizeof(mem_info))
2413 ABORT("Weird VirtualQuery result");
2414 alloc_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
2415 result = VirtualAlloc(start_addr, alloc_len, MEM_COMMIT,
2416 GC_pages_executable ? PAGE_EXECUTE_READWRITE :
2417 PAGE_READWRITE);
2418 if (result != start_addr) {
2419 if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
2420 GetLastError() == ERROR_OUTOFMEMORY) {
2421 ABORT("Not enough memory to process remapping");
2422 } else {
2423 ABORT("VirtualAlloc remapping failed");
2424 }
2425 }
2426 GC_unmapped_bytes -= alloc_len;
2427 start_addr += alloc_len;
2428 len -= alloc_len;
2429 }
2430 # else
2431 /* It was already remapped with PROT_NONE. */
2432 int result;
2433 if (0 == start_addr) return;
2434
2435 # ifndef NACL
2436 result = mprotect(start_addr, len, (PROT_READ | PROT_WRITE)
2437 | (GC_pages_executable ? PROT_EXEC : 0));
2438 # else
2439 {
2440 /* NaCl does not expose mprotect, but mmap should work fine. */
2441 void *mmap_result = mmap(start_addr, len, (PROT_READ | PROT_WRITE)
2442 | (GC_pages_executable ? PROT_EXEC : 0),
2443 MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
2444 zero_fd, 0 /* offset */);
2445 if (mmap_result != (void *)start_addr)
2446 ABORT("mmap as mprotect failed");
2447 /* Fake the return value as if mprotect succeeded. */
2448 result = 0;
2449 }
2450 # endif /* NACL */
2451 # undef IGNORE_PAGES_EXECUTABLE
2452
2453 if (result != 0) {
2454 if (GC_print_stats)
2455 GC_log_printf("Mprotect failed at %p (length %lu) with errno %d\n",
2456 start_addr, (unsigned long)len, errno);
2457 ABORT("mprotect remapping failed");
2458 }
2459 GC_unmapped_bytes -= len;
2460 # endif
2461 }
2462
2463 /* Two adjacent blocks have already been unmapped and are about to */
2464 /* be merged. Unmap the whole block. This typically requires */
2465 /* that we unmap a small section in the middle that was not previously */
2466 /* unmapped due to alignment constraints. */
GC_unmap_gap(ptr_t start1,size_t bytes1,ptr_t start2,size_t bytes2)2467 GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2,
2468 size_t bytes2)
2469 {
2470 ptr_t start1_addr = GC_unmap_start(start1, bytes1);
2471 ptr_t end1_addr = GC_unmap_end(start1, bytes1);
2472 ptr_t start2_addr = GC_unmap_start(start2, bytes2);
2473 ptr_t start_addr = end1_addr;
2474 ptr_t end_addr = start2_addr;
2475 size_t len;
2476 GC_ASSERT(start1 + bytes1 == start2);
2477 if (0 == start1_addr) start_addr = GC_unmap_start(start1, bytes1 + bytes2);
2478 if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2);
2479 if (0 == start_addr) return;
2480 len = end_addr - start_addr;
2481 # if defined(MSWIN32) || defined(MSWINCE)
2482 while (len != 0) {
2483 MEMORY_BASIC_INFORMATION mem_info;
2484 GC_word free_len;
2485 if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
2486 != sizeof(mem_info))
2487 ABORT("Weird VirtualQuery result");
2488 free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
2489 if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
2490 ABORT("VirtualFree failed");
2491 GC_unmapped_bytes += free_len;
2492 start_addr += free_len;
2493 len -= free_len;
2494 }
2495 # else
2496 if (len != 0) {
2497 /* Immediately remap as above. */
2498 void * result;
2499 result = mmap(start_addr, len, PROT_NONE,
2500 MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
2501 zero_fd, 0/* offset */);
2502 if (result != (void *)start_addr)
2503 ABORT("mmap(PROT_NONE) failed");
2504 }
2505 GC_unmapped_bytes += len;
2506 # endif
2507 }
2508
2509 #endif /* USE_MUNMAP */
2510
2511 /* Routine for pushing any additional roots. In THREADS */
2512 /* environment, this is also responsible for marking from */
2513 /* thread stacks. */
2514 #ifndef THREADS
2515 GC_INNER void (*GC_push_other_roots)(void) = 0;
2516 #else /* THREADS */
2517
2518 # ifdef PCR
GC_push_thread_stack(PCR_Th_T * t,PCR_Any dummy)2519 PCR_ERes GC_push_thread_stack(PCR_Th_T *t, PCR_Any dummy)
2520 {
2521 struct PCR_ThCtl_TInfoRep info;
2522 PCR_ERes result;
2523
2524 info.ti_stkLow = info.ti_stkHi = 0;
2525 result = PCR_ThCtl_GetInfo(t, &info);
2526 GC_push_all_stack((ptr_t)(info.ti_stkLow), (ptr_t)(info.ti_stkHi));
2527 return(result);
2528 }
2529
2530 /* Push the contents of an old object. We treat this as stack */
2531 /* data only because that makes it robust against mark stack */
2532 /* overflow. */
GC_push_old_obj(void * p,size_t size,PCR_Any data)2533 PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any data)
2534 {
2535 GC_push_all_stack((ptr_t)p, (ptr_t)p + size);
2536 return(PCR_ERes_okay);
2537 }
2538
2539 extern struct PCR_MM_ProcsRep * GC_old_allocator;
2540 /* defined in pcr_interface.c. */
2541
GC_default_push_other_roots(void)2542 STATIC void GC_default_push_other_roots(void)
2543 {
2544 /* Traverse data allocated by previous memory managers. */
2545 if ((*(GC_old_allocator->mmp_enumerate))(PCR_Bool_false,
2546 GC_push_old_obj, 0)
2547 != PCR_ERes_okay) {
2548 ABORT("Old object enumeration failed");
2549 }
2550 /* Traverse all thread stacks. */
2551 if (PCR_ERes_IsErr(
2552 PCR_ThCtl_ApplyToAllOtherThreads(GC_push_thread_stack,0))
2553 || PCR_ERes_IsErr(GC_push_thread_stack(PCR_Th_CurrThread(), 0))) {
2554 ABORT("Thread stack marking failed");
2555 }
2556 }
2557
2558 # endif /* PCR */
2559
2560
2561 # if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
2562
2563 GC_INNER void GC_push_all_stacks(void);
2564
GC_default_push_other_roots(void)2565 STATIC void GC_default_push_other_roots(void)
2566 {
2567 GC_push_all_stacks();
2568 }
2569
2570 # endif /* GC_WIN32_THREADS || GC_PTHREADS */
2571
2572 # ifdef SN_TARGET_PS3
GC_default_push_other_roots(void)2573 STATIC void GC_default_push_other_roots(void)
2574 {
2575 ABORT("GC_default_push_other_roots is not implemented");
2576 }
2577
GC_push_thread_structures(void)2578 void GC_push_thread_structures(void)
2579 {
2580 ABORT("GC_push_thread_structures is not implemented");
2581 }
2582 # endif /* SN_TARGET_PS3 */
2583
2584 GC_INNER void (*GC_push_other_roots)(void) = GC_default_push_other_roots;
2585 #endif /* THREADS */
2586
2587 /*
2588 * Routines for accessing dirty bits on virtual pages.
2589 * There are six ways to maintain this information:
2590 * DEFAULT_VDB: A simple dummy implementation that treats every page
2591 * as possibly dirty. This makes incremental collection
2592 * useless, but the implementation is still correct.
2593 * MANUAL_VDB: Stacks and static data are always considered dirty.
2594 * Heap pages are considered dirty if GC_dirty(p) has been
2595 * called on some pointer p pointing to somewhere inside
2596 * an object on that page. A GC_dirty() call on a large
2597 * object directly dirties only a single page, but for
2598 * MANUAL_VDB we are careful to treat an object with a dirty
2599 * page as completely dirty.
2600 * In order to avoid races, an object must be marked dirty
2601 * after it is written, and a reference to the object
2602 * must be kept on a stack or in a register in the interim.
2603 * With threads enabled, an object directly reachable from the
2604 * stack at the time of a collection is treated as dirty.
2605 * In single-threaded mode, it suffices to ensure that no
2606 * collection can take place between the pointer assignment
2607 * and the GC_dirty() call.
2608 * PCR_VDB: Use PPCRs virtual dirty bit facility.
2609 * PROC_VDB: Use the /proc facility for reading dirty bits. Only
2610 * works under some SVR4 variants. Even then, it may be
2611 * too slow to be entirely satisfactory. Requires reading
2612 * dirty bits for entire address space. Implementations tend
2613 * to assume that the client is a (slow) debugger.
2614 * MPROTECT_VDB:Protect pages and then catch the faults to keep track of
2615 * dirtied pages. The implementation (and implementability)
2616 * is highly system dependent. This usually fails when system
2617 * calls write to a protected page. We prevent the read system
2618 * call from doing so. It is the clients responsibility to
2619 * make sure that other system calls are similarly protected
2620 * or write only to the stack.
2621 * GWW_VDB: Use the Win32 GetWriteWatch functions, if available, to
2622 * read dirty bits. In case it is not available (because we
2623 * are running on Windows 95, Windows 2000 or earlier),
2624 * MPROTECT_VDB may be defined as a fallback strategy.
2625 */
2626 #ifndef GC_DISABLE_INCREMENTAL
2627 GC_INNER GC_bool GC_dirty_maintained = FALSE;
2628 #endif
2629
2630 #if defined(PROC_VDB) || defined(GWW_VDB)
2631 /* Add all pages in pht2 to pht1 */
GC_or_pages(page_hash_table pht1,page_hash_table pht2)2632 STATIC void GC_or_pages(page_hash_table pht1, page_hash_table pht2)
2633 {
2634 register int i;
2635 for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
2636 }
2637
2638 # ifdef MPROTECT_VDB
GC_gww_page_was_dirty(struct hblk * h)2639 STATIC GC_bool GC_gww_page_was_dirty(struct hblk * h)
2640 # else
2641 GC_INNER GC_bool GC_page_was_dirty(struct hblk * h)
2642 # endif
2643 {
2644 register word index;
2645 if (HDR(h) == 0)
2646 return TRUE;
2647 index = PHT_HASH(h);
2648 return get_pht_entry_from_index(GC_grungy_pages, index);
2649 }
2650
2651 # if defined(CHECKSUMS) || defined(PROC_VDB)
2652 /* Used only if GWW_VDB. */
2653 # ifdef MPROTECT_VDB
GC_gww_page_was_ever_dirty(struct hblk * h)2654 STATIC GC_bool GC_gww_page_was_ever_dirty(struct hblk * h)
2655 # else
2656 GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h)
2657 # endif
2658 {
2659 register word index;
2660 if (HDR(h) == 0)
2661 return TRUE;
2662 index = PHT_HASH(h);
2663 return get_pht_entry_from_index(GC_written_pages, index);
2664 }
2665 # endif /* CHECKSUMS || PROC_VDB */
2666
2667 # ifndef MPROTECT_VDB
2668 /* Ignore write hints. They don't help us here. */
2669 /*ARGSUSED*/
GC_remove_protection(struct hblk * h,word nblocks,GC_bool is_ptrfree)2670 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
2671 GC_bool is_ptrfree) {}
2672 # endif
2673
2674 #endif /* PROC_VDB || GWW_VDB */
2675
2676 #ifdef GWW_VDB
2677
2678 # define GC_GWW_BUF_LEN (MAXHINCR * HBLKSIZE / 4096 /* X86 page size */)
2679 /* Still susceptible to overflow, if there are very large allocations, */
2680 /* and everything is dirty. */
2681 static PVOID gww_buf[GC_GWW_BUF_LEN];
2682
2683 # ifdef MPROTECT_VDB
GC_gww_dirty_init(void)2684 GC_INNER GC_bool GC_gww_dirty_init(void)
2685 {
2686 detect_GetWriteWatch();
2687 return GC_GWW_AVAILABLE();
2688 }
2689 # else
GC_dirty_init(void)2690 GC_INNER void GC_dirty_init(void)
2691 {
2692 detect_GetWriteWatch();
2693 GC_dirty_maintained = GC_GWW_AVAILABLE();
2694 }
2695 # endif /* !MPROTECT_VDB */
2696
2697 # ifdef MPROTECT_VDB
GC_gww_read_dirty(void)2698 STATIC void GC_gww_read_dirty(void)
2699 # else
2700 GC_INNER void GC_read_dirty(void)
2701 # endif
2702 {
2703 word i;
2704
2705 BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
2706
2707 for (i = 0; i != GC_n_heap_sects; ++i) {
2708 GC_ULONG_PTR count;
2709
2710 do {
2711 PVOID * pages, * pages_end;
2712 DWORD page_size;
2713
2714 pages = gww_buf;
2715 count = GC_GWW_BUF_LEN;
2716 /* GetWriteWatch is documented as returning non-zero when it */
2717 /* fails, but the documentation doesn't explicitly say why it */
2718 /* would fail or what its behaviour will be if it fails. */
2719 /* It does appear to fail, at least on recent W2K instances, if */
2720 /* the underlying memory was not allocated with the appropriate */
2721 /* flag. This is common if GC_enable_incremental is called */
2722 /* shortly after GC initialization. To avoid modifying the */
2723 /* interface, we silently work around such a failure, it only */
2724 /* affects the initial (small) heap allocation. If there are */
2725 /* more dirty pages than will fit in the buffer, this is not */
2726 /* treated as a failure; we must check the page count in the */
2727 /* loop condition. Since each partial call will reset the */
2728 /* status of some pages, this should eventually terminate even */
2729 /* in the overflow case. */
2730 if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
2731 GC_heap_sects[i].hs_start,
2732 GC_heap_sects[i].hs_bytes,
2733 pages,
2734 &count,
2735 &page_size) != 0) {
2736 static int warn_count = 0;
2737 unsigned j;
2738 struct hblk * start = (struct hblk *)GC_heap_sects[i].hs_start;
2739 static struct hblk *last_warned = 0;
2740 size_t nblocks = divHBLKSZ(GC_heap_sects[i].hs_bytes);
2741
2742 if ( i != 0 && last_warned != start && warn_count++ < 5) {
2743 last_warned = start;
2744 WARN(
2745 "GC_gww_read_dirty unexpectedly failed at %p: "
2746 "Falling back to marking all pages dirty\n", start);
2747 }
2748 for (j = 0; j < nblocks; ++j) {
2749 word hash = PHT_HASH(start + j);
2750 set_pht_entry_from_index(GC_grungy_pages, hash);
2751 }
2752 count = 1; /* Done with this section. */
2753 } else /* succeeded */ {
2754 pages_end = pages + count;
2755 while (pages != pages_end) {
2756 struct hblk * h = (struct hblk *) *pages++;
2757 struct hblk * h_end = (struct hblk *) ((char *) h + page_size);
2758 do
2759 set_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
2760 while (++h < h_end);
2761 }
2762 }
2763 } while (count == GC_GWW_BUF_LEN);
2764 /* FIXME: It's unclear from Microsoft's documentation if this loop */
2765 /* is useful. We suspect the call just fails if the buffer fills */
2766 /* up. But that should still be handled correctly. */
2767 }
2768
2769 GC_or_pages(GC_written_pages, GC_grungy_pages);
2770 }
2771 #endif /* GWW_VDB */
2772
2773 #ifdef DEFAULT_VDB
2774 /* All of the following assume the allocation lock is held. */
2775
2776 /* The client asserts that unallocated pages in the heap are never */
2777 /* written. */
2778
2779 /* Initialize virtual dirty bit implementation. */
GC_dirty_init(void)2780 GC_INNER void GC_dirty_init(void)
2781 {
2782 if (GC_print_stats == VERBOSE)
2783 GC_log_printf("Initializing DEFAULT_VDB...\n");
2784 GC_dirty_maintained = TRUE;
2785 }
2786
2787 /* Retrieve system dirty bits for heap to a local buffer. */
2788 /* Restore the systems notion of which pages are dirty. */
GC_read_dirty(void)2789 GC_INNER void GC_read_dirty(void) {}
2790
2791 /* Is the HBLKSIZE sized page at h marked dirty in the local buffer? */
2792 /* If the actual page size is different, this returns TRUE if any */
2793 /* of the pages overlapping h are dirty. This routine may err on the */
2794 /* side of labeling pages as dirty (and this implementation does). */
2795 /*ARGSUSED*/
GC_page_was_dirty(struct hblk * h)2796 GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
2797 {
2798 return(TRUE);
2799 }
2800
2801 /* The following two routines are typically less crucial. */
2802 /* They matter most with large dynamic libraries, or if we can't */
2803 /* accurately identify stacks, e.g. under Solaris 2.X. Otherwise the */
2804 /* following default versions are adequate. */
2805 # ifdef CHECKSUMS
2806 /* Could any valid GC heap pointer ever have been written to this page? */
2807 /*ARGSUSED*/
GC_page_was_ever_dirty(struct hblk * h)2808 GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h)
2809 {
2810 return(TRUE);
2811 }
2812 # endif /* CHECKSUMS */
2813
2814 /* A call that: */
2815 /* I) hints that [h, h+nblocks) is about to be written. */
2816 /* II) guarantees that protection is removed. */
2817 /* (I) may speed up some dirty bit implementations. */
2818 /* (II) may be essential if we need to ensure that */
2819 /* pointer-free system call buffers in the heap are */
2820 /* not protected. */
2821 /*ARGSUSED*/
GC_remove_protection(struct hblk * h,word nblocks,GC_bool is_ptrfree)2822 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
2823 GC_bool is_ptrfree) {}
2824 #endif /* DEFAULT_VDB */
2825
2826 #ifdef MANUAL_VDB
2827 /* Initialize virtual dirty bit implementation. */
GC_dirty_init(void)2828 GC_INNER void GC_dirty_init(void)
2829 {
2830 if (GC_print_stats == VERBOSE)
2831 GC_log_printf("Initializing MANUAL_VDB...\n");
2832 /* GC_dirty_pages and GC_grungy_pages are already cleared. */
2833 GC_dirty_maintained = TRUE;
2834 }
2835
2836 /* Retrieve system dirty bits for heap to a local buffer. */
2837 /* Restore the systems notion of which pages are dirty. */
GC_read_dirty(void)2838 GC_INNER void GC_read_dirty(void)
2839 {
2840 BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
2841 (sizeof GC_dirty_pages));
2842 BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
2843 }
2844
2845 /* Is the HBLKSIZE sized page at h marked dirty in the local buffer? */
2846 /* If the actual page size is different, this returns TRUE if any */
2847 /* of the pages overlapping h are dirty. This routine may err on the */
2848 /* side of labeling pages as dirty (and this implementation does). */
GC_page_was_dirty(struct hblk * h)2849 GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
2850 {
2851 register word index = PHT_HASH(h);
2852 return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
2853 }
2854
2855 # define async_set_pht_entry_from_index(db, index) \
2856 set_pht_entry_from_index(db, index) /* for now */
2857
2858 /* Mark the page containing p as dirty. Logically, this dirties the */
2859 /* entire object. */
GC_dirty(ptr_t p)2860 void GC_dirty(ptr_t p)
2861 {
2862 word index = PHT_HASH(p);
2863 async_set_pht_entry_from_index(GC_dirty_pages, index);
2864 }
2865
2866 /*ARGSUSED*/
GC_remove_protection(struct hblk * h,word nblocks,GC_bool is_ptrfree)2867 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
2868 GC_bool is_ptrfree) {}
2869
2870 # ifdef CHECKSUMS
2871 /* Could any valid GC heap pointer ever have been written to this page? */
2872 /*ARGSUSED*/
GC_page_was_ever_dirty(struct hblk * h)2873 GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h)
2874 {
2875 /* FIXME - implement me. */
2876 return(TRUE);
2877 }
2878 # endif /* CHECKSUMS */
2879
2880 #endif /* MANUAL_VDB */
2881
2882 #ifdef MPROTECT_VDB
2883 /* See DEFAULT_VDB for interface descriptions. */
2884
2885 /*
2886 * This implementation maintains dirty bits itself by catching write
2887 * faults and keeping track of them. We assume nobody else catches
2888 * SIGBUS or SIGSEGV. We assume no write faults occur in system calls.
2889 * This means that clients must ensure that system calls don't write
2890 * to the write-protected heap. Probably the best way to do this is to
2891 * ensure that system calls write at most to POINTERFREE objects in the
2892 * heap, and do even that only if we are on a platform on which those
2893 * are not protected. Another alternative is to wrap system calls
2894 * (see example for read below), but the current implementation holds
2895 * applications.
2896 * We assume the page size is a multiple of HBLKSIZE.
2897 * We prefer them to be the same. We avoid protecting POINTERFREE
2898 * objects only if they are the same.
2899 */
2900 # ifdef DARWIN
2901 /* Using vm_protect (mach syscall) over mprotect (BSD syscall) seems to
2902 decrease the likelihood of some of the problems described below. */
2903 # include <mach/vm_map.h>
2904 STATIC mach_port_t GC_task_self = 0;
2905 # define PROTECT(addr,len) \
2906 if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
2907 FALSE, VM_PROT_READ \
2908 | (GC_pages_executable ? VM_PROT_EXECUTE : 0)) \
2909 != KERN_SUCCESS) { \
2910 ABORT("vm_protect(PROTECT) failed"); \
2911 }
2912 # define UNPROTECT(addr,len) \
2913 if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
2914 FALSE, (VM_PROT_READ | VM_PROT_WRITE) \
2915 | (GC_pages_executable ? VM_PROT_EXECUTE : 0)) \
2916 != KERN_SUCCESS) { \
2917 ABORT("vm_protect(UNPROTECT) failed"); \
2918 }
2919
2920 # elif !defined(MSWIN32) && !defined(MSWINCE)
2921 # include <sys/mman.h>
2922 # include <signal.h>
2923 # include <sys/syscall.h>
2924
2925 # define PROTECT(addr, len) \
2926 if (mprotect((caddr_t)(addr), (size_t)(len), \
2927 PROT_READ \
2928 | (GC_pages_executable ? PROT_EXEC : 0)) < 0) { \
2929 ABORT("mprotect failed"); \
2930 }
2931 # define UNPROTECT(addr, len) \
2932 if (mprotect((caddr_t)(addr), (size_t)(len), \
2933 (PROT_READ | PROT_WRITE) \
2934 | (GC_pages_executable ? PROT_EXEC : 0)) < 0) { \
2935 ABORT(GC_pages_executable ? "un-mprotect executable page" \
2936 " failed (probably disabled by OS)" : \
2937 "un-mprotect failed"); \
2938 }
2939 # undef IGNORE_PAGES_EXECUTABLE
2940
2941 # else /* MSWIN32 */
2942 # ifndef MSWINCE
2943 # include <signal.h>
2944 # endif
2945
2946 static DWORD protect_junk;
2947 # define PROTECT(addr, len) \
2948 if (!VirtualProtect((addr), (len), \
2949 GC_pages_executable ? PAGE_EXECUTE_READ : \
2950 PAGE_READONLY, \
2951 &protect_junk)) { \
2952 if (GC_print_stats) \
2953 GC_log_printf("Last error code: 0x%lx\n", (long)GetLastError()); \
2954 ABORT("VirtualProtect failed"); \
2955 }
2956 # define UNPROTECT(addr, len) \
2957 if (!VirtualProtect((addr), (len), \
2958 GC_pages_executable ? PAGE_EXECUTE_READWRITE : \
2959 PAGE_READWRITE, \
2960 &protect_junk)) { \
2961 ABORT("un-VirtualProtect failed"); \
2962 }
2963 # endif /* MSWIN32 || MSWINCE || DARWIN */
2964
2965 # if defined(MSWIN32)
2966 typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_HNDLR_PTR;
2967 # undef SIG_DFL
2968 # define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER)((signed_word)-1)
2969 # elif defined(MSWINCE)
2970 typedef LONG (WINAPI *SIG_HNDLR_PTR)(struct _EXCEPTION_POINTERS *);
2971 # undef SIG_DFL
2972 # define SIG_DFL (SIG_HNDLR_PTR) (-1)
2973 # elif defined(DARWIN)
2974 typedef void (* SIG_HNDLR_PTR)();
2975 # else
2976 typedef void (* SIG_HNDLR_PTR)(int, siginfo_t *, void *);
2977 typedef void (* PLAIN_HNDLR_PTR)(int);
2978 # endif
2979
2980 # if defined(__GLIBC__)
2981 # if __GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 2
2982 # error glibc too old?
2983 # endif
2984 # endif
2985
2986 #ifndef DARWIN
2987 STATIC SIG_HNDLR_PTR GC_old_segv_handler = 0;
2988 /* Also old MSWIN32 ACCESS_VIOLATION filter */
2989 # if !defined(MSWIN32) && !defined(MSWINCE)
2990 STATIC SIG_HNDLR_PTR GC_old_bus_handler = 0;
2991 STATIC GC_bool GC_old_bus_handler_used_si = FALSE;
2992 STATIC GC_bool GC_old_segv_handler_used_si = FALSE;
2993 # endif
2994 #endif /* !DARWIN */
2995
2996 #if defined(THREADS)
2997 /* We need to lock around the bitmap update in the write fault handler */
2998 /* in order to avoid the risk of losing a bit. We do this with a */
2999 /* test-and-set spin lock if we know how to do that. Otherwise we */
3000 /* check whether we are already in the handler and use the dumb but */
3001 /* safe fallback algorithm of setting all bits in the word. */
3002 /* Contention should be very rare, so we do the minimum to handle it */
3003 /* correctly. */
3004 #ifdef AO_HAVE_test_and_set_acquire
3005 GC_INNER volatile AO_TS_t GC_fault_handler_lock = AO_TS_INITIALIZER;
async_set_pht_entry_from_index(volatile page_hash_table db,size_t index)3006 static void async_set_pht_entry_from_index(volatile page_hash_table db,
3007 size_t index)
3008 {
3009 while (AO_test_and_set_acquire(&GC_fault_handler_lock) == AO_TS_SET) {
3010 /* empty */
3011 }
3012 /* Could also revert to set_pht_entry_from_index_safe if initial */
3013 /* GC_test_and_set fails. */
3014 set_pht_entry_from_index(db, index);
3015 AO_CLEAR(&GC_fault_handler_lock);
3016 }
3017 #else /* !AO_HAVE_test_and_set_acquire */
3018 # error No test_and_set operation: Introduces a race.
3019 /* THIS WOULD BE INCORRECT! */
3020 /* The dirty bit vector may be temporarily wrong, */
3021 /* just before we notice the conflict and correct it. We may end up */
3022 /* looking at it while it's wrong. But this requires contention */
3023 /* exactly when a GC is triggered, which seems far less likely to */
3024 /* fail than the old code, which had no reported failures. Thus we */
3025 /* leave it this way while we think of something better, or support */
3026 /* GC_test_and_set on the remaining platforms. */
3027 static volatile word currently_updating = 0;
async_set_pht_entry_from_index(volatile page_hash_table db,size_t index)3028 static void async_set_pht_entry_from_index(volatile page_hash_table db,
3029 size_t index)
3030 {
3031 unsigned int update_dummy;
3032 currently_updating = (word)(&update_dummy);
3033 set_pht_entry_from_index(db, index);
3034 /* If we get contention in the 10 or so instruction window here, */
3035 /* and we get stopped by a GC between the two updates, we lose! */
3036 if (currently_updating != (word)(&update_dummy)) {
3037 set_pht_entry_from_index_safe(db, index);
3038 /* We claim that if two threads concurrently try to update the */
3039 /* dirty bit vector, the first one to execute UPDATE_START */
3040 /* will see it changed when UPDATE_END is executed. (Note that */
3041 /* &update_dummy must differ in two distinct threads.) It */
3042 /* will then execute set_pht_entry_from_index_safe, thus */
3043 /* returning us to a safe state, though not soon enough. */
3044 }
3045 }
3046 #endif /* !AO_HAVE_test_and_set_acquire */
3047 #else /* !THREADS */
3048 # define async_set_pht_entry_from_index(db, index) \
3049 set_pht_entry_from_index(db, index)
3050 #endif /* !THREADS */
3051
3052 #ifdef CHECKSUMS
3053 void GC_record_fault(struct hblk * h); /* from checksums.c */
3054 #endif
3055
3056 #ifndef DARWIN
3057
3058 # if !defined(MSWIN32) && !defined(MSWINCE)
3059 # include <errno.h>
3060 # if defined(FREEBSD) || defined(HURD) || defined(HPUX)
3061 # define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
3062 # else
3063 # define SIG_OK (sig == SIGSEGV)
3064 # endif
3065 # if defined(FREEBSD)
3066 # ifndef SEGV_ACCERR
3067 # define SEGV_ACCERR 2
3068 # endif
3069 # define CODE_OK (si -> si_code == BUS_PAGE_FAULT \
3070 || si -> si_code == SEGV_ACCERR)
3071 # elif defined(OSF1)
3072 # define CODE_OK (si -> si_code == 2 /* experimentally determined */)
3073 # elif defined(IRIX5)
3074 # define CODE_OK (si -> si_code == EACCES)
3075 # elif defined(HURD)
3076 # define CODE_OK TRUE
3077 # elif defined(LINUX)
3078 # define CODE_OK TRUE
3079 /* Empirically c.trapno == 14, on IA32, but is that useful? */
3080 /* Should probably consider alignment issues on other */
3081 /* architectures. */
3082 # elif defined(HPUX)
3083 # define CODE_OK (si -> si_code == SEGV_ACCERR \
3084 || si -> si_code == BUS_ADRERR \
3085 || si -> si_code == BUS_UNKNOWN \
3086 || si -> si_code == SEGV_UNKNOWN \
3087 || si -> si_code == BUS_OBJERR)
3088 # elif defined(SUNOS5SIGS)
3089 # define CODE_OK (si -> si_code == SEGV_ACCERR)
3090 # endif
3091 # ifndef NO_GETCONTEXT
3092 # include <ucontext.h>
3093 # endif
3094 /*ARGSUSED*/
GC_write_fault_handler(int sig,siginfo_t * si,void * raw_sc)3095 STATIC void GC_write_fault_handler(int sig, siginfo_t *si, void *raw_sc)
3096 # else
3097 # define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode \
3098 == STATUS_ACCESS_VIOLATION)
3099 # define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] \
3100 == 1) /* Write fault */
3101 GC_INNER LONG WINAPI GC_write_fault_handler(
3102 struct _EXCEPTION_POINTERS *exc_info)
3103 # endif /* MSWIN32 || MSWINCE */
3104 {
3105 # if !defined(MSWIN32) && !defined(MSWINCE)
3106 char *addr = si -> si_addr;
3107 # else
3108 char * addr = (char *) (exc_info -> ExceptionRecord
3109 -> ExceptionInformation[1]);
3110 # endif
3111 unsigned i;
3112
3113 if (SIG_OK && CODE_OK) {
3114 register struct hblk * h =
3115 (struct hblk *)((word)addr & ~(GC_page_size-1));
3116 GC_bool in_allocd_block;
3117 # ifdef CHECKSUMS
3118 GC_record_fault(h);
3119 # endif
3120
3121 # ifdef SUNOS5SIGS
3122 /* Address is only within the correct physical page. */
3123 in_allocd_block = FALSE;
3124 for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
3125 if (HDR(h+i) != 0) {
3126 in_allocd_block = TRUE;
3127 break;
3128 }
3129 }
3130 # else
3131 in_allocd_block = (HDR(addr) != 0);
3132 # endif
3133 if (!in_allocd_block) {
3134 /* FIXME - We should make sure that we invoke the */
3135 /* old handler with the appropriate calling */
3136 /* sequence, which often depends on SA_SIGINFO. */
3137
3138 /* Heap blocks now begin and end on page boundaries */
3139 SIG_HNDLR_PTR old_handler;
3140
3141 # if defined(MSWIN32) || defined(MSWINCE)
3142 old_handler = GC_old_segv_handler;
3143 # else
3144 GC_bool used_si;
3145
3146 if (sig == SIGSEGV) {
3147 old_handler = GC_old_segv_handler;
3148 used_si = GC_old_segv_handler_used_si;
3149 } else {
3150 old_handler = GC_old_bus_handler;
3151 used_si = GC_old_bus_handler_used_si;
3152 }
3153 # endif
3154
3155 if (old_handler == (SIG_HNDLR_PTR)SIG_DFL) {
3156 # if !defined(MSWIN32) && !defined(MSWINCE)
3157 if (GC_print_stats)
3158 GC_log_printf("Unexpected segfault at %p\n", addr);
3159 ABORT("Unexpected bus error or segmentation fault");
3160 # else
3161 return(EXCEPTION_CONTINUE_SEARCH);
3162 # endif
3163 } else {
3164 /*
3165 * FIXME: This code should probably check if the
3166 * old signal handler used the traditional style and
3167 * if so call it using that style.
3168 */
3169 # if defined(MSWIN32) || defined(MSWINCE)
3170 return((*old_handler)(exc_info));
3171 # else
3172 if (used_si)
3173 ((SIG_HNDLR_PTR)old_handler) (sig, si, raw_sc);
3174 else
3175 /* FIXME: should pass nonstandard args as well. */
3176 ((PLAIN_HNDLR_PTR)old_handler) (sig);
3177 return;
3178 # endif
3179 }
3180 }
3181 UNPROTECT(h, GC_page_size);
3182 /* We need to make sure that no collection occurs between */
3183 /* the UNPROTECT and the setting of the dirty bit. Otherwise */
3184 /* a write by a third thread might go unnoticed. Reversing */
3185 /* the order is just as bad, since we would end up unprotecting */
3186 /* a page in a GC cycle during which it's not marked. */
3187 /* Currently we do this by disabling the thread stopping */
3188 /* signals while this handler is running. An alternative might */
3189 /* be to record the fact that we're about to unprotect, or */
3190 /* have just unprotected a page in the GC's thread structure, */
3191 /* and then to have the thread stopping code set the dirty */
3192 /* flag, if necessary. */
3193 for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
3194 size_t index = PHT_HASH(h+i);
3195
3196 async_set_pht_entry_from_index(GC_dirty_pages, index);
3197 }
3198 /* The write may not take place before dirty bits are read. */
3199 /* But then we'll fault again ... */
3200 # if defined(MSWIN32) || defined(MSWINCE)
3201 return(EXCEPTION_CONTINUE_EXECUTION);
3202 # else
3203 return;
3204 # endif
3205 }
3206 # if defined(MSWIN32) || defined(MSWINCE)
3207 return EXCEPTION_CONTINUE_SEARCH;
3208 # else
3209 if (GC_print_stats)
3210 GC_log_printf("Unexpected segfault at %p\n", addr);
3211 ABORT("Unexpected bus error or segmentation fault");
3212 # endif
3213 }
3214 #endif /* !DARWIN */
3215
3216 /* We hold the allocation lock. We expect block h to be written */
3217 /* shortly. Ensure that all pages containing any part of the n hblks */
3218 /* starting at h are no longer protected. If is_ptrfree is false, also */
3219 /* ensure that they will subsequently appear to be dirty. Not allowed */
3220 /* to call GC_printf (and the friends) here, see Win32 GC_stop_world() */
3221 /* for the information. */
GC_remove_protection(struct hblk * h,word nblocks,GC_bool is_ptrfree)3222 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
3223 GC_bool is_ptrfree)
3224 {
3225 struct hblk * h_trunc; /* Truncated to page boundary */
3226 struct hblk * h_end; /* Page boundary following block end */
3227 struct hblk * current;
3228
3229 # if defined(GWW_VDB)
3230 if (GC_GWW_AVAILABLE()) return;
3231 # endif
3232 if (!GC_dirty_maintained) return;
3233 h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));
3234 h_end = (struct hblk *)(((word)(h + nblocks) + GC_page_size-1)
3235 & ~(GC_page_size-1));
3236 if (h_end == h_trunc + 1 &&
3237 get_pht_entry_from_index(GC_dirty_pages, PHT_HASH(h_trunc))) {
3238 /* already marked dirty, and hence unprotected. */
3239 return;
3240 }
3241 for (current = h_trunc; current < h_end; ++current) {
3242 size_t index = PHT_HASH(current);
3243 if (!is_ptrfree || current < h || current >= h + nblocks) {
3244 async_set_pht_entry_from_index(GC_dirty_pages, index);
3245 }
3246 }
3247 UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);
3248 }
3249
3250 #if !defined(DARWIN)
GC_dirty_init(void)3251 GC_INNER void GC_dirty_init(void)
3252 {
3253 # if !defined(MSWIN32) && !defined(MSWINCE)
3254 struct sigaction act, oldact;
3255 act.sa_flags = SA_RESTART | SA_SIGINFO;
3256 act.sa_sigaction = GC_write_fault_handler;
3257 (void)sigemptyset(&act.sa_mask);
3258 # ifdef SIG_SUSPEND
3259 /* Arrange to postpone SIG_SUSPEND while we're in a write fault */
3260 /* handler. This effectively makes the handler atomic w.r.t. */
3261 /* stopping the world for GC. */
3262 (void)sigaddset(&act.sa_mask, SIG_SUSPEND);
3263 # endif /* SIG_SUSPEND */
3264 # endif
3265 if (GC_print_stats == VERBOSE)
3266 GC_log_printf(
3267 "Initializing mprotect virtual dirty bit implementation\n");
3268 GC_dirty_maintained = TRUE;
3269 if (GC_page_size % HBLKSIZE != 0) {
3270 ABORT("Page size not multiple of HBLKSIZE");
3271 }
3272 # if !defined(MSWIN32) && !defined(MSWINCE)
3273 # if defined(GC_IRIX_THREADS)
3274 sigaction(SIGSEGV, 0, &oldact);
3275 sigaction(SIGSEGV, &act, 0);
3276 # else
3277 {
3278 int res = sigaction(SIGSEGV, &act, &oldact);
3279 if (res != 0) ABORT("Sigaction failed");
3280 }
3281 # endif
3282 if (oldact.sa_flags & SA_SIGINFO) {
3283 GC_old_segv_handler = oldact.sa_sigaction;
3284 GC_old_segv_handler_used_si = TRUE;
3285 } else {
3286 GC_old_segv_handler = (SIG_HNDLR_PTR)oldact.sa_handler;
3287 GC_old_segv_handler_used_si = FALSE;
3288 }
3289 if (GC_old_segv_handler == (SIG_HNDLR_PTR)SIG_IGN) {
3290 if (GC_print_stats)
3291 GC_err_printf("Previously ignored segmentation violation!?\n");
3292 GC_old_segv_handler = (SIG_HNDLR_PTR)SIG_DFL;
3293 }
3294 if (GC_old_segv_handler != (SIG_HNDLR_PTR)SIG_DFL) {
3295 if (GC_print_stats == VERBOSE)
3296 GC_log_printf("Replaced other SIGSEGV handler\n");
3297 }
3298 # if defined(HPUX) || defined(LINUX) || defined(HURD) \
3299 || (defined(FREEBSD) && defined(SUNOS5SIGS))
3300 sigaction(SIGBUS, &act, &oldact);
3301 if (oldact.sa_flags & SA_SIGINFO) {
3302 GC_old_bus_handler = oldact.sa_sigaction;
3303 GC_old_bus_handler_used_si = TRUE;
3304 } else {
3305 GC_old_bus_handler = (SIG_HNDLR_PTR)oldact.sa_handler;
3306 GC_old_bus_handler_used_si = FALSE;
3307 }
3308 if (GC_old_bus_handler == (SIG_HNDLR_PTR)SIG_IGN) {
3309 if (GC_print_stats)
3310 GC_err_printf("Previously ignored bus error!?\n");
3311 GC_old_bus_handler = (SIG_HNDLR_PTR)SIG_DFL;
3312 }
3313 if (GC_old_bus_handler != (SIG_HNDLR_PTR)SIG_DFL) {
3314 if (GC_print_stats == VERBOSE)
3315 GC_log_printf("Replaced other SIGBUS handler\n");
3316 }
3317 # endif /* HPUX || LINUX || HURD || (FREEBSD && SUNOS5SIGS) */
3318 # endif /* ! MS windows */
3319 # if defined(GWW_VDB)
3320 if (GC_gww_dirty_init())
3321 return;
3322 # endif
3323 # if defined(MSWIN32)
3324 GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
3325 if (GC_old_segv_handler != NULL) {
3326 if (GC_print_stats)
3327 GC_log_printf("Replaced other UnhandledExceptionFilter\n");
3328 } else {
3329 GC_old_segv_handler = SIG_DFL;
3330 }
3331 # elif defined(MSWINCE)
3332 /* MPROTECT_VDB is unsupported for WinCE at present. */
3333 /* FIXME: implement it (if possible). */
3334 # endif
3335 }
3336 #endif /* !DARWIN */
3337
GC_incremental_protection_needs(void)3338 GC_API int GC_CALL GC_incremental_protection_needs(void)
3339 {
3340 if (GC_page_size == HBLKSIZE) {
3341 return GC_PROTECTS_POINTER_HEAP;
3342 } else {
3343 return GC_PROTECTS_POINTER_HEAP | GC_PROTECTS_PTRFREE_HEAP;
3344 }
3345 }
3346 #define HAVE_INCREMENTAL_PROTECTION_NEEDS
3347
3348 #define IS_PTRFREE(hhdr) ((hhdr)->hb_descr == 0)
3349 #define PAGE_ALIGNED(x) !((word)(x) & (GC_page_size - 1))
3350
GC_protect_heap(void)3351 STATIC void GC_protect_heap(void)
3352 {
3353 ptr_t start;
3354 size_t len;
3355 struct hblk * current;
3356 struct hblk * current_start; /* Start of block to be protected. */
3357 struct hblk * limit;
3358 unsigned i;
3359 GC_bool protect_all =
3360 (0 != (GC_incremental_protection_needs() & GC_PROTECTS_PTRFREE_HEAP));
3361 for (i = 0; i < GC_n_heap_sects; i++) {
3362 start = GC_heap_sects[i].hs_start;
3363 len = GC_heap_sects[i].hs_bytes;
3364 if (protect_all) {
3365 PROTECT(start, len);
3366 } else {
3367 GC_ASSERT(PAGE_ALIGNED(len))
3368 GC_ASSERT(PAGE_ALIGNED(start))
3369 current_start = current = (struct hblk *)start;
3370 limit = (struct hblk *)(start + len);
3371 while (current < limit) {
3372 hdr * hhdr;
3373 word nhblks;
3374 GC_bool is_ptrfree;
3375
3376 GC_ASSERT(PAGE_ALIGNED(current));
3377 GET_HDR(current, hhdr);
3378 if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
3379 /* This can happen only if we're at the beginning of a */
3380 /* heap segment, and a block spans heap segments. */
3381 /* We will handle that block as part of the preceding */
3382 /* segment. */
3383 GC_ASSERT(current_start == current);
3384 current_start = ++current;
3385 continue;
3386 }
3387 if (HBLK_IS_FREE(hhdr)) {
3388 GC_ASSERT(PAGE_ALIGNED(hhdr -> hb_sz));
3389 nhblks = divHBLKSZ(hhdr -> hb_sz);
3390 is_ptrfree = TRUE; /* dirty on alloc */
3391 } else {
3392 nhblks = OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
3393 is_ptrfree = IS_PTRFREE(hhdr);
3394 }
3395 if (is_ptrfree) {
3396 if (current_start < current) {
3397 PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
3398 }
3399 current_start = (current += nhblks);
3400 } else {
3401 current += nhblks;
3402 }
3403 }
3404 if (current_start < current) {
3405 PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
3406 }
3407 }
3408 }
3409 }
3410
3411 /* We assume that either the world is stopped or its OK to lose dirty */
3412 /* bits while this is happenning (as in GC_enable_incremental). */
GC_read_dirty(void)3413 GC_INNER void GC_read_dirty(void)
3414 {
3415 # if defined(GWW_VDB)
3416 if (GC_GWW_AVAILABLE()) {
3417 GC_gww_read_dirty();
3418 return;
3419 }
3420 # endif
3421 BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
3422 (sizeof GC_dirty_pages));
3423 BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
3424 GC_protect_heap();
3425 }
3426
GC_page_was_dirty(struct hblk * h)3427 GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
3428 {
3429 register word index;
3430
3431 # if defined(GWW_VDB)
3432 if (GC_GWW_AVAILABLE())
3433 return GC_gww_page_was_dirty(h);
3434 # endif
3435
3436 index = PHT_HASH(h);
3437 return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
3438 }
3439
3440 /*
3441 * Acquiring the allocation lock here is dangerous, since this
3442 * can be called from within GC_call_with_alloc_lock, and the cord
3443 * package does so. On systems that allow nested lock acquisition, this
3444 * happens to work.
3445 * On other systems, SET_LOCK_HOLDER and friends must be suitably defined.
3446 */
3447
3448 #if 0
3449 static GC_bool syscall_acquired_lock = FALSE; /* Protected by GC lock. */
3450
3451 void GC_begin_syscall(void)
3452 {
3453 /* FIXME: Resurrecting this code would require fixing the */
3454 /* test, which can spuriously return TRUE. */
3455 if (!I_HOLD_LOCK()) {
3456 LOCK();
3457 syscall_acquired_lock = TRUE;
3458 }
3459 }
3460
3461 void GC_end_syscall(void)
3462 {
3463 if (syscall_acquired_lock) {
3464 syscall_acquired_lock = FALSE;
3465 UNLOCK();
3466 }
3467 }
3468
3469 void GC_unprotect_range(ptr_t addr, word len)
3470 {
3471 struct hblk * start_block;
3472 struct hblk * end_block;
3473 register struct hblk *h;
3474 ptr_t obj_start;
3475
3476 if (!GC_dirty_maintained) return;
3477 obj_start = GC_base(addr);
3478 if (obj_start == 0) return;
3479 if (GC_base(addr + len - 1) != obj_start) {
3480 ABORT("GC_unprotect_range(range bigger than object)");
3481 }
3482 start_block = (struct hblk *)((word)addr & ~(GC_page_size - 1));
3483 end_block = (struct hblk *)((word)(addr + len - 1) & ~(GC_page_size - 1));
3484 end_block += GC_page_size/HBLKSIZE - 1;
3485 for (h = start_block; h <= end_block; h++) {
3486 register word index = PHT_HASH(h);
3487
3488 async_set_pht_entry_from_index(GC_dirty_pages, index);
3489 }
3490 UNPROTECT(start_block,
3491 ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
3492 }
3493
3494
3495 /* We no longer wrap read by default, since that was causing too many */
3496 /* problems. It is preferred that the client instead avoids writing */
3497 /* to the write-protected heap with a system call. */
3498 /* This still serves as sample code if you do want to wrap system calls.*/
3499
3500 #if !defined(MSWIN32) && !defined(MSWINCE) && !defined(GC_USE_LD_WRAP)
3501 /* Replacement for UNIX system call. */
3502 /* Other calls that write to the heap should be handled similarly. */
3503 /* Note that this doesn't work well for blocking reads: It will hold */
3504 /* the allocation lock for the entire duration of the call. Multithreaded */
3505 /* clients should really ensure that it won't block, either by setting */
3506 /* the descriptor nonblocking, or by calling select or poll first, to */
3507 /* make sure that input is available. */
3508 /* Another, preferred alternative is to ensure that system calls never */
3509 /* write to the protected heap (see above). */
3510 # include <unistd.h>
3511 # include <sys/uio.h>
3512 ssize_t read(int fd, void *buf, size_t nbyte)
3513 {
3514 int result;
3515
3516 GC_begin_syscall();
3517 GC_unprotect_range(buf, (word)nbyte);
3518 # if defined(IRIX5) || defined(GC_LINUX_THREADS)
3519 /* Indirect system call may not always be easily available. */
3520 /* We could call _read, but that would interfere with the */
3521 /* libpthread interception of read. */
3522 /* On Linux, we have to be careful with the linuxthreads */
3523 /* read interception. */
3524 {
3525 struct iovec iov;
3526
3527 iov.iov_base = buf;
3528 iov.iov_len = nbyte;
3529 result = readv(fd, &iov, 1);
3530 }
3531 # else
3532 # if defined(HURD)
3533 result = __read(fd, buf, nbyte);
3534 # else
3535 /* The two zero args at the end of this list are because one
3536 IA-64 syscall() implementation actually requires six args
3537 to be passed, even though they aren't always used. */
3538 result = syscall(SYS_read, fd, buf, nbyte, 0, 0);
3539 # endif /* !HURD */
3540 # endif
3541 GC_end_syscall();
3542 return(result);
3543 }
3544 #endif /* !MSWIN32 && !MSWINCE && !GC_LINUX_THREADS */
3545
3546 #if defined(GC_USE_LD_WRAP) && !defined(THREADS)
3547 /* We use the GNU ld call wrapping facility. */
3548 /* I'm not sure that this actually wraps whatever version of read */
3549 /* is called by stdio. That code also mentions __read. */
3550 # include <unistd.h>
3551 ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
3552 {
3553 int result;
3554
3555 GC_begin_syscall();
3556 GC_unprotect_range(buf, (word)nbyte);
3557 result = __real_read(fd, buf, nbyte);
3558 GC_end_syscall();
3559 return(result);
3560 }
3561
3562 /* We should probably also do this for __read, or whatever stdio */
3563 /* actually calls. */
3564 #endif
3565 #endif /* 0 */
3566
3567 # ifdef CHECKSUMS
3568 /*ARGSUSED*/
GC_page_was_ever_dirty(struct hblk * h)3569 GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h)
3570 {
3571 # if defined(GWW_VDB)
3572 if (GC_GWW_AVAILABLE())
3573 return GC_gww_page_was_ever_dirty(h);
3574 # endif
3575 return(TRUE);
3576 }
3577 # endif /* CHECKSUMS */
3578
3579 #endif /* MPROTECT_VDB */
3580
3581 #ifdef PROC_VDB
3582 /* See DEFAULT_VDB for interface descriptions. */
3583
3584 /* This implementation assumes a Solaris 2.X like /proc */
3585 /* pseudo-file-system from which we can read page modified bits. This */
3586 /* facility is far from optimal (e.g. we would like to get the info for */
3587 /* only some of the address space), but it avoids intercepting system */
3588 /* calls. */
3589
3590 # include <errno.h>
3591 # include <sys/types.h>
3592 # include <sys/signal.h>
3593 # include <sys/fault.h>
3594 # include <sys/syscall.h>
3595 # include <sys/procfs.h>
3596 # include <sys/stat.h>
3597
3598 # define INITIAL_BUF_SZ 16384
3599 STATIC word GC_proc_buf_size = INITIAL_BUF_SZ;
3600 STATIC char *GC_proc_buf = NULL;
3601 STATIC int GC_proc_fd = 0;
3602
GC_dirty_init(void)3603 GC_INNER void GC_dirty_init(void)
3604 {
3605 int fd;
3606 char buf[30];
3607
3608 if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) {
3609 memset(GC_written_pages, 0xff, sizeof(page_hash_table));
3610 if (GC_print_stats == VERBOSE)
3611 GC_log_printf("Allocated bytes:%lu:all pages may have been written\n",
3612 (unsigned long)(GC_bytes_allocd
3613 + GC_bytes_allocd_before_gc));
3614 }
3615
3616 sprintf(buf, "/proc/%ld", (long)getpid());
3617 fd = open(buf, O_RDONLY);
3618 if (fd < 0) {
3619 ABORT("/proc open failed");
3620 }
3621 GC_proc_fd = syscall(SYS_ioctl, fd, PIOCOPENPD, 0);
3622 close(fd);
3623 syscall(SYS_fcntl, GC_proc_fd, F_SETFD, FD_CLOEXEC);
3624 if (GC_proc_fd < 0) {
3625 WARN("/proc ioctl(PIOCOPENPD) failed", 0);
3626 return;
3627 }
3628
3629 GC_dirty_maintained = TRUE;
3630 GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
3631 }
3632
3633 # define READ read
3634
GC_read_dirty(void)3635 GC_INNER void GC_read_dirty(void)
3636 {
3637 int nmaps;
3638 unsigned long npages;
3639 unsigned pagesize;
3640 ptr_t vaddr, limit;
3641 struct prasmap * map;
3642 char * bufp;
3643 int i;
3644
3645 BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
3646 bufp = GC_proc_buf;
3647 if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
3648 /* Retry with larger buffer. */
3649 word new_size = 2 * GC_proc_buf_size;
3650 char *new_buf;
3651 if (GC_print_stats)
3652 GC_err_printf("/proc read failed: GC_proc_buf_size = %lu\n",
3653 (unsigned long)GC_proc_buf_size);
3654
3655 new_buf = GC_scratch_alloc(new_size);
3656 if (new_buf != 0) {
3657 GC_proc_buf = bufp = new_buf;
3658 GC_proc_buf_size = new_size;
3659 }
3660 if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
3661 WARN("Insufficient space for /proc read\n", 0);
3662 /* Punt: */
3663 memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
3664 memset(GC_written_pages, 0xff, sizeof(page_hash_table));
3665 return;
3666 }
3667 }
3668
3669 /* Copy dirty bits into GC_grungy_pages */
3670 nmaps = ((struct prpageheader *)bufp) -> pr_nmap;
3671 # ifdef DEBUG_DIRTY_BITS
3672 GC_log_printf("Proc VDB read: pr_nmap= %u, pr_npage= %lu\n",
3673 nmaps, ((struct prpageheader *)bufp)->pr_npage);
3674
3675 # endif
3676 bufp += sizeof(struct prpageheader);
3677 for (i = 0; i < nmaps; i++) {
3678 map = (struct prasmap *)bufp;
3679 vaddr = (ptr_t)(map -> pr_vaddr);
3680 npages = map -> pr_npage;
3681 pagesize = map -> pr_pagesize;
3682 # ifdef DEBUG_DIRTY_BITS
3683 GC_log_printf(
3684 "pr_vaddr= %p, npage= %lu, mflags= 0x%x, pagesize= 0x%x\n",
3685 vaddr, npages, map->pr_mflags, pagesize);
3686 # endif
3687
3688 bufp += sizeof(struct prasmap);
3689 limit = vaddr + pagesize * npages;
3690 for (; vaddr < limit; vaddr += pagesize) {
3691 if ((*bufp++) & PG_MODIFIED) {
3692 register struct hblk * h;
3693 ptr_t next_vaddr = vaddr + pagesize;
3694 # ifdef DEBUG_DIRTY_BITS
3695 GC_log_printf("dirty page at: %p\n", vaddr);
3696 # endif
3697 for (h = (struct hblk *)vaddr; (ptr_t)h < next_vaddr; h++) {
3698 register word index = PHT_HASH(h);
3699 set_pht_entry_from_index(GC_grungy_pages, index);
3700 }
3701 }
3702 }
3703 bufp = (char *)(((word)bufp + (sizeof(long)-1)) & ~(sizeof(long)-1));
3704 }
3705 # ifdef DEBUG_DIRTY_BITS
3706 GC_log_printf("Proc VDB read done.\n");
3707 # endif
3708
3709 /* Update GC_written_pages. */
3710 GC_or_pages(GC_written_pages, GC_grungy_pages);
3711 }
3712
3713 # undef READ
3714 #endif /* PROC_VDB */
3715
3716 #ifdef PCR_VDB
3717
3718 # include "vd/PCR_VD.h"
3719
3720 # define NPAGES (32*1024) /* 128 MB */
3721
3722 PCR_VD_DB GC_grungy_bits[NPAGES];
3723
3724 STATIC ptr_t GC_vd_base = NULL;
3725 /* Address corresponding to GC_grungy_bits[0] */
3726 /* HBLKSIZE aligned. */
3727
GC_dirty_init(void)3728 GC_INNER void GC_dirty_init(void)
3729 {
3730 GC_dirty_maintained = TRUE;
3731 /* For the time being, we assume the heap generally grows up */
3732 GC_vd_base = GC_heap_sects[0].hs_start;
3733 if (GC_vd_base == 0) {
3734 ABORT("Bad initial heap segment");
3735 }
3736 if (PCR_VD_Start(HBLKSIZE, GC_vd_base, NPAGES*HBLKSIZE)
3737 != PCR_ERes_okay) {
3738 ABORT("Dirty bit initialization failed");
3739 }
3740 }
3741
GC_read_dirty(void)3742 GC_INNER void GC_read_dirty(void)
3743 {
3744 /* lazily enable dirty bits on newly added heap sects */
3745 {
3746 static int onhs = 0;
3747 int nhs = GC_n_heap_sects;
3748 for(; onhs < nhs; onhs++) {
3749 PCR_VD_WriteProtectEnable(
3750 GC_heap_sects[onhs].hs_start,
3751 GC_heap_sects[onhs].hs_bytes );
3752 }
3753 }
3754
3755 if (PCR_VD_Clear(GC_vd_base, NPAGES*HBLKSIZE, GC_grungy_bits)
3756 != PCR_ERes_okay) {
3757 ABORT("Dirty bit read failed");
3758 }
3759 }
3760
GC_page_was_dirty(struct hblk * h)3761 GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
3762 {
3763 if((ptr_t)h < GC_vd_base || (ptr_t)h >= GC_vd_base + NPAGES*HBLKSIZE) {
3764 return(TRUE);
3765 }
3766 return(GC_grungy_bits[h - (struct hblk *)GC_vd_base] & PCR_VD_DB_dirtyBit);
3767 }
3768
3769 /*ARGSUSED*/
GC_remove_protection(struct hblk * h,word nblocks,GC_bool is_ptrfree)3770 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
3771 GC_bool is_ptrfree)
3772 {
3773 PCR_VD_WriteProtectDisable(h, nblocks*HBLKSIZE);
3774 PCR_VD_WriteProtectEnable(h, nblocks*HBLKSIZE);
3775 }
3776
3777 #endif /* PCR_VDB */
3778
3779 #if defined(MPROTECT_VDB) && defined(DARWIN)
3780 /* The following sources were used as a "reference" for this exception
3781 handling code:
3782 1. Apple's mach/xnu documentation
3783 2. Timothy J. Wood's "Mach Exception Handlers 101" post to the
3784 omnigroup's macosx-dev list.
3785 www.omnigroup.com/mailman/archive/macosx-dev/2000-June/014178.html
3786 3. macosx-nat.c from Apple's GDB source code.
3787 */
3788
3789 /* The bug that caused all this trouble should now be fixed. This should
3790 eventually be removed if all goes well. */
3791
3792 /* #define BROKEN_EXCEPTION_HANDLING */
3793
3794 #include <mach/mach.h>
3795 #include <mach/mach_error.h>
3796 #include <mach/thread_status.h>
3797 #include <mach/exception.h>
3798 #include <mach/task.h>
3799 #include <pthread.h>
3800
3801 /* These are not defined in any header, although they are documented */
3802 extern boolean_t
3803 exc_server(mach_msg_header_t *, mach_msg_header_t *);
3804
3805 extern kern_return_t
3806 exception_raise(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
3807 exception_data_t, mach_msg_type_number_t);
3808
3809 extern kern_return_t
3810 exception_raise_state(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
3811 exception_data_t, mach_msg_type_number_t,
3812 thread_state_flavor_t*, thread_state_t,
3813 mach_msg_type_number_t, thread_state_t,
3814 mach_msg_type_number_t*);
3815
3816 extern kern_return_t
3817 exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
3818 exception_type_t, exception_data_t,
3819 mach_msg_type_number_t, thread_state_flavor_t*,
3820 thread_state_t, mach_msg_type_number_t,
3821 thread_state_t, mach_msg_type_number_t*);
3822
3823 GC_API_OSCALL kern_return_t
3824 catch_exception_raise(mach_port_t exception_port, mach_port_t thread,
3825 mach_port_t task, exception_type_t exception,
3826 exception_data_t code, mach_msg_type_number_t code_count);
3827
3828 /* These should never be called, but just in case... */
3829 GC_API_OSCALL kern_return_t
catch_exception_raise_state(mach_port_name_t exception_port,int exception,exception_data_t code,mach_msg_type_number_t codeCnt,int flavor,thread_state_t old_state,int old_stateCnt,thread_state_t new_state,int new_stateCnt)3830 catch_exception_raise_state(mach_port_name_t exception_port, int exception,
3831 exception_data_t code,
3832 mach_msg_type_number_t codeCnt, int flavor,
3833 thread_state_t old_state, int old_stateCnt,
3834 thread_state_t new_state, int new_stateCnt)
3835 {
3836 ABORT("Unexpected catch_exception_raise_state invocation");
3837 return(KERN_INVALID_ARGUMENT);
3838 }
3839
3840 GC_API_OSCALL kern_return_t
catch_exception_raise_state_identity(mach_port_name_t exception_port,mach_port_t thread,mach_port_t task,int exception,exception_data_t code,mach_msg_type_number_t codeCnt,int flavor,thread_state_t old_state,int old_stateCnt,thread_state_t new_state,int new_stateCnt)3841 catch_exception_raise_state_identity(mach_port_name_t exception_port,
3842 mach_port_t thread, mach_port_t task,
3843 int exception, exception_data_t code,
3844 mach_msg_type_number_t codeCnt, int flavor,
3845 thread_state_t old_state, int old_stateCnt,
3846 thread_state_t new_state, int new_stateCnt)
3847 {
3848 ABORT("Unexpected catch_exception_raise_state_identity invocation");
3849 return(KERN_INVALID_ARGUMENT);
3850 }
3851
3852 #define MAX_EXCEPTION_PORTS 16
3853
3854 static struct {
3855 mach_msg_type_number_t count;
3856 exception_mask_t masks[MAX_EXCEPTION_PORTS];
3857 exception_handler_t ports[MAX_EXCEPTION_PORTS];
3858 exception_behavior_t behaviors[MAX_EXCEPTION_PORTS];
3859 thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
3860 } GC_old_exc_ports;
3861
3862 STATIC struct {
3863 void (*volatile os_callback[3])(void);
3864 mach_port_t exception;
3865 # if defined(THREADS)
3866 mach_port_t reply;
3867 # endif
3868 } GC_ports = {
3869 {
3870 /* This is to prevent stripping these routines as dead. */
3871 (void (*)(void))catch_exception_raise,
3872 (void (*)(void))catch_exception_raise_state,
3873 (void (*)(void))catch_exception_raise_state_identity
3874 },
3875 0
3876 };
3877
3878 typedef struct {
3879 mach_msg_header_t head;
3880 } GC_msg_t;
3881
3882 typedef enum {
3883 GC_MP_NORMAL,
3884 GC_MP_DISCARDING,
3885 GC_MP_STOPPED
3886 } GC_mprotect_state_t;
3887
3888 #ifdef THREADS
3889 /* FIXME: 1 and 2 seem to be safe to use in the msgh_id field, */
3890 /* but it isn't documented. Use the source and see if they */
3891 /* should be ok. */
3892 # define ID_STOP 1
3893 # define ID_RESUME 2
3894
3895 /* This value is only used on the reply port. */
3896 # define ID_ACK 3
3897
3898 STATIC GC_mprotect_state_t GC_mprotect_state = 0;
3899
3900 /* The following should ONLY be called when the world is stopped. */
GC_mprotect_thread_notify(mach_msg_id_t id)3901 STATIC void GC_mprotect_thread_notify(mach_msg_id_t id)
3902 {
3903 struct {
3904 GC_msg_t msg;
3905 mach_msg_trailer_t trailer;
3906 } buf;
3907 mach_msg_return_t r;
3908
3909 /* remote, local */
3910 buf.msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
3911 buf.msg.head.msgh_size = sizeof(buf.msg);
3912 buf.msg.head.msgh_remote_port = GC_ports.exception;
3913 buf.msg.head.msgh_local_port = MACH_PORT_NULL;
3914 buf.msg.head.msgh_id = id;
3915
3916 r = mach_msg(&buf.msg.head, MACH_SEND_MSG | MACH_RCV_MSG | MACH_RCV_LARGE,
3917 sizeof(buf.msg), sizeof(buf), GC_ports.reply,
3918 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
3919 if (r != MACH_MSG_SUCCESS)
3920 ABORT("mach_msg failed in GC_mprotect_thread_notify");
3921 if (buf.msg.head.msgh_id != ID_ACK)
3922 ABORT("Invalid ack in GC_mprotect_thread_notify");
3923 }
3924
3925 /* Should only be called by the mprotect thread */
GC_mprotect_thread_reply(void)3926 STATIC void GC_mprotect_thread_reply(void)
3927 {
3928 GC_msg_t msg;
3929 mach_msg_return_t r;
3930 /* remote, local */
3931
3932 msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
3933 msg.head.msgh_size = sizeof(msg);
3934 msg.head.msgh_remote_port = GC_ports.reply;
3935 msg.head.msgh_local_port = MACH_PORT_NULL;
3936 msg.head.msgh_id = ID_ACK;
3937
3938 r = mach_msg(&msg.head, MACH_SEND_MSG, sizeof(msg), 0, MACH_PORT_NULL,
3939 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
3940 if (r != MACH_MSG_SUCCESS)
3941 ABORT("mach_msg failed in GC_mprotect_thread_reply");
3942 }
3943
GC_mprotect_stop(void)3944 GC_INNER void GC_mprotect_stop(void)
3945 {
3946 GC_mprotect_thread_notify(ID_STOP);
3947 }
3948
GC_mprotect_resume(void)3949 GC_INNER void GC_mprotect_resume(void)
3950 {
3951 GC_mprotect_thread_notify(ID_RESUME);
3952 }
3953
3954 # ifndef GC_NO_THREADS_DISCOVERY
3955 GC_INNER void GC_darwin_register_mach_handler_thread(mach_port_t thread);
3956 # endif
3957
3958 #else
3959 /* The compiler should optimize away any GC_mprotect_state computations */
3960 # define GC_mprotect_state GC_MP_NORMAL
3961 #endif /* !THREADS */
3962
GC_mprotect_thread(void * arg)3963 STATIC void *GC_mprotect_thread(void *arg)
3964 {
3965 mach_msg_return_t r;
3966 /* These two structures contain some private kernel data. We don't */
3967 /* need to access any of it so we don't bother defining a proper */
3968 /* struct. The correct definitions are in the xnu source code. */
3969 struct {
3970 mach_msg_header_t head;
3971 char data[256];
3972 } reply;
3973 struct {
3974 mach_msg_header_t head;
3975 mach_msg_body_t msgh_body;
3976 char data[1024];
3977 } msg;
3978 mach_msg_id_t id;
3979
3980 # if defined(THREADS) && !defined(GC_NO_THREADS_DISCOVERY)
3981 GC_darwin_register_mach_handler_thread(mach_thread_self());
3982 # endif
3983
3984 for(;;) {
3985 r = mach_msg(&msg.head, MACH_RCV_MSG | MACH_RCV_LARGE |
3986 (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 0),
3987 0, sizeof(msg), GC_ports.exception,
3988 GC_mprotect_state == GC_MP_DISCARDING ? 0
3989 : MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
3990 id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
3991
3992 # if defined(THREADS)
3993 if(GC_mprotect_state == GC_MP_DISCARDING) {
3994 if(r == MACH_RCV_TIMED_OUT) {
3995 GC_mprotect_state = GC_MP_STOPPED;
3996 GC_mprotect_thread_reply();
3997 continue;
3998 }
3999 if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
4000 ABORT("Out of order mprotect thread request");
4001 }
4002 # endif /* THREADS */
4003
4004 if (r != MACH_MSG_SUCCESS) {
4005 if (GC_print_stats)
4006 GC_log_printf("mach_msg failed with code %d: %s\n", (int)r,
4007 mach_error_string(r));
4008 ABORT("mach_msg failed");
4009 }
4010
4011 switch(id) {
4012 # if defined(THREADS)
4013 case ID_STOP:
4014 if(GC_mprotect_state != GC_MP_NORMAL)
4015 ABORT("Called mprotect_stop when state wasn't normal");
4016 GC_mprotect_state = GC_MP_DISCARDING;
4017 break;
4018 case ID_RESUME:
4019 if(GC_mprotect_state != GC_MP_STOPPED)
4020 ABORT("Called mprotect_resume when state wasn't stopped");
4021 GC_mprotect_state = GC_MP_NORMAL;
4022 GC_mprotect_thread_reply();
4023 break;
4024 # endif /* THREADS */
4025 default:
4026 /* Handle the message (calls catch_exception_raise) */
4027 if(!exc_server(&msg.head, &reply.head))
4028 ABORT("exc_server failed");
4029 /* Send the reply */
4030 r = mach_msg(&reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0,
4031 MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
4032 MACH_PORT_NULL);
4033 if(r != MACH_MSG_SUCCESS) {
4034 /* This will fail if the thread dies, but the thread */
4035 /* shouldn't die... */
4036 # ifdef BROKEN_EXCEPTION_HANDLING
4037 GC_err_printf("mach_msg failed with %d %s while sending "
4038 "exc reply\n", (int)r, mach_error_string(r));
4039 # else
4040 ABORT("mach_msg failed while sending exception reply");
4041 # endif
4042 }
4043 } /* switch */
4044 } /* for(;;) */
4045 /* NOT REACHED */
4046 return NULL;
4047 }
4048
4049 /* All this SIGBUS code shouldn't be necessary. All protection faults should
4050 be going through the mach exception handler. However, it seems a SIGBUS is
4051 occasionally sent for some unknown reason. Even more odd, it seems to be
4052 meaningless and safe to ignore. */
4053 #ifdef BROKEN_EXCEPTION_HANDLING
4054
4055 /* Updates to this aren't atomic, but the SIGBUSs seem pretty rare. */
4056 /* Even if this doesn't get updated property, it isn't really a proble. */
4057 STATIC int GC_sigbus_count = 0;
4058
GC_darwin_sigbus(int num,siginfo_t * sip,void * context)4059 STATIC void GC_darwin_sigbus(int num, siginfo_t *sip, void *context)
4060 {
4061 if (num != SIGBUS)
4062 ABORT("Got a non-sigbus signal in the sigbus handler");
4063
4064 /* Ugh... some seem safe to ignore, but too many in a row probably means
4065 trouble. GC_sigbus_count is reset for each mach exception that is
4066 handled */
4067 if (GC_sigbus_count >= 8) {
4068 ABORT("Got more than 8 SIGBUSs in a row!");
4069 } else {
4070 GC_sigbus_count++;
4071 WARN("Ignoring SIGBUS.\n", 0);
4072 }
4073 }
4074 #endif /* BROKEN_EXCEPTION_HANDLING */
4075
GC_dirty_init(void)4076 GC_INNER void GC_dirty_init(void)
4077 {
4078 kern_return_t r;
4079 mach_port_t me;
4080 pthread_t thread;
4081 pthread_attr_t attr;
4082 exception_mask_t mask;
4083
4084 if (GC_print_stats == VERBOSE)
4085 GC_log_printf(
4086 "Initializing mach/darwin mprotect virtual dirty bit implementation\n");
4087 # ifdef BROKEN_EXCEPTION_HANDLING
4088 WARN("Enabling workarounds for various darwin "
4089 "exception handling bugs.\n", 0);
4090 # endif
4091 GC_dirty_maintained = TRUE;
4092 if (GC_page_size % HBLKSIZE != 0) {
4093 ABORT("Page size not multiple of HBLKSIZE");
4094 }
4095
4096 GC_task_self = me = mach_task_self();
4097
4098 r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.exception);
4099 if (r != KERN_SUCCESS)
4100 ABORT("mach_port_allocate failed (exception port)");
4101
4102 r = mach_port_insert_right(me, GC_ports.exception, GC_ports.exception,
4103 MACH_MSG_TYPE_MAKE_SEND);
4104 if (r != KERN_SUCCESS)
4105 ABORT("mach_port_insert_right failed (exception port)");
4106
4107 # if defined(THREADS)
4108 r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.reply);
4109 if(r != KERN_SUCCESS)
4110 ABORT("mach_port_allocate failed (reply port)");
4111 # endif
4112
4113 /* The exceptions we want to catch */
4114 mask = EXC_MASK_BAD_ACCESS;
4115
4116 r = task_get_exception_ports(me, mask, GC_old_exc_ports.masks,
4117 &GC_old_exc_ports.count, GC_old_exc_ports.ports,
4118 GC_old_exc_ports.behaviors,
4119 GC_old_exc_ports.flavors);
4120 if (r != KERN_SUCCESS)
4121 ABORT("task_get_exception_ports failed");
4122
4123 r = task_set_exception_ports(me, mask, GC_ports.exception, EXCEPTION_DEFAULT,
4124 GC_MACH_THREAD_STATE);
4125 if (r != KERN_SUCCESS)
4126 ABORT("task_set_exception_ports failed");
4127 if (pthread_attr_init(&attr) != 0)
4128 ABORT("pthread_attr_init failed");
4129 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
4130 ABORT("pthread_attr_setdetachedstate failed");
4131
4132 # undef pthread_create
4133 /* This will call the real pthread function, not our wrapper */
4134 if (pthread_create(&thread, &attr, GC_mprotect_thread, NULL) != 0)
4135 ABORT("pthread_create failed");
4136 pthread_attr_destroy(&attr);
4137
4138 /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
4139 # ifdef BROKEN_EXCEPTION_HANDLING
4140 {
4141 struct sigaction sa, oldsa;
4142 sa.sa_handler = (SIG_HNDLR_PTR)GC_darwin_sigbus;
4143 sigemptyset(&sa.sa_mask);
4144 sa.sa_flags = SA_RESTART|SA_SIGINFO;
4145 if (sigaction(SIGBUS, &sa, &oldsa) < 0)
4146 ABORT("sigaction failed");
4147 if ((SIG_HNDLR_PTR)oldsa.sa_handler != SIG_DFL) {
4148 if (GC_print_stats == VERBOSE)
4149 GC_err_printf("Replaced other SIGBUS handler\n");
4150 }
4151 }
4152 # endif /* BROKEN_EXCEPTION_HANDLING */
4153 }
4154
4155 /* The source code for Apple's GDB was used as a reference for the */
4156 /* exception forwarding code. This code is similar to be GDB code only */
4157 /* because there is only one way to do it. */
GC_forward_exception(mach_port_t thread,mach_port_t task,exception_type_t exception,exception_data_t data,mach_msg_type_number_t data_count)4158 STATIC kern_return_t GC_forward_exception(mach_port_t thread, mach_port_t task,
4159 exception_type_t exception,
4160 exception_data_t data,
4161 mach_msg_type_number_t data_count)
4162 {
4163 unsigned int i;
4164 kern_return_t r;
4165 mach_port_t port;
4166 exception_behavior_t behavior;
4167 thread_state_flavor_t flavor;
4168
4169 thread_state_data_t thread_state;
4170 mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
4171
4172 for (i=0; i < GC_old_exc_ports.count; i++)
4173 if (GC_old_exc_ports.masks[i] & (1 << exception))
4174 break;
4175 if (i == GC_old_exc_ports.count)
4176 ABORT("No handler for exception!");
4177
4178 port = GC_old_exc_ports.ports[i];
4179 behavior = GC_old_exc_ports.behaviors[i];
4180 flavor = GC_old_exc_ports.flavors[i];
4181
4182 if (behavior == EXCEPTION_STATE || behavior == EXCEPTION_STATE_IDENTITY) {
4183 r = thread_get_state(thread, flavor, thread_state, &thread_state_count);
4184 if(r != KERN_SUCCESS)
4185 ABORT("thread_get_state failed in forward_exception");
4186 }
4187
4188 switch(behavior) {
4189 case EXCEPTION_STATE:
4190 r = exception_raise_state(port, thread, task, exception, data, data_count,
4191 &flavor, thread_state, thread_state_count,
4192 thread_state, &thread_state_count);
4193 break;
4194 case EXCEPTION_STATE_IDENTITY:
4195 r = exception_raise_state_identity(port, thread, task, exception, data,
4196 data_count, &flavor, thread_state,
4197 thread_state_count, thread_state,
4198 &thread_state_count);
4199 break;
4200 /* case EXCEPTION_DEFAULT: */ /* default signal handlers */
4201 default: /* user-supplied signal handlers */
4202 r = exception_raise(port, thread, task, exception, data, data_count);
4203 }
4204
4205 if (behavior == EXCEPTION_STATE || behavior == EXCEPTION_STATE_IDENTITY) {
4206 r = thread_set_state(thread, flavor, thread_state, thread_state_count);
4207 if (r != KERN_SUCCESS)
4208 ABORT("thread_set_state failed in forward_exception");
4209 }
4210 return r;
4211 }
4212
4213 #define FWD() GC_forward_exception(thread, task, exception, code, code_count)
4214
4215 #ifdef ARM32
4216 # define DARWIN_EXC_STATE ARM_EXCEPTION_STATE
4217 # define DARWIN_EXC_STATE_COUNT ARM_EXCEPTION_STATE_COUNT
4218 # define DARWIN_EXC_STATE_T arm_exception_state_t
4219 # define DARWIN_EXC_STATE_DAR THREAD_FLD(far)
4220 #elif defined(POWERPC)
4221 # if CPP_WORDSZ == 32
4222 # define DARWIN_EXC_STATE PPC_EXCEPTION_STATE
4223 # define DARWIN_EXC_STATE_COUNT PPC_EXCEPTION_STATE_COUNT
4224 # define DARWIN_EXC_STATE_T ppc_exception_state_t
4225 # else
4226 # define DARWIN_EXC_STATE PPC_EXCEPTION_STATE64
4227 # define DARWIN_EXC_STATE_COUNT PPC_EXCEPTION_STATE64_COUNT
4228 # define DARWIN_EXC_STATE_T ppc_exception_state64_t
4229 # endif
4230 # define DARWIN_EXC_STATE_DAR THREAD_FLD(dar)
4231 #elif defined(I386) || defined(X86_64)
4232 # if CPP_WORDSZ == 32
4233 # define DARWIN_EXC_STATE x86_EXCEPTION_STATE32
4234 # define DARWIN_EXC_STATE_COUNT x86_EXCEPTION_STATE32_COUNT
4235 # define DARWIN_EXC_STATE_T x86_exception_state32_t
4236 # else
4237 # define DARWIN_EXC_STATE x86_EXCEPTION_STATE64
4238 # define DARWIN_EXC_STATE_COUNT x86_EXCEPTION_STATE64_COUNT
4239 # define DARWIN_EXC_STATE_T x86_exception_state64_t
4240 # endif
4241 # define DARWIN_EXC_STATE_DAR THREAD_FLD(faultvaddr)
4242 #else
4243 # error FIXME for non-arm/ppc/x86 darwin
4244 #endif
4245
4246 /* This violates the namespace rules but there isn't anything that can */
4247 /* be done about it. The exception handling stuff is hard coded to */
4248 /* call this. catch_exception_raise, catch_exception_raise_state and */
4249 /* and catch_exception_raise_state_identity are called from OS. */
4250 GC_API_OSCALL kern_return_t
catch_exception_raise(mach_port_t exception_port,mach_port_t thread,mach_port_t task,exception_type_t exception,exception_data_t code,mach_msg_type_number_t code_count)4251 catch_exception_raise(mach_port_t exception_port, mach_port_t thread,
4252 mach_port_t task, exception_type_t exception,
4253 exception_data_t code, mach_msg_type_number_t code_count)
4254 {
4255 kern_return_t r;
4256 char *addr;
4257 struct hblk *h;
4258 unsigned int i;
4259 thread_state_flavor_t flavor = DARWIN_EXC_STATE;
4260 mach_msg_type_number_t exc_state_count = DARWIN_EXC_STATE_COUNT;
4261 DARWIN_EXC_STATE_T exc_state;
4262
4263 if (exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
4264 # ifdef DEBUG_EXCEPTION_HANDLING
4265 /* We aren't interested, pass it on to the old handler */
4266 GC_log_printf("Exception: 0x%x Code: 0x%x 0x%x in catch...\n",
4267 exception, code_count > 0 ? code[0] : -1,
4268 code_count > 1 ? code[1] : -1);
4269 # endif
4270 return FWD();
4271 }
4272
4273 r = thread_get_state(thread, flavor, (natural_t*)&exc_state,
4274 &exc_state_count);
4275 if(r != KERN_SUCCESS) {
4276 /* The thread is supposed to be suspended while the exception */
4277 /* handler is called. This shouldn't fail. */
4278 # ifdef BROKEN_EXCEPTION_HANDLING
4279 GC_err_printf("thread_get_state failed in catch_exception_raise\n");
4280 return KERN_SUCCESS;
4281 # else
4282 ABORT("thread_get_state failed in catch_exception_raise");
4283 # endif
4284 }
4285
4286 /* This is the address that caused the fault */
4287 addr = (char*) exc_state.DARWIN_EXC_STATE_DAR;
4288 if (HDR(addr) == 0) {
4289 /* Ugh... just like the SIGBUS problem above, it seems we get */
4290 /* a bogus KERN_PROTECTION_FAILURE every once and a while. We wait */
4291 /* till we get a bunch in a row before doing anything about it. */
4292 /* If a "real" fault ever occurs it'll just keep faulting over and */
4293 /* over and we'll hit the limit pretty quickly. */
4294 # ifdef BROKEN_EXCEPTION_HANDLING
4295 static char *last_fault;
4296 static int last_fault_count;
4297
4298 if(addr != last_fault) {
4299 last_fault = addr;
4300 last_fault_count = 0;
4301 }
4302 if(++last_fault_count < 32) {
4303 if(last_fault_count == 1)
4304 WARN("Ignoring KERN_PROTECTION_FAILURE at %p\n", addr);
4305 return KERN_SUCCESS;
4306 }
4307
4308 GC_err_printf(
4309 "Unexpected KERN_PROTECTION_FAILURE at %p; aborting...\n", addr);
4310 /* Can't pass it along to the signal handler because that is */
4311 /* ignoring SIGBUS signals. We also shouldn't call ABORT here as */
4312 /* signals don't always work too well from the exception handler. */
4313 exit(EXIT_FAILURE);
4314 # else /* BROKEN_EXCEPTION_HANDLING */
4315 /* Pass it along to the next exception handler
4316 (which should call SIGBUS/SIGSEGV) */
4317 return FWD();
4318 # endif /* !BROKEN_EXCEPTION_HANDLING */
4319 }
4320
4321 # ifdef BROKEN_EXCEPTION_HANDLING
4322 /* Reset the number of consecutive SIGBUSs */
4323 GC_sigbus_count = 0;
4324 # endif
4325
4326 if (GC_mprotect_state == GC_MP_NORMAL) { /* common case */
4327 h = (struct hblk*)((word)addr & ~(GC_page_size-1));
4328 UNPROTECT(h, GC_page_size);
4329 for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
4330 register int index = PHT_HASH(h+i);
4331 async_set_pht_entry_from_index(GC_dirty_pages, index);
4332 }
4333 } else if (GC_mprotect_state == GC_MP_DISCARDING) {
4334 /* Lie to the thread for now. No sense UNPROTECT()ing the memory
4335 when we're just going to PROTECT() it again later. The thread
4336 will just fault again once it resumes */
4337 } else {
4338 /* Shouldn't happen, i don't think */
4339 GC_err_printf("KERN_PROTECTION_FAILURE while world is stopped\n");
4340 return FWD();
4341 }
4342 return KERN_SUCCESS;
4343 }
4344 #undef FWD
4345
4346 #ifndef NO_DESC_CATCH_EXCEPTION_RAISE
4347 /* These symbols should have REFERENCED_DYNAMICALLY (0x10) bit set to */
4348 /* let strip know they are not to be stripped. */
4349 __asm__(".desc _catch_exception_raise, 0x10");
4350 __asm__(".desc _catch_exception_raise_state, 0x10");
4351 __asm__(".desc _catch_exception_raise_state_identity, 0x10");
4352 #endif
4353
4354 #endif /* DARWIN && MPROTECT_VDB */
4355
4356 #ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
GC_incremental_protection_needs(void)4357 GC_API int GC_CALL GC_incremental_protection_needs(void)
4358 {
4359 return GC_PROTECTS_NONE;
4360 }
4361 #endif /* !HAVE_INCREMENTAL_PROTECTION_NEEDS */
4362
4363 #ifdef ECOS
4364 /* Undo sbrk() redirection. */
4365 # undef sbrk
4366 #endif
4367
4368 /* If value is non-zero then allocate executable memory. */
GC_set_pages_executable(int value)4369 GC_API void GC_CALL GC_set_pages_executable(int value)
4370 {
4371 GC_ASSERT(!GC_is_initialized);
4372 /* Even if IGNORE_PAGES_EXECUTABLE is defined, GC_pages_executable is */
4373 /* touched here to prevent a compiler warning. */
4374 GC_pages_executable = (GC_bool)(value != 0);
4375 }
4376
4377 /* Returns non-zero if the GC-allocated memory is executable. */
4378 /* GC_get_pages_executable is defined after all the places */
4379 /* where GC_get_pages_executable is undefined. */
GC_get_pages_executable(void)4380 GC_API int GC_CALL GC_get_pages_executable(void)
4381 {
4382 # ifdef IGNORE_PAGES_EXECUTABLE
4383 return 1; /* Always allocate executable memory. */
4384 # else
4385 return (int)GC_pages_executable;
4386 # endif
4387 }
4388
4389 /* Call stack save code for debugging. Should probably be in */
4390 /* mach_dep.c, but that requires reorganization. */
4391
4392 /* I suspect the following works for most X86 *nix variants, so */
4393 /* long as the frame pointer is explicitly stored. In the case of gcc, */
4394 /* compiler flags (e.g. -fomit-frame-pointer) determine whether it is. */
4395 #if defined(I386) && defined(LINUX) && defined(SAVE_CALL_CHAIN)
4396 # include <features.h>
4397
4398 struct frame {
4399 struct frame *fr_savfp;
4400 long fr_savpc;
4401 long fr_arg[NARGS]; /* All the arguments go here. */
4402 };
4403 #endif
4404
4405 #if defined(SPARC)
4406 # if defined(LINUX)
4407 # include <features.h>
4408
4409 struct frame {
4410 long fr_local[8];
4411 long fr_arg[6];
4412 struct frame *fr_savfp;
4413 long fr_savpc;
4414 # ifndef __arch64__
4415 char *fr_stret;
4416 # endif
4417 long fr_argd[6];
4418 long fr_argx[0];
4419 };
4420 # elif defined (DRSNX)
4421 # include <sys/sparc/frame.h>
4422 # elif defined(OPENBSD)
4423 # include <frame.h>
4424 # elif defined(FREEBSD) || defined(NETBSD)
4425 # include <machine/frame.h>
4426 # else
4427 # include <sys/frame.h>
4428 # endif
4429 # if NARGS > 6
4430 # error We only know how to get the first 6 arguments
4431 # endif
4432 #endif /* SPARC */
4433
4434 #ifdef NEED_CALLINFO
4435 /* Fill in the pc and argument information for up to NFRAMES of my */
4436 /* callers. Ignore my frame and my callers frame. */
4437
4438 #ifdef LINUX
4439 # include <unistd.h>
4440 #endif
4441
4442 #endif /* NEED_CALLINFO */
4443
4444 #if defined(GC_HAVE_BUILTIN_BACKTRACE)
4445 # ifdef _MSC_VER
4446 # include "private/msvc_dbg.h"
4447 # else
4448 # include <execinfo.h>
4449 # endif
4450 #endif
4451
4452 #ifdef SAVE_CALL_CHAIN
4453
4454 #if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
4455 && defined(GC_HAVE_BUILTIN_BACKTRACE)
4456
4457 #ifdef REDIRECT_MALLOC
4458 /* Deal with possible malloc calls in backtrace by omitting */
4459 /* the infinitely recursing backtrace. */
4460 # ifdef THREADS
4461 __thread /* If your compiler doesn't understand this */
4462 /* you could use something like pthread_getspecific. */
4463 # endif
4464 GC_in_save_callers = FALSE;
4465 #endif
4466
GC_save_callers(struct callinfo info[NFRAMES])4467 GC_INNER void GC_save_callers(struct callinfo info[NFRAMES])
4468 {
4469 void * tmp_info[NFRAMES + 1];
4470 int npcs, i;
4471 # define IGNORE_FRAMES 1
4472
4473 /* We retrieve NFRAMES+1 pc values, but discard the first, since it */
4474 /* points to our own frame. */
4475 # ifdef REDIRECT_MALLOC
4476 if (GC_in_save_callers) {
4477 info[0].ci_pc = (word)(&GC_save_callers);
4478 for (i = 1; i < NFRAMES; ++i) info[i].ci_pc = 0;
4479 return;
4480 }
4481 GC_in_save_callers = TRUE;
4482 # endif
4483 GC_STATIC_ASSERT(sizeof(struct callinfo) == sizeof(void *));
4484 npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES);
4485 BCOPY(tmp_info+IGNORE_FRAMES, info, (npcs - IGNORE_FRAMES) * sizeof(void *));
4486 for (i = npcs - IGNORE_FRAMES; i < NFRAMES; ++i) info[i].ci_pc = 0;
4487 # ifdef REDIRECT_MALLOC
4488 GC_in_save_callers = FALSE;
4489 # endif
4490 }
4491
4492 #else /* No builtin backtrace; do it ourselves */
4493
4494 #if (defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD)) && defined(SPARC)
4495 # define FR_SAVFP fr_fp
4496 # define FR_SAVPC fr_pc
4497 #else
4498 # define FR_SAVFP fr_savfp
4499 # define FR_SAVPC fr_savpc
4500 #endif
4501
4502 #if defined(SPARC) && (defined(__arch64__) || defined(__sparcv9))
4503 # define BIAS 2047
4504 #else
4505 # define BIAS 0
4506 #endif
4507
GC_save_callers(struct callinfo info[NFRAMES])4508 GC_INNER void GC_save_callers(struct callinfo info[NFRAMES])
4509 {
4510 struct frame *frame;
4511 struct frame *fp;
4512 int nframes = 0;
4513 # ifdef I386
4514 /* We assume this is turned on only with gcc as the compiler. */
4515 asm("movl %%ebp,%0" : "=r"(frame));
4516 fp = frame;
4517 # else
4518 frame = (struct frame *)GC_save_regs_in_stack();
4519 fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
4520 #endif
4521
4522 for (; (!(fp HOTTER_THAN frame) && !(GC_stackbottom HOTTER_THAN (ptr_t)fp)
4523 && (nframes < NFRAMES));
4524 fp = (struct frame *)((long) fp -> FR_SAVFP + BIAS), nframes++) {
4525 register int i;
4526
4527 info[nframes].ci_pc = fp->FR_SAVPC;
4528 # if NARGS > 0
4529 for (i = 0; i < NARGS; i++) {
4530 info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
4531 }
4532 # endif /* NARGS > 0 */
4533 }
4534 if (nframes < NFRAMES) info[nframes].ci_pc = 0;
4535 }
4536
4537 #endif /* No builtin backtrace */
4538
4539 #endif /* SAVE_CALL_CHAIN */
4540
4541 #ifdef NEED_CALLINFO
4542
4543 /* Print info to stderr. We do NOT hold the allocation lock */
GC_print_callers(struct callinfo info[NFRAMES])4544 GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
4545 {
4546 int i;
4547 static int reentry_count = 0;
4548 GC_bool stop = FALSE;
4549 DCL_LOCK_STATE;
4550
4551 /* FIXME: This should probably use a different lock, so that we */
4552 /* become callable with or without the allocation lock. */
4553 LOCK();
4554 ++reentry_count;
4555 UNLOCK();
4556
4557 # if NFRAMES == 1
4558 GC_err_printf("\tCaller at allocation:\n");
4559 # else
4560 GC_err_printf("\tCall chain at allocation:\n");
4561 # endif
4562 for (i = 0; i < NFRAMES && !stop; i++) {
4563 if (info[i].ci_pc == 0) break;
4564 # if NARGS > 0
4565 {
4566 int j;
4567
4568 GC_err_printf("\t\targs: ");
4569 for (j = 0; j < NARGS; j++) {
4570 if (j != 0) GC_err_printf(", ");
4571 GC_err_printf("%d (0x%X)", ~(info[i].ci_arg[j]),
4572 ~(info[i].ci_arg[j]));
4573 }
4574 GC_err_printf("\n");
4575 }
4576 # endif
4577 if (reentry_count > 1) {
4578 /* We were called during an allocation during */
4579 /* a previous GC_print_callers call; punt. */
4580 GC_err_printf("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
4581 continue;
4582 }
4583 {
4584 # ifdef LINUX
4585 FILE *pipe;
4586 # endif
4587 # if defined(GC_HAVE_BUILTIN_BACKTRACE) \
4588 && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
4589 char **sym_name =
4590 backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
4591 char *name = sym_name[0];
4592 # else
4593 char buf[40];
4594 char *name = buf;
4595 sprintf(buf, "##PC##= 0x%lx", info[i].ci_pc);
4596 # endif
4597 # if defined(LINUX) && !defined(SMALL_CONFIG)
4598 /* Try for a line number. */
4599 {
4600 # define EXE_SZ 100
4601 static char exe_name[EXE_SZ];
4602 # define CMD_SZ 200
4603 char cmd_buf[CMD_SZ];
4604 # define RESULT_SZ 200
4605 static char result_buf[RESULT_SZ];
4606 size_t result_len;
4607 char *old_preload;
4608 # define PRELOAD_SZ 200
4609 char preload_buf[PRELOAD_SZ];
4610 static GC_bool found_exe_name = FALSE;
4611 static GC_bool will_fail = FALSE;
4612 int ret_code;
4613 /* Try to get it via a hairy and expensive scheme. */
4614 /* First we get the name of the executable: */
4615 if (will_fail) goto out;
4616 if (!found_exe_name) {
4617 ret_code = readlink("/proc/self/exe", exe_name, EXE_SZ);
4618 if (ret_code < 0 || ret_code >= EXE_SZ
4619 || exe_name[0] != '/') {
4620 will_fail = TRUE; /* Don't try again. */
4621 goto out;
4622 }
4623 exe_name[ret_code] = '\0';
4624 found_exe_name = TRUE;
4625 }
4626 /* Then we use popen to start addr2line -e <exe> <addr> */
4627 /* There are faster ways to do this, but hopefully this */
4628 /* isn't time critical. */
4629 sprintf(cmd_buf, "/usr/bin/addr2line -f -e %s 0x%lx", exe_name,
4630 (unsigned long)info[i].ci_pc);
4631 old_preload = GETENV("LD_PRELOAD");
4632 if (0 != old_preload) {
4633 if (strlen (old_preload) >= PRELOAD_SZ) {
4634 will_fail = TRUE;
4635 goto out;
4636 }
4637 strcpy (preload_buf, old_preload);
4638 unsetenv ("LD_PRELOAD");
4639 }
4640 pipe = popen(cmd_buf, "r");
4641 if (0 != old_preload
4642 && 0 != setenv ("LD_PRELOAD", preload_buf, 0)) {
4643 WARN("Failed to reset LD_PRELOAD\n", 0);
4644 }
4645 if (pipe == NULL
4646 || (result_len = fread(result_buf, 1, RESULT_SZ - 1, pipe))
4647 == 0) {
4648 if (pipe != NULL) pclose(pipe);
4649 will_fail = TRUE;
4650 goto out;
4651 }
4652 if (result_buf[result_len - 1] == '\n') --result_len;
4653 result_buf[result_len] = 0;
4654 if (result_buf[0] == '?'
4655 || (result_buf[result_len-2] == ':'
4656 && result_buf[result_len-1] == '0')) {
4657 pclose(pipe);
4658 goto out;
4659 }
4660 /* Get rid of embedded newline, if any. Test for "main" */
4661 {
4662 char * nl = strchr(result_buf, '\n');
4663 if (nl != NULL && nl < result_buf + result_len) {
4664 *nl = ':';
4665 }
4666 if (strncmp(result_buf, "main", nl - result_buf) == 0) {
4667 stop = TRUE;
4668 }
4669 }
4670 if (result_len < RESULT_SZ - 25) {
4671 /* Add in hex address */
4672 sprintf(result_buf + result_len, " [0x%lx]",
4673 (unsigned long)info[i].ci_pc);
4674 }
4675 name = result_buf;
4676 pclose(pipe);
4677 out:;
4678 }
4679 # endif /* LINUX */
4680 GC_err_printf("\t\t%s\n", name);
4681 # if defined(GC_HAVE_BUILTIN_BACKTRACE) \
4682 && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
4683 free(sym_name); /* May call GC_free; that's OK */
4684 # endif
4685 }
4686 }
4687 LOCK();
4688 --reentry_count;
4689 UNLOCK();
4690 }
4691
4692 #endif /* NEED_CALLINFO */
4693
4694 #if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
4695 /* Dump /proc/self/maps to GC_stderr, to enable looking up names for */
4696 /* addresses in FIND_LEAK output. */
GC_print_address_map(void)4697 void GC_print_address_map(void)
4698 {
4699 GC_err_printf("---------- Begin address map ----------\n");
4700 GC_err_puts(GC_get_maps());
4701 GC_err_printf("---------- End address map ----------\n");
4702 }
4703 #endif /* LINUX && ELF */
4704