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