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