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