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