~ubuntu-branches/ubuntu/quantal/libgc/quantal

« back to all changes in this revision

Viewing changes to os_dep.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger
  • Date: 2011-02-19 12:19:56 UTC
  • mfrom: (1.3.2 upstream) (0.1.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 14.
  • Revision ID: james.westby@ubuntu.com-20110219121956-67rb69xlt5nud3v2
Tags: 1:7.1-5
Upload to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 */
16
16
 
17
17
# include "private/gc_priv.h"
 
18
# ifdef THREADS
 
19
#   include "atomic_ops.h"
 
20
# endif
18
21
 
19
22
# if defined(LINUX) && !defined(POWERPC)
20
23
#   include <linux/version.h>
48
51
# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \
49
52
    && !defined(MSWINCE)
50
53
#   include <sys/types.h>
51
 
#   if !defined(MSWIN32) && !defined(SUNOS4)
 
54
#   if !defined(MSWIN32)
52
55
#       include <unistd.h>
53
56
#   endif
54
57
# endif
60
63
#   include <signal.h>
61
64
# endif
62
65
 
 
66
#ifdef UNIX_LIKE
 
67
# include <fcntl.h>
 
68
#endif
 
69
 
63
70
#if defined(LINUX) || defined(LINUX_STACKBOTTOM)
64
71
# include <ctype.h>
65
72
#endif
67
74
/* Blatantly OS dependent routines, except for those that are related   */
68
75
/* to dynamic loading.                                                  */
69
76
 
70
 
# if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START)
71
 
#   define NEED_FIND_LIMIT
72
 
# endif
73
 
 
74
 
# if !defined(STACKBOTTOM) && defined(HEURISTIC2)
75
 
#   define NEED_FIND_LIMIT
76
 
# endif
77
 
 
78
 
# if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR)
79
 
#   define NEED_FIND_LIMIT
80
 
# endif
81
 
 
82
 
# if (defined(SVR4) || defined(AUX) || defined(DGUX) \
83
 
      || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
84
 
#   define NEED_FIND_LIMIT
85
 
# endif
86
 
 
87
 
#if defined(FREEBSD) && (defined(I386) || defined(X86_64) || defined(powerpc) || defined(__powerpc__))
88
 
#  include <machine/trap.h>
89
 
#  if !defined(PCR)
90
 
#    define NEED_FIND_LIMIT
91
 
#  endif
92
 
#endif
93
 
 
94
 
#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) \
95
 
    && !defined(NEED_FIND_LIMIT)
96
 
   /* Used by GC_init_netbsd_elf() below.       */
97
 
#  define NEED_FIND_LIMIT
98
 
#endif
99
 
 
100
 
#ifdef NEED_FIND_LIMIT
101
 
#   include <setjmp.h>
102
 
#endif
103
 
 
104
77
#ifdef AMIGA
105
78
# define GC_AMIGA_DEF
106
79
# include "AmigaOS.c"
107
80
# undef GC_AMIGA_DEF
108
81
#endif
109
82
 
110
 
#if defined(MSWIN32) || defined(MSWINCE)
 
83
#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
111
84
# define WIN32_LEAN_AND_MEAN
112
85
# define NOSERVICE
113
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.                      */
114
89
#endif
115
90
 
116
91
#ifdef MACOS
121
96
# include <sys/uio.h>
122
97
# include <malloc.h>   /* for locking */
123
98
#endif
124
 
#if defined(USE_MMAP) || defined(USE_MUNMAP)
125
 
# ifndef USE_MMAP
 
99
 
 
100
#if defined(LINUX) || defined(FREEBSD) || defined(SOLARIS) || defined(IRIX5) \
 
101
        || defined(USE_MMAP) || defined(USE_MUNMAP)
 
102
# define MMAP_SUPPORTED
 
103
#endif
 
104
 
 
105
#if defined(MMAP_SUPPORTED) || defined(ADD_HEAP_GUARD_PAGES)
 
106
# if defined(USE_MUNMAP) && !defined(USE_MMAP)
126
107
    --> USE_MUNMAP requires USE_MMAP
127
108
# endif
128
109
# include <sys/types.h>
131
112
# include <errno.h>
132
113
#endif
133
114
 
134
 
#ifdef UNIX_LIKE
135
 
# include <fcntl.h>
136
 
# if defined(SUNOS5SIGS) && !defined(FREEBSD)
137
 
#  include <sys/siginfo.h>
138
 
# endif
139
 
  /* Define SETJMP and friends to be the version that restores  */
140
 
  /* the signal mask.                                           */
141
 
# define SETJMP(env) sigsetjmp(env, 1)
142
 
# define LONGJMP(env, val) siglongjmp(env, val)
143
 
# define JMP_BUF sigjmp_buf
144
 
#else
145
 
# define SETJMP(env) setjmp(env)
146
 
# define LONGJMP(env, val) longjmp(env, val)
147
 
# define JMP_BUF jmp_buf
148
 
#endif
149
 
 
150
115
#ifdef DARWIN
151
116
/* for get_etext and friends */
152
117
#include <mach-o/getsect.h>
172
137
 
173
138
#if defined(LINUX) && \
174
139
    (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) || !defined(SMALL_CONFIG))
 
140
# define NEED_PROC_MAPS
 
141
#endif
175
142
 
 
143
#ifdef NEED_PROC_MAPS
176
144
/* We need to parse /proc/self/maps, either to find dynamic libraries,  */
177
145
/* and/or to find the register backing store base (IA64).  Do it once   */
178
146
/* here.                                                                */
195
163
    return num_read;
196
164
}
197
165
 
 
166
/* Determine the length of a file by incrementally reading it into a    */
 
167
/* This would be sily to use on a file supporting lseek, but Linux      */
 
168
/* /proc files usually do not.                                          */
 
169
size_t GC_get_file_len(int f)
 
170
{
 
171
    size_t total = 0;
 
172
    ssize_t result;
 
173
#   define GET_FILE_LEN_BUF_SZ 500
 
174
    char buf[GET_FILE_LEN_BUF_SZ];
 
175
 
 
176
    do {
 
177
        result = read(f, buf, GET_FILE_LEN_BUF_SZ);
 
178
        if (result == -1) return 0;
 
179
        total += result;
 
180
    } while (result > 0);
 
181
    return total;
 
182
}
 
183
 
 
184
size_t GC_get_maps_len(void)
 
185
{
 
186
    int f = open("/proc/self/maps", O_RDONLY);
 
187
    size_t result = GC_get_file_len(f);
 
188
    close(f);
 
189
    return result;
 
190
}
 
191
 
198
192
/*
199
 
 * Apply fn to a buffer containing the contents of /proc/self/maps.
200
 
 * Return the result of fn or, if we failed, 0.
201
 
 * We currently do nothing to /proc/self/maps other than simply read
202
 
 * it.  This code could be simplified if we could determine its size
 
193
 * Copy the contents of /proc/self/maps to a buffer in our address space.
 
194
 * Return the address of the buffer, or zero on failure.
 
195
 * This code could be simplified if we could determine its size
203
196
 * ahead of time.
204
197
 */
205
 
 
206
 
word GC_apply_to_maps(word (*fn)(char *))
 
198
char * GC_get_maps(void)
207
199
{
208
200
    int f;
209
201
    int result;
210
 
    size_t maps_size = 4000;  /* Initial guess.         */
211
202
    static char init_buf[1];
212
203
    static char *maps_buf = init_buf;
213
204
    static size_t maps_buf_sz = 1;
 
205
    size_t maps_size, old_maps_size = 0;
 
206
 
 
207
    /* The buffer is essentially static, so there must be a single client. */
 
208
    GC_ASSERT(I_HOLD_LOCK());
 
209
 
 
210
    /* Note that in the presence of threads, the maps file can  */
 
211
    /* essentially shrink asynchronously and unexpectedly as    */
 
212
    /* threads that we already think of as dead release their   */
 
213
    /* stacks.  And there is no easy way to read the entire     */
 
214
    /* file atomically.  This is arguably a misfeature of the   */
 
215
    /* /proc/.../maps interface.                                */
 
216
 
 
217
    /* Since we dont believe the file can grow                  */
 
218
    /* asynchronously, it should suffice to first determine     */
 
219
    /* the size (using lseek or read), and then to reread the   */
 
220
    /* file.  If the size is inconsistent we have to retry.     */
 
221
    /* This only matters with threads enabled, and if we use    */
 
222
    /* this to locate roots (not the default).                  */
 
223
 
 
224
    /* Determine the initial size of /proc/self/maps.           */
 
225
    /* Note that lseek doesn't work, at least as of 2.6.15.     */
 
226
#   ifdef THREADS
 
227
        maps_size = GC_get_maps_len();
 
228
        if (0 == maps_size) return 0;
 
229
#   else
 
230
        maps_size = 4000;       /* Guess */
 
231
#   endif
214
232
 
215
233
    /* Read /proc/self/maps, growing maps_buf as necessary.     */
216
 
        /* Note that we may not allocate conventionally, and    */
217
 
        /* thus can't use stdio.                                */
 
234
    /* Note that we may not allocate conventionally, and        */
 
235
    /* thus can't use stdio.                                    */
218
236
        do {
219
 
            if (maps_size >= maps_buf_sz) {
 
237
            while (maps_size >= maps_buf_sz) {
220
238
              /* Grow only by powers of 2, since we leak "too small" buffers. */
221
239
              while (maps_size >= maps_buf_sz) maps_buf_sz *= 2;
222
240
              maps_buf = GC_scratch_alloc(maps_buf_sz);
 
241
#             ifdef THREADS
 
242
                /* Recompute initial length, since we allocated.        */
 
243
                /* This can only happen a few times per program         */
 
244
                /* execution.                                           */
 
245
                maps_size = GC_get_maps_len();
 
246
                if (0 == maps_size) return 0;
 
247
#             endif
223
248
              if (maps_buf == 0) return 0;
224
249
            }
 
250
            GC_ASSERT(maps_buf_sz >= maps_size + 1);
225
251
            f = open("/proc/self/maps", O_RDONLY);
226
252
            if (-1 == f) return 0;
 
253
#           ifdef THREADS
 
254
              old_maps_size = maps_size;
 
255
#           endif
227
256
            maps_size = 0;
228
257
            do {
229
258
                result = GC_repeat_read(f, maps_buf, maps_buf_sz-1);
231
260
                maps_size += result;
232
261
            } while (result == maps_buf_sz-1);
233
262
            close(f);
234
 
        } while (maps_size >= maps_buf_sz);
 
263
#           ifdef THREADS
 
264
              if (maps_size > old_maps_size) {
 
265
                GC_err_printf("Old maps size = %d, new maps size = %d\n",
 
266
                              old_maps_size, maps_size);
 
267
                ABORT("Unexpected asynchronous /proc/self/maps growth: "
 
268
                      "Unregistered thread?");
 
269
              }
 
270
#           endif
 
271
        } while (maps_size >= maps_buf_sz || maps_size < old_maps_size);
 
272
                /* In the single-threaded case, the second clause is false.     */
235
273
        maps_buf[maps_size] = '\0';
236
274
        
237
275
    /* Apply fn to result. */
238
 
        return fn(maps_buf);
 
276
        return maps_buf;
239
277
}
240
278
 
241
 
#endif /* Need GC_apply_to_maps */
242
 
 
243
 
#if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64))
244
279
//
245
280
//  GC_parse_map_entry parses an entry from /proc/self/maps so we can
246
281
//  locate all writable data segments that belong to shared libraries.
250
285
//  ^^^^^^^^ ^^^^^^^^ ^^^^          ^^
251
286
//  start    end      prot          maj_dev
252
287
//
253
 
//  Note that since about auguat 2003 kernels, the columns no longer have
 
288
//  Note that since about august 2003 kernels, the columns no longer have
254
289
//  fixed offsets on 64-bit kernels.  Hence we no longer rely on fixed offsets
255
290
//  anywhere, which is safer anyway.
256
291
//
257
292
 
258
293
/*
259
294
 * Assign various fields of the first line in buf_ptr to *start, *end,
260
 
 * *prot_buf and *maj_dev.  Only *prot_buf may be set for unwritable maps.
 
295
 * *prot, *maj_dev and *mapping_name.  Mapping_name may be NULL.
 
296
 * *prot and *mapping_name are assigned pointers into the original
 
297
 * buffer.
261
298
 */
262
 
char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
263
 
                                char *prot_buf, unsigned int *maj_dev)
 
299
char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
 
300
                                char **prot, unsigned int *maj_dev,
 
301
                                char **mapping_name)
264
302
{
265
 
    char *start_start, *end_start, *prot_start, *maj_dev_start;
 
303
    char *start_start, *end_start, *maj_dev_start;
266
304
    char *p;
267
305
    char *endp;
268
306
 
274
312
    while (isspace(*p)) ++p;
275
313
    start_start = p;
276
314
    GC_ASSERT(isxdigit(*start_start));
277
 
    *start = strtoul(start_start, &endp, 16); p = endp;
 
315
    *start = (ptr_t)strtoul(start_start, &endp, 16); p = endp;
278
316
    GC_ASSERT(*p=='-');
279
317
 
280
318
    ++p;
281
319
    end_start = p;
282
320
    GC_ASSERT(isxdigit(*end_start));
283
 
    *end = strtoul(end_start, &endp, 16); p = endp;
 
321
    *end = (ptr_t)strtoul(end_start, &endp, 16); p = endp;
284
322
    GC_ASSERT(isspace(*p));
285
323
 
286
324
    while (isspace(*p)) ++p;
287
 
    prot_start = p;
288
 
    GC_ASSERT(*prot_start == 'r' || *prot_start == '-');
289
 
    memcpy(prot_buf, prot_start, 4);
290
 
    prot_buf[4] = '\0';
291
 
    if (prot_buf[1] == 'w') {/* we can skip the rest if it's not writable. */
292
 
        /* Skip past protection field to offset field */
293
 
          while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
294
 
          GC_ASSERT(isxdigit(*p));
295
 
        /* Skip past offset field, which we ignore */
296
 
          while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
297
 
        maj_dev_start = p;
298
 
        GC_ASSERT(isxdigit(*maj_dev_start));
299
 
        *maj_dev = strtoul(maj_dev_start, NULL, 16);
 
325
    GC_ASSERT(*p == 'r' || *p == '-');
 
326
    *prot = p;
 
327
    /* Skip past protection field to offset field */
 
328
       while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
 
329
    GC_ASSERT(isxdigit(*p));
 
330
    /* Skip past offset field, which we ignore */
 
331
          while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
 
332
    maj_dev_start = p;
 
333
    GC_ASSERT(isxdigit(*maj_dev_start));
 
334
    *maj_dev = strtoul(maj_dev_start, NULL, 16);
 
335
 
 
336
    if (mapping_name == 0) {
 
337
      while (*p && *p++ != '\n');
 
338
    } else {
 
339
      while (*p && *p != '\n' && *p != '/' && *p != '[') p++;
 
340
      *mapping_name = p;
 
341
      while (*p && *p++ != '\n');
300
342
    }
301
343
 
302
 
    while (*p && *p++ != '\n');
303
 
 
304
344
    return p;
305
345
}
306
346
 
307
 
#endif /* Need to parse /proc/self/maps. */     
 
347
/* Try to read the backing store base from /proc/self/maps.             */
 
348
/* Return the bounds of the writable mapping with a 0 major device,     */
 
349
/* which includes the address passed as data.                           */
 
350
/* Return FALSE if there is no such mapping.                            */
 
351
GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp, ptr_t *endp)
 
352
{
 
353
  char *prot;
 
354
  ptr_t my_start, my_end;
 
355
  unsigned int maj_dev;
 
356
  char *maps = GC_get_maps();
 
357
  char *buf_ptr = maps;
 
358
  
 
359
  if (0 == maps) return(FALSE);
 
360
  for (;;) {
 
361
    buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,
 
362
                                 &prot, &maj_dev, 0);
 
363
 
 
364
    if (buf_ptr == NULL) return FALSE;
 
365
    if (prot[1] == 'w' && maj_dev == 0) {
 
366
        if (my_end > addr && my_start <= addr) {
 
367
          *startp = my_start;
 
368
          *endp = my_end;
 
369
          return TRUE;
 
370
        }
 
371
    }
 
372
  }
 
373
  return FALSE;
 
374
}
 
375
 
 
376
#if defined(REDIRECT_MALLOC)
 
377
/* Find the text(code) mapping for the library whose name, after        */
 
378
/* stripping the directory part, starts with nm.                        */
 
379
GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp)
 
380
{
 
381
  size_t nm_len = strlen(nm);
 
382
  char *prot;
 
383
  char *map_path;
 
384
  ptr_t my_start, my_end;
 
385
  unsigned int maj_dev;
 
386
  char *maps = GC_get_maps();
 
387
  char *buf_ptr = maps;
 
388
  
 
389
  if (0 == maps) return(FALSE);
 
390
  for (;;) {
 
391
    buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,
 
392
                                 &prot, &maj_dev, &map_path);
 
393
 
 
394
    if (buf_ptr == NULL) return FALSE;
 
395
    if (prot[0] == 'r' && prot[1] == '-' && prot[2] == 'x') {
 
396
        char *p = map_path;
 
397
        /* Set p to point just past last slash, if any. */
 
398
          while (*p != '\0' && *p != '\n' && *p != ' ' && *p != '\t') ++p;
 
399
          while (*p != '/' && p >= map_path) --p;
 
400
          ++p;
 
401
        if (strncmp(nm, p, nm_len) == 0) {
 
402
          *startp = my_start;
 
403
          *endp = my_end;
 
404
          return TRUE;
 
405
        }
 
406
    }
 
407
  }
 
408
  return FALSE;
 
409
}
 
410
#endif /* REDIRECT_MALLOC */
 
411
 
 
412
#ifdef IA64
 
413
static ptr_t backing_store_base_from_proc(void)
 
414
{
 
415
    ptr_t my_start, my_end;
 
416
    if (!GC_enclosing_mapping(GC_save_regs_in_stack(), &my_start, &my_end)) {
 
417
        if (GC_print_stats) {
 
418
            GC_log_printf("Failed to find backing store base from /proc\n");
 
419
        }
 
420
        return 0;
 
421
    }
 
422
    return my_start;
 
423
}
 
424
#endif
 
425
 
 
426
#endif /* NEED_PROC_MAPS */     
308
427
 
309
428
#if defined(SEARCH_FOR_DATA_START)
310
429
  /* The I386 case can be handled without a search.  The Alpha case     */
312
431
  /* for recent Linux versions.  This seems to be the easiest way to    */
313
432
  /* cover all versions.                                                */
314
433
 
315
 
# ifdef LINUX
 
434
# if defined(LINUX) || defined(HURD)
316
435
    /* Some Linux distributions arrange to define __data_start.  Some   */
317
436
    /* define data_start as a weak symbol.  The latter is technically   */
318
437
    /* broken, since the user program may define data_start, in which   */
329
448
 
330
449
  void GC_init_linux_data_start()
331
450
  {
332
 
    extern ptr_t GC_find_limit();
 
451
    extern ptr_t GC_find_limit(ptr_t, GC_bool);
333
452
 
334
 
#   ifdef LINUX
 
453
#   if defined(LINUX) || defined(HURD)
335
454
      /* Try the easy approaches first: */
336
455
      if ((ptr_t)__data_start != 0) {
337
456
          GC_data_start = (ptr_t)(__data_start);
352
471
# define ECOS_GC_MEMORY_SIZE (448 * 1024)
353
472
# endif /* ECOS_GC_MEMORY_SIZE */
354
473
 
355
 
// setjmp() function, as described in ANSI para 7.6.1.1
356
 
#undef SETJMP
357
 
#define SETJMP( __env__ )  hal_setjmp( __env__ )
358
 
 
359
474
// FIXME: This is a simple way of allocating memory which is
360
475
// compatible with ECOS early releases.  Later releases use a more
361
476
// sophisticated means of allocating memory than this simple static
383
498
#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
384
499
  ptr_t GC_data_start;
385
500
 
386
 
  void GC_init_netbsd_elf()
 
501
  void GC_init_netbsd_elf(void)
387
502
  {
388
 
    extern ptr_t GC_find_limit();
 
503
    extern ptr_t GC_find_limit(ptr_t, GC_bool);
389
504
    extern char **environ;
390
505
        /* This may need to be environ, without the underscore, for     */
391
506
        /* some versions.                                               */
501
616
      && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW) \
502
617
      && !defined(NOSYS) && !defined(ECOS)
503
618
 
504
 
#   if defined(sigmask) && !defined(UTS4) && !defined(HURD)
 
619
#   if 0
505
620
        /* Use the traditional BSD interface */
506
621
#       define SIGSET_T int
507
622
#       define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))
510
625
          /* longjmp implementations.  Most systems appear not to have  */
511
626
          /* a signal 32.                                               */
512
627
#       define SIGSETMASK(old, new) (old) = sigsetmask(new)
513
 
#   else
514
 
        /* Use POSIX/SYSV interface     */
515
 
#       define SIGSET_T sigset_t
516
 
#       define SIG_DEL(set, signal) sigdelset(&(set), (signal))
517
 
#       define SIG_FILL(set) sigfillset(&set)
518
 
#       define SIGSETMASK(old, new) sigprocmask(SIG_SETMASK, &(new), &(old))
519
628
#   endif
520
629
 
 
630
    /* Use POSIX/SYSV interface */
 
631
#   define SIGSET_T sigset_t
 
632
#   define SIG_DEL(set, signal) sigdelset(&(set), (signal))
 
633
#   define SIG_FILL(set) sigfillset(&set)
 
634
#   define SIGSETMASK(old, new) sigprocmask(SIG_SETMASK, &(new), &(old))
 
635
 
 
636
 
521
637
static GC_bool mask_initialized = FALSE;
522
638
 
523
639
static SIGSET_T new_mask;
526
642
 
527
643
static SIGSET_T dummy;
528
644
 
529
 
#if defined(PRINTSTATS) && !defined(THREADS)
 
645
#if defined(GC_ASSERTIONS) && !defined(THREADS)
530
646
# define CHECK_SIGNALS
531
647
  int GC_sig_disabled = 0;
532
648
#endif
533
649
 
534
 
void GC_disable_signals()
 
650
void GC_disable_signals(void)
535
651
{
536
652
    if (!mask_initialized) {
537
653
        SIG_FILL(new_mask);
560
676
    SIGSETMASK(old_mask,new_mask);
561
677
}
562
678
 
563
 
void GC_enable_signals()
 
679
void GC_enable_signals(void)
564
680
{
565
681
#   ifdef CHECK_SIGNALS
566
682
        if (GC_sig_disabled != 1) ABORT("Unmatched enable");
583
699
word GC_page_size;
584
700
 
585
701
# if defined(MSWIN32) || defined(MSWINCE)
586
 
  void GC_setpagesize()
 
702
  void GC_setpagesize(void)
587
703
  {
588
704
    GetSystemInfo(&GC_sysinfo);
589
705
    GC_page_size = GC_sysinfo.dwPageSize;
590
706
  }
591
707
 
592
708
# else
593
 
#   if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP) \
594
 
       || defined(USE_MUNMAP)
595
 
        void GC_setpagesize()
 
709
#   if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP)
 
710
        void GC_setpagesize(void)
596
711
        {
597
712
            GC_page_size = GETPAGESIZE();
598
713
        }
599
714
#   else
600
715
        /* It's acceptable to fake it. */
601
 
        void GC_setpagesize()
 
716
        void GC_setpagesize(void)
602
717
        {
603
718
            GC_page_size = HBLKSIZE;
604
719
        }
611
726
 * With threads, GC_mark_roots needs to know how to do this.
612
727
 * Called with allocator lock held.
613
728
 */
614
 
# if defined(MSWIN32) || defined(MSWINCE)
 
729
# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
615
730
# define is_writable(prot) ((prot) == PAGE_READWRITE \
616
731
                            || (prot) == PAGE_WRITECOPY \
617
732
                            || (prot) == PAGE_EXECUTE_READWRITE \
637
752
    return(buf.RegionSize);
638
753
}
639
754
 
640
 
ptr_t GC_get_stack_base()
 
755
GC_API int GC_get_stack_base(struct GC_stack_base *sb)
641
756
{
642
757
    int dummy;
643
758
    ptr_t sp = (ptr_t)(&dummy);
644
759
    ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_page_size - 1));
645
760
    word size = GC_get_writable_length(trunc_sp, 0);
646
761
   
647
 
    return(trunc_sp + size);
648
 
}
649
 
 
 
762
    sb -> mem_base = trunc_sp + size;
 
763
    return GC_SUCCESS;
 
764
}
 
765
 
 
766
#define HAVE_GET_STACK_BASE
 
767
 
 
768
/* This is always called from the main thread.  */
 
769
ptr_t GC_get_main_stack_base(void)
 
770
{
 
771
    struct GC_stack_base sb;
 
772
 
 
773
    GC_get_stack_base(&sb);
 
774
    return (ptr_t)sb.mem_base;
 
775
}
650
776
 
651
777
# endif /* MS Windows */
652
778
 
653
779
# ifdef BEOS
654
780
# include <kernel/OS.h>
655
 
ptr_t GC_get_stack_base(){
 
781
ptr_t GC_get_main_stack_base(void){
656
782
        thread_info th;
657
783
        get_thread_info(find_thread(NULL),&th);
658
784
        return th.stack_end;
662
788
 
663
789
# ifdef OS2
664
790
 
665
 
ptr_t GC_get_stack_base()
 
791
ptr_t GC_get_main_stack_base(void)
666
792
{
667
793
    PTIB ptib;
668
794
    PPIB ppib;
669
795
    
670
796
    if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
671
 
        GC_err_printf0("DosGetInfoBlocks failed\n");
 
797
        GC_err_printf("DosGetInfoBlocks failed\n");
672
798
        ABORT("DosGetInfoBlocks failed\n");
673
799
    }
674
800
    return((ptr_t)(ptib -> tib_pstacklimit));
684
810
 
685
811
# if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
686
812
 
687
 
#   ifdef __STDC__
688
 
        typedef void (*handler)(int);
689
 
#   else
690
 
        typedef void (*handler)();
691
 
#   endif
 
813
    typedef void (*handler)(int);
692
814
 
693
815
#   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
694
816
    || defined(HURD) || defined(NETBSD)
695
817
        static struct sigaction old_segv_act;
696
 
#       if defined(IRIX5) || defined(HPUX) \
 
818
#       if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) \
697
819
        || defined(HURD) || defined(NETBSD)
698
820
            static struct sigaction old_bus_act;
699
821
#       endif
701
823
        static handler old_segv_handler, old_bus_handler;
702
824
#   endif
703
825
    
704
 
#   ifdef __STDC__
705
 
      void GC_set_and_save_fault_handler(handler h)
706
 
#   else
707
 
      void GC_set_and_save_fault_handler(h)
708
 
      handler h;
709
 
#   endif
 
826
    void GC_set_and_save_fault_handler(handler h)
710
827
    {
711
828
#       if defined(SUNOS5SIGS) || defined(IRIX5)  \
712
829
        || defined(OSF1) || defined(HURD) || defined(NETBSD)
726
843
                /* and setting a handler at the same time.              */
727
844
                (void) sigaction(SIGSEGV, 0, &old_segv_act);
728
845
                (void) sigaction(SIGSEGV, &act, 0);
729
 
                (void) sigaction(SIGBUS, 0, &old_bus_act);
730
 
                (void) sigaction(SIGBUS, &act, 0);
731
846
#         else
732
847
                (void) sigaction(SIGSEGV, &act, &old_segv_act);
733
 
#               if defined(IRIX5) \
 
848
#               if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
734
849
                   || defined(HPUX) || defined(HURD) || defined(NETBSD)
735
850
                    /* Under Irix 5.x or HP/UX, we may get SIGBUS.      */
736
851
                    /* Pthreads doesn't exist under Irix 5.x, so we     */
747
862
    }
748
863
# endif /* NEED_FIND_LIMIT || UNIX_LIKE */
749
864
 
750
 
# ifdef NEED_FIND_LIMIT
 
865
# if defined(NEED_FIND_LIMIT) || \
 
866
     defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS)
751
867
  /* Some tools to implement HEURISTIC2 */
752
868
#   define MIN_PAGE_SIZE 256    /* Smallest conceivable page size, bytes */
753
 
    /* static */ JMP_BUF GC_jmp_buf;
754
869
    
755
870
    /*ARGSUSED*/
756
 
    void GC_fault_handler(sig)
757
 
    int sig;
 
871
    void GC_fault_handler(int sig)
758
872
    {
759
873
        LONGJMP(GC_jmp_buf, 1);
760
874
    }
761
875
 
762
 
    void GC_setup_temporary_fault_handler()
 
876
    void GC_setup_temporary_fault_handler(void)
763
877
    {
 
878
        /* Handler is process-wide, so this should only happen in */
 
879
        /* one thread at a time.                                  */
 
880
        GC_ASSERT(I_HOLD_LOCK());
764
881
        GC_set_and_save_fault_handler(GC_fault_handler);
765
882
    }
766
883
    
767
 
    void GC_reset_fault_handler()
 
884
    void GC_reset_fault_handler(void)
768
885
    {
769
886
#       if defined(SUNOS5SIGS) || defined(IRIX5) \
770
887
           || defined(OSF1) || defined(HURD) || defined(NETBSD)
771
888
          (void) sigaction(SIGSEGV, &old_segv_act, 0);
772
 
#         if defined(IRIX5) \
 
889
#         if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
773
890
             || defined(HPUX) || defined(HURD) || defined(NETBSD)
774
891
              (void) sigaction(SIGBUS, &old_bus_act, 0);
775
892
#         endif
784
901
    /* Return the first nonaddressible location > p (up) or     */
785
902
    /* the smallest location q s.t. [q,p) is addressable (!up). */
786
903
    /* We assume that p (up) or p-1 (!up) is addressable.       */
787
 
    ptr_t GC_find_limit(p, up)
788
 
    ptr_t p;
789
 
    GC_bool up;
 
904
    /* Requires allocation lock.                                */
 
905
    ptr_t GC_find_limit_with_bound(ptr_t p, GC_bool up, ptr_t bound)
790
906
    {
791
 
        static VOLATILE ptr_t result;
792
 
                /* Needs to be static, since otherwise it may not be    */
 
907
        static volatile ptr_t result;
 
908
                /* Safer if static, since otherwise it may not be       */
793
909
                /* preserved across the longjmp.  Can safely be         */
794
 
                /* static since it's only called once, with the         */
 
910
                /* static since it's only called with the               */
795
911
                /* allocation lock held.                                */
796
912
 
797
 
 
 
913
        GC_ASSERT(I_HOLD_LOCK());
798
914
        GC_setup_temporary_fault_handler();
799
915
        if (SETJMP(GC_jmp_buf) == 0) {
800
916
            result = (ptr_t)(((word)(p))
802
918
            for (;;) {
803
919
                if (up) {
804
920
                    result += MIN_PAGE_SIZE;
 
921
                    if (result >= bound) return bound;
805
922
                } else {
806
923
                    result -= MIN_PAGE_SIZE;
 
924
                    if (result <= bound) return bound;
807
925
                }
808
926
                GC_noop1((word)(*result));
809
927
            }
814
932
        }
815
933
        return(result);
816
934
    }
 
935
 
 
936
    ptr_t GC_find_limit(ptr_t p, GC_bool up)
 
937
    {
 
938
      if (up) {
 
939
        return GC_find_limit_with_bound(p, up, (ptr_t)(word)(-1));
 
940
      } else {
 
941
        return GC_find_limit_with_bound(p, up, 0);
 
942
      }
 
943
    }
817
944
# endif
818
945
 
819
946
#if defined(ECOS) || defined(NOSYS)
820
 
  ptr_t GC_get_stack_base()
 
947
  ptr_t GC_get_main_stack_base(void)
821
948
  {
822
949
    return STACKBOTTOM;
823
950
  }
860
987
#endif
861
988
 
862
989
# ifdef IA64
863
 
    /* Try to read the backing store base from /proc/self/maps. */
864
 
    /* We look for the writable mapping with a 0 major device,  */
865
 
    /* which is as close to our frame as possible, but below it.*/
866
 
    static word backing_store_base_from_maps(char *maps)
867
 
    {
868
 
      char prot_buf[5];
869
 
      char *buf_ptr = maps;
870
 
      word start, end;
871
 
      unsigned int maj_dev;
872
 
      word current_best = 0;
873
 
      word dummy;
874
 
  
875
 
      for (;;) {
876
 
        buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
877
 
        if (buf_ptr == NULL) return current_best;
878
 
        if (prot_buf[1] == 'w' && maj_dev == 0) {
879
 
            if (end < (word)(&dummy) && start > current_best) current_best = start;
880
 
        }
881
 
      }
882
 
      return current_best;
883
 
    }
884
 
 
885
 
    static word backing_store_base_from_proc(void)
886
 
    {
887
 
        return GC_apply_to_maps(backing_store_base_from_maps);
888
 
    }
889
 
 
890
990
#   ifdef USE_LIBC_PRIVATES
891
991
#     pragma weak __libc_ia64_register_backing_store_base
892
992
      extern ptr_t __libc_ia64_register_backing_store_base;
894
994
 
895
995
    ptr_t GC_get_register_stack_base(void)
896
996
    {
 
997
      ptr_t result;
 
998
 
897
999
#     ifdef USE_LIBC_PRIVATES
898
1000
        if (0 != &__libc_ia64_register_backing_store_base
899
1001
            && 0 != __libc_ia64_register_backing_store_base) {
904
1006
          return __libc_ia64_register_backing_store_base;
905
1007
        }
906
1008
#     endif
907
 
      word result = backing_store_base_from_proc();
 
1009
      result = backing_store_base_from_proc();
908
1010
      if (0 == result) {
909
 
          /* Use dumb heuristics.  Works only for default configuration. */
910
 
          result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
911
 
          result += BACKING_STORE_ALIGNMENT - 1;
912
 
          result &= ~(BACKING_STORE_ALIGNMENT - 1);
913
 
          /* Verify that it's at least readable.  If not, we goofed. */
914
 
          GC_noop1(*(word *)result); 
 
1011
          result = GC_find_limit(GC_save_regs_in_stack(), FALSE);
 
1012
          /* Now seems to work better than constant displacement        */
 
1013
          /* heuristic used in 6.X versions.  The latter seems to       */
 
1014
          /* fail for 2.6 kernels.                                      */
915
1015
      }
916
 
      return (ptr_t)result;
 
1016
      return result;
917
1017
    }
918
1018
# endif
919
1019
 
938
1038
    /* this.                                                    */  
939
1039
#   ifdef USE_LIBC_PRIVATES
940
1040
      if (0 != &__libc_stack_end && 0 != __libc_stack_end ) {
941
 
#       ifdef IA64
 
1041
#       if defined(IA64)
942
1042
          /* Some versions of glibc set the address 16 bytes too        */
943
1043
          /* low while the initialization code is running.              */
944
1044
          if (((word)__libc_stack_end & 0xfff) + 0x10 < 0x1000) {
945
1045
            return __libc_stack_end + 0x10;
946
1046
          } /* Otherwise it's not safe to add 16 bytes and we fall      */
947
1047
            /* back to using /proc.                                     */
948
 
#       else 
949
 
#       ifdef SPARC
 
1048
#       elif defined(SPARC)
950
1049
          /* Older versions of glibc for 64-bit Sparc do not set
951
1050
           * this variable correctly, it gets set to either zero
952
1051
           * or one.
956
1055
#       else
957
1056
          return __libc_stack_end;
958
1057
#       endif
959
 
#       endif
960
1058
      }
961
1059
#   endif
962
1060
    f = open("/proc/self/stat", O_RDONLY);
1007
1105
#endif /* FREEBSD_STACKBOTTOM */
1008
1106
 
1009
1107
#if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \
1010
 
    && !defined(MSWINCE) && !defined(OS2) && !defined(NOSYS) && !defined(ECOS)
 
1108
    && !defined(MSWINCE) && !defined(OS2) && !defined(NOSYS) && !defined(ECOS) \
 
1109
    && !defined(CYGWIN32)
1011
1110
 
1012
 
ptr_t GC_get_stack_base()
 
1111
ptr_t GC_get_main_stack_base(void)
1013
1112
{
1014
 
#   if defined(HEURISTIC1) || defined(HEURISTIC2) || \
1015
 
       defined(LINUX_STACKBOTTOM) || defined(FREEBSD_STACKBOTTOM)
1016
 
    word dummy;
 
1113
#   if defined(HEURISTIC1) || defined(HEURISTIC2)
 
1114
      word dummy;
 
1115
#   endif
1017
1116
    ptr_t result;
1018
 
#   endif
1019
1117
 
1020
1118
#   define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
1021
1119
 
1067
1165
 
1068
1166
# endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS, !NOSYS, !ECOS */
1069
1167
 
 
1168
#if defined(GC_LINUX_THREADS) && !defined(HAVE_GET_STACK_BASE)
 
1169
 
 
1170
#include <pthread.h>
 
1171
 
 
1172
#ifdef IA64
 
1173
  ptr_t GC_greatest_stack_base_below(ptr_t bound);
 
1174
        /* From pthread_support.c */
 
1175
#endif
 
1176
 
 
1177
int GC_get_stack_base(struct GC_stack_base *b)
 
1178
{
 
1179
    pthread_attr_t attr;
 
1180
    size_t size;
 
1181
 
 
1182
    if (pthread_getattr_np(pthread_self(), &attr) != 0) {
 
1183
        WARN("pthread_getattr_np failed\n", 0);
 
1184
        return GC_UNIMPLEMENTED;
 
1185
    }
 
1186
    if (pthread_attr_getstack(&attr, &(b -> mem_base), &size) != 0) {
 
1187
        ABORT("pthread_attr_getstack failed");
 
1188
    }
 
1189
#   ifdef STACK_GROWS_DOWN
 
1190
        b -> mem_base = (char *)(b -> mem_base) + size;
 
1191
#   endif
 
1192
#   ifdef IA64
 
1193
      /* We could try backing_store_base_from_proc, but that's safe     */
 
1194
      /* only if no mappings are being asynchronously created.          */
 
1195
      /* Subtracting the size from the stack base doesn't work for at   */
 
1196
      /* least the main thread.                                         */
 
1197
      LOCK();
 
1198
      {
 
1199
        ptr_t bsp = GC_save_regs_in_stack();
 
1200
        ptr_t next_stack = GC_greatest_stack_base_below(bsp);
 
1201
        if (0 == next_stack) {
 
1202
          b -> reg_base = GC_find_limit(bsp, FALSE);
 
1203
        } else {
 
1204
          /* Avoid walking backwards into preceding memory stack and    */
 
1205
          /* growing it.                                                */
 
1206
          b -> reg_base = GC_find_limit_with_bound(bsp, FALSE, next_stack);
 
1207
        }
 
1208
      }
 
1209
      UNLOCK();
 
1210
#   endif
 
1211
    return GC_SUCCESS;
 
1212
}
 
1213
 
 
1214
#define HAVE_GET_STACK_BASE
 
1215
 
 
1216
#endif /* GC_LINUX_THREADS */
 
1217
 
 
1218
#ifndef HAVE_GET_STACK_BASE
 
1219
/* Retrieve stack base.                                         */
 
1220
/* Using the GC_find_limit version is risky.                    */
 
1221
/* On IA64, for example, there is no guard page between the     */
 
1222
/* stack of one thread and the register backing store of the    */
 
1223
/* next.  Thus this is likely to identify way too large a       */
 
1224
/* "stack" and thus at least result in disastrous performance.  */
 
1225
/* FIXME - Implement better strategies here.                    */
 
1226
int GC_get_stack_base(struct GC_stack_base *b)
 
1227
{
 
1228
    int dummy;
 
1229
 
 
1230
#   ifdef NEED_FIND_LIMIT
 
1231
#     ifdef STACK_GROWS_DOWN
 
1232
        b -> mem_base = GC_find_limit((ptr_t)(&dummy), TRUE);
 
1233
#       ifdef IA64
 
1234
          b -> reg_base = GC_find_limit(GC_save_regs_in_stack(), FALSE);
 
1235
#       endif
 
1236
#     else
 
1237
        b -> mem_base = GC_find_limit(&dummy, FALSE);
 
1238
#     endif
 
1239
      return GC_SUCCESS;
 
1240
#   else
 
1241
      return GC_UNIMPLEMENTED;
 
1242
#   endif
 
1243
}
 
1244
#endif
 
1245
 
1070
1246
/*
1071
1247
 * Register static data segment(s) as roots.
1072
1248
 * If more data segments are added later then they need to be registered
1077
1253
 
1078
1254
# ifdef OS2
1079
1255
 
1080
 
void GC_register_data_segments()
 
1256
void GC_register_data_segments(void)
1081
1257
{
1082
1258
    PTIB ptib;
1083
1259
    PPIB ppib;
1092
1268
    
1093
1269
    
1094
1270
    if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
1095
 
        GC_err_printf0("DosGetInfoBlocks failed\n");
 
1271
        GC_err_printf("DosGetInfoBlocks failed\n");
1096
1272
        ABORT("DosGetInfoBlocks failed\n");
1097
1273
    }
1098
1274
    module_handle = ppib -> pib_hmte;
1099
1275
    if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) {
1100
 
        GC_err_printf0("DosQueryModuleName failed\n");
 
1276
        GC_err_printf("DosQueryModuleName failed\n");
1101
1277
        ABORT("DosGetInfoBlocks failed\n");
1102
1278
    }
1103
1279
    myexefile = fopen(path, "rb");
1158
1334
      if (!(flags & OBJWRITE)) continue;
1159
1335
      if (!(flags & OBJREAD)) continue;
1160
1336
      if (flags & OBJINVALID) {
1161
 
          GC_err_printf0("Object with invalid pages?\n");
 
1337
          GC_err_printf("Object with invalid pages?\n");
1162
1338
          continue;
1163
1339
      } 
1164
1340
      GC_add_roots_inner(O32_BASE(seg), O32_BASE(seg)+O32_SIZE(seg), FALSE);
1181
1357
        /* This used to be set for gcc, to avoid dealing with           */
1182
1358
        /* the structured exception handling issues.  But we now have   */
1183
1359
        /* assembly code to do that right.                              */
 
1360
 
 
1361
# if defined(GWW_VDB)
 
1362
 
 
1363
#   ifndef _BASETSD_H_
 
1364
      typedef ULONG * PULONG_PTR;
 
1365
#   endif
 
1366
    typedef UINT (WINAPI * GetWriteWatch_type)(
 
1367
      DWORD, PVOID, SIZE_T, PVOID*, PULONG_PTR, PULONG);
 
1368
    static GetWriteWatch_type GetWriteWatch_func;
 
1369
    static DWORD GetWriteWatch_alloc_flag;
 
1370
 
 
1371
#   define GC_GWW_AVAILABLE() (GetWriteWatch_func != NULL)
 
1372
 
 
1373
    static void detect_GetWriteWatch(void)
 
1374
    {
 
1375
      static GC_bool done;
 
1376
      if (done)
 
1377
        return;
 
1378
 
 
1379
      GetWriteWatch_func = (GetWriteWatch_type)
 
1380
        GetProcAddress(GetModuleHandle("kernel32.dll"), "GetWriteWatch");
 
1381
      if (GetWriteWatch_func != NULL) {
 
1382
        /* Also check whether VirtualAlloc accepts MEM_WRITE_WATCH,   */
 
1383
        /* as some versions of kernel32.dll have one but not the      */
 
1384
        /* other, making the feature completely broken.               */
 
1385
        void * page = VirtualAlloc(NULL, GC_page_size,
 
1386
                                    MEM_WRITE_WATCH | MEM_RESERVE,
 
1387
                                    PAGE_READWRITE);
 
1388
        if (page != NULL) {
 
1389
          PVOID pages[16];
 
1390
          ULONG_PTR count = 16;
 
1391
          DWORD page_size;
 
1392
          /* Check that it actually works.  In spite of some            */
 
1393
          /* documentation it actually seems to exist on W2K.           */
 
1394
          /* This test may be unnecessary, but ...                      */
 
1395
          if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
 
1396
                                 page, GC_page_size,
 
1397
                                 pages,
 
1398
                                 &count,
 
1399
                                 &page_size) != 0) {
 
1400
            /* GetWriteWatch always fails. */
 
1401
            GetWriteWatch_func = NULL;
 
1402
          } else {
 
1403
            GetWriteWatch_alloc_flag = MEM_WRITE_WATCH;
 
1404
          }
 
1405
          VirtualFree(page, GC_page_size, MEM_RELEASE);
 
1406
        } else {
 
1407
          /* GetWriteWatch will be useless. */
 
1408
          GetWriteWatch_func = NULL;
 
1409
        }
 
1410
      }
 
1411
      if (GC_print_stats) {
 
1412
        if (GetWriteWatch_func == NULL) {
 
1413
          GC_log_printf("Did not find a usable GetWriteWatch()\n");
 
1414
        } else {
 
1415
          GC_log_printf("Using GetWriteWatch()\n");
 
1416
        }
 
1417
      }
 
1418
      done = TRUE;
 
1419
    }
 
1420
 
 
1421
# endif /* GWW_VDB */
 
1422
 
1184
1423
  GC_bool GC_wnt = FALSE;
1185
 
        /* This is a Windows NT derivative, i.e. NT, W2K, XP or later.  */
 
1424
         /* This is a Windows NT derivative, i.e. NT, W2K, XP or later.  */
1186
1425
  
1187
 
  void GC_init_win32()
 
1426
  void GC_init_win32(void)
1188
1427
  {
1189
 
    /* if we're running under win32s, assume that no DLLs will be loaded */
 
1428
    /* Set GC_wnt.                                                       */
 
1429
    /* If we're running under win32s, assume that no DLLs will be loaded */
 
1430
    /* I doubt anyone still runs win32s, but ...                         */
1190
1431
    DWORD v = GetVersion();
1191
1432
    GC_wnt = !(v & 0x80000000);
1192
1433
    GC_no_win32_dlls |= ((!GC_wnt) && (v & 0xff) <= 3);
1198
1439
  ptr_t GC_least_described_address(ptr_t start)
1199
1440
  {  
1200
1441
    MEMORY_BASIC_INFORMATION buf;
1201
 
    DWORD result;
 
1442
    size_t result;
1202
1443
    LPVOID limit;
1203
1444
    ptr_t p;
1204
1445
    LPVOID q;
1212
1453
        if (result != sizeof(buf) || buf.AllocationBase == 0) break;
1213
1454
        p = (ptr_t)(buf.AllocationBase);
1214
1455
    }
1215
 
    return(p);
 
1456
    return p;
1216
1457
  }
1217
1458
# endif
1218
1459
 
1248
1489
  void *GC_get_allocation_base(void *p)
1249
1490
  {
1250
1491
    MEMORY_BASIC_INFORMATION buf;
1251
 
    DWORD result = VirtualQuery(p, &buf, sizeof(buf));
 
1492
    size_t result = VirtualQuery(p, &buf, sizeof(buf));
1252
1493
    if (result != sizeof(buf)) {
1253
1494
      ABORT("Weird VirtualQuery result");
1254
1495
    }
1279
1520
          free(new_l); return;
1280
1521
        }
1281
1522
    }
1282
 
#   ifdef CONDPRINT
1283
 
      if (GC_print_stats)
1284
 
          GC_printf1("Found new system malloc AllocationBase at 0x%lx\n",
1285
 
                     candidate);
1286
 
#   endif
 
1523
    if (GC_print_stats)
 
1524
          GC_log_printf("Found new system malloc AllocationBase at %p\n",
 
1525
                        candidate);
1287
1526
    new_l -> allocation_base = candidate;
1288
1527
    new_l -> next = GC_malloc_heap_l;
1289
1528
    GC_malloc_heap_l = new_l;
1298
1537
     unsigned i;
1299
1538
     
1300
1539
#    ifndef REDIRECT_MALLOC
1301
 
       static word last_gc_no = -1;
1302
 
     
1303
 
       if (last_gc_no != GC_gc_no) {
1304
 
         GC_add_current_malloc_heap();
1305
 
         last_gc_no = GC_gc_no;
1306
 
       }
1307
1540
       if (GC_root_size > GC_max_root_size) GC_max_root_size = GC_root_size;
1308
1541
       if (GC_is_malloc_heap_base(p)) return TRUE;
1309
1542
#    endif
1317
1550
  void GC_register_root_section(ptr_t static_root)
1318
1551
  {
1319
1552
      MEMORY_BASIC_INFORMATION buf;
1320
 
      DWORD result;
 
1553
      size_t result;
1321
1554
      DWORD protect;
1322
1555
      LPVOID p;
1323
1556
      char * base;
1360
1593
 
1361
1594
# if (defined(SVR4) || defined(AUX) || defined(DGUX) \
1362
1595
      || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
1363
 
ptr_t GC_SysVGetDataStart(max_page_size, etext_addr)
1364
 
int max_page_size;
1365
 
int * etext_addr;
 
1596
ptr_t GC_SysVGetDataStart(size_t max_page_size, ptr_t etext_addr)
1366
1597
{
1367
1598
    word text_end = ((word)(etext_addr) + sizeof(word) - 1)
1368
1599
                    & ~(sizeof(word) - 1);
1370
1601
    word next_page = ((text_end + (word)max_page_size - 1)
1371
1602
                      & ~((word)max_page_size - 1));
1372
1603
    word page_offset = (text_end & ((word)max_page_size - 1));
1373
 
    VOLATILE char * result = (char *)(next_page + page_offset);
 
1604
    volatile char * result = (char *)(next_page + page_offset);
1374
1605
    /* Note that this isnt equivalent to just adding            */
1375
1606
    /* max_page_size to &etext if &etext is at a page boundary  */
1376
1607
    
1398
1629
/* For now we don't assume that there is always an empty page after     */
1399
1630
/* etext.  But in some cases there actually seems to be slightly more.  */
1400
1631
/* This also deals with holes between read-only data and writable data. */
1401
 
ptr_t GC_FreeBSDGetDataStart(max_page_size, etext_addr)
1402
 
int max_page_size;
1403
 
int * etext_addr;
 
1632
ptr_t GC_FreeBSDGetDataStart(size_t max_page_size, ptr_t etext_addr)
1404
1633
{
1405
1634
    word text_end = ((word)(etext_addr) + sizeof(word) - 1)
1406
1635
                     & ~(sizeof(word) - 1);
1407
1636
        /* etext rounded to word boundary       */
1408
 
    VOLATILE word next_page = (text_end + (word)max_page_size - 1)
 
1637
    volatile word next_page = (text_end + (word)max_page_size - 1)
1409
1638
                              & ~((word)max_page_size - 1);
1410
 
    VOLATILE ptr_t result = (ptr_t)text_end;
 
1639
    volatile ptr_t result = (ptr_t)text_end;
1411
1640
    GC_setup_temporary_fault_handler();
1412
1641
    if (SETJMP(GC_jmp_buf) == 0) {
1413
1642
        /* Try reading at the address.                          */
1414
1643
        /* This should happen before there is another thread.   */
1415
1644
        for (; next_page < (word)(DATAEND); next_page += (word)max_page_size)
1416
 
            *(VOLATILE char *)next_page;
 
1645
            *(volatile char *)next_page;
1417
1646
        GC_reset_fault_handler();
1418
1647
    } else {
1419
1648
        GC_reset_fault_handler();
1434
1663
 
1435
1664
#else /* !OS2 && !Windows && !AMIGA */
1436
1665
 
1437
 
void GC_register_data_segments()
 
1666
void GC_register_data_segments(void)
1438
1667
{
1439
 
#   if !defined(PCR) && !defined(SRC_M3) && !defined(MACOS)
 
1668
#   if !defined(PCR) && !defined(MACOS)
1440
1669
#     if defined(REDIRECT_MALLOC) && defined(GC_SOLARIS_THREADS)
1441
1670
        /* As of Solaris 2.3, the Solaris threads implementation        */
1442
1671
        /* allocates the data structure for the initial thread with     */
1445
1674
        /* hanging from it.  We're on thin ice here ...                 */
1446
1675
        extern caddr_t sbrk();
1447
1676
 
1448
 
        GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);
 
1677
        GC_add_roots_inner(DATASTART, (ptr_t)sbrk(0), FALSE);
1449
1678
#     else
1450
 
        GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE);
 
1679
        GC_add_roots_inner(DATASTART, (ptr_t)(DATAEND), FALSE);
1451
1680
#       if defined(DATASTART2)
1452
 
         GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), FALSE);
 
1681
          GC_add_roots_inner(DATASTART2, (ptr_t)(DATAEND2), FALSE);
1453
1682
#       endif
1454
1683
#     endif
1455
1684
#   endif
1503
1732
        && !defined(MSWIN32) && !defined(MSWINCE) \
1504
1733
        && !defined(MACOS) && !defined(DOS4GW) && !defined(NONSTOP)
1505
1734
 
1506
 
# ifdef SUNOS4
1507
 
    extern caddr_t sbrk();
1508
 
# endif
1509
 
# ifdef __STDC__
1510
 
#   define SBRK_ARG_T ptrdiff_t
1511
 
# else
1512
 
#   define SBRK_ARG_T int
1513
 
# endif
1514
 
 
1515
 
 
1516
 
# if 0 && defined(RS6000)  /* We now use mmap */
1517
 
/* The compiler seems to generate speculative reads one past the end of */
1518
 
/* an allocated object.  Hence we need to make sure that the page       */
1519
 
/* following the last heap page is also mapped.                         */
1520
 
ptr_t GC_unix_get_mem(bytes)
1521
 
word bytes;
1522
 
{
1523
 
    caddr_t cur_brk = (caddr_t)sbrk(0);
1524
 
    caddr_t result;
1525
 
    SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
1526
 
    static caddr_t my_brk_val = 0;
1527
 
    
1528
 
    if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */
1529
 
    if (lsbs != 0) {
1530
 
        if((caddr_t)(sbrk(GC_page_size - lsbs)) == (caddr_t)(-1)) return(0);
1531
 
    }
1532
 
    if (cur_brk == my_brk_val) {
1533
 
        /* Use the extra block we allocated last time. */
1534
 
        result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
1535
 
        if (result == (caddr_t)(-1)) return(0);
1536
 
        result -= GC_page_size;
1537
 
    } else {
1538
 
        result = (ptr_t)sbrk(GC_page_size + (SBRK_ARG_T)bytes);
1539
 
        if (result == (caddr_t)(-1)) return(0);
1540
 
    }
1541
 
    my_brk_val = result + bytes + GC_page_size; /* Always page aligned */
1542
 
    return((ptr_t)result);
1543
 
}
1544
 
 
1545
 
#else  /* Not RS6000 */
1546
 
 
1547
 
#if defined(USE_MMAP) || defined(USE_MUNMAP)
 
1735
# define SBRK_ARG_T ptrdiff_t
 
1736
 
 
1737
#if defined(MMAP_SUPPORTED)
1548
1738
 
1549
1739
#ifdef USE_MMAP_FIXED
1550
1740
#   define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
1566
1756
# define OPT_MAP_ANON 0
1567
1757
#endif 
1568
1758
 
1569
 
#endif /* defined(USE_MMAP) || defined(USE_MUNMAP) */
1570
 
 
1571
 
#if defined(USE_MMAP)
1572
 
/* Tested only under Linux, IRIX5 and Solaris 2 */
1573
 
 
1574
1759
#ifndef HEAP_START
1575
1760
#   define HEAP_START 0
1576
1761
#endif
1577
1762
 
1578
 
ptr_t GC_unix_get_mem(bytes)
1579
 
word bytes;
 
1763
ptr_t GC_unix_mmap_get_mem(word bytes)
1580
1764
{
1581
1765
    void *result;
1582
1766
    static ptr_t last_addr = HEAP_START;
1604
1788
        /* don't work, so we discard it and try again.                  */
1605
1789
        munmap(result, (size_t)(-GC_page_size) - (size_t)result);
1606
1790
                        /* Leave last page mapped, so we can't repeat. */
1607
 
        return GC_unix_get_mem(bytes);
 
1791
        return GC_unix_mmap_get_mem(bytes);
1608
1792
      }
1609
1793
#   else
1610
1794
      GC_ASSERT(last_addr != 0);
1612
1796
    return((ptr_t)result);
1613
1797
}
1614
1798
 
1615
 
#else /* Not RS6000, not USE_MMAP */
1616
 
ptr_t GC_unix_get_mem(bytes)
1617
 
word bytes;
 
1799
# endif  /* MMAP_SUPPORTED */
 
1800
 
 
1801
#if defined(USE_MMAP)
 
1802
 
 
1803
ptr_t GC_unix_get_mem(word bytes)
 
1804
{
 
1805
    return GC_unix_mmap_get_mem(bytes);
 
1806
}
 
1807
 
 
1808
#else /* Not USE_MMAP */
 
1809
 
 
1810
ptr_t GC_unix_sbrk_get_mem(word bytes)
1618
1811
{
1619
1812
  ptr_t result;
1620
1813
# ifdef IRIX5
1636
1829
            goto out;
1637
1830
        }
1638
1831
    }
 
1832
#   ifdef ADD_HEAP_GUARD_PAGES
 
1833
      /* This is useful for catching severe memory overwrite problems that */
 
1834
      /* span heap sections.  It shouldn't otherwise be turned on.         */
 
1835
      {
 
1836
        ptr_t guard = (ptr_t)sbrk((SBRK_ARG_T)GC_page_size);
 
1837
        if (mprotect(guard, GC_page_size, PROT_NONE) != 0)
 
1838
            ABORT("ADD_HEAP_GUARD_PAGES: mprotect failed");
 
1839
      }
 
1840
#   endif /* ADD_HEAP_GUARD_PAGES */
1639
1841
    result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
1640
1842
    if (result == (ptr_t)(-1)) result = 0;
1641
1843
  }
1646
1848
  return(result);
1647
1849
}
1648
1850
 
 
1851
#if defined(MMAP_SUPPORTED)
 
1852
 
 
1853
/* By default, we try both sbrk and mmap, in that order. */
 
1854
ptr_t GC_unix_get_mem(word bytes)
 
1855
{
 
1856
    static GC_bool sbrk_failed = FALSE;
 
1857
    ptr_t result = 0;
 
1858
 
 
1859
    if (!sbrk_failed) result = GC_unix_sbrk_get_mem(bytes);
 
1860
    if (0 == result) {
 
1861
        sbrk_failed = TRUE;
 
1862
        result = GC_unix_mmap_get_mem(bytes);
 
1863
    }
 
1864
    if (0 == result) {
 
1865
        /* Try sbrk again, in case sbrk memory became available. */
 
1866
        result = GC_unix_sbrk_get_mem(bytes);
 
1867
    }
 
1868
    return result;
 
1869
}
 
1870
 
 
1871
#else /* !MMAP_SUPPORTED */
 
1872
 
 
1873
ptr_t GC_unix_get_mem(word bytes)
 
1874
{
 
1875
    return GC_unix_sbrk_get_mem(bytes);
 
1876
}
 
1877
 
 
1878
#endif
 
1879
 
1649
1880
#endif /* Not USE_MMAP */
1650
 
#endif /* Not RS6000 */
1651
1881
 
1652
1882
# endif /* UN*X */
1653
1883
 
1683
1913
 
1684
1914
word GC_n_heap_bases = 0;
1685
1915
 
1686
 
ptr_t GC_win32_get_mem(bytes)
1687
 
word bytes;
 
1916
word GC_mem_top_down = 0;  /* Change to MEM_TOP_DOWN  for better 64-bit */
 
1917
                           /* testing.  Otherwise all addresses tend to */
 
1918
                           /* end up in first 4GB, hiding bugs.         */
 
1919
 
 
1920
ptr_t GC_win32_get_mem(word bytes)
1688
1921
{
1689
1922
    ptr_t result;
1690
1923
 
1693
1926
        /* There are also unconfirmed rumors of other           */
1694
1927
        /* problems, so we dodge the issue.                     */
1695
1928
        result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);
1696
 
        result = (ptr_t)(((word)result + HBLKSIZE) & ~(HBLKSIZE-1));
 
1929
        result = (ptr_t)(((word)result + HBLKSIZE - 1) & ~(HBLKSIZE-1));
1697
1930
    } else {
1698
1931
        /* VirtualProtect only works on regions returned by a   */
1699
1932
        /* single VirtualAlloc call.  Thus we allocate one      */
1703
1936
        /* This wastes a small amount of memory, and risks      */
1704
1937
        /* increased fragmentation.  But better alternatives    */
1705
1938
        /* would require effort.                                */
 
1939
        /* Pass the MEM_WRITE_WATCH only if GetWriteWatch-based */
 
1940
        /* VDBs are enabled and the GetWriteWatch function is   */
 
1941
        /* available.  Otherwise we waste resources or possibly */
 
1942
        /* cause VirtualAlloc to fail (observed in Windows 2000 */
 
1943
        /* SP2).                                                */
1706
1944
        result = (ptr_t) VirtualAlloc(NULL, bytes + 1,
1707
 
                                      MEM_COMMIT | MEM_RESERVE,
 
1945
#                                     ifdef GWW_VDB
 
1946
                                        GetWriteWatch_alloc_flag |
 
1947
#                                     endif
 
1948
                                      MEM_COMMIT | MEM_RESERVE
 
1949
                                      | GC_mem_top_down,
1708
1950
                                      PAGE_EXECUTE_READWRITE);
1709
1951
    }
1710
1952
    if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
1711
1953
        /* If I read the documentation correctly, this can      */
1712
1954
        /* only happen if HBLKSIZE > 64k or not a power of 2.   */
1713
1955
    if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
1714
 
    GC_heap_bases[GC_n_heap_bases++] = result;
 
1956
    if (0 != result) GC_heap_bases[GC_n_heap_bases++] = result;
1715
1957
    return(result);                       
1716
1958
}
1717
1959
 
1718
 
void GC_win32_free_heap ()
 
1960
void GC_win32_free_heap(void)
1719
1961
{
1720
1962
    if (GC_no_win32_dlls) {
1721
1963
        while (GC_n_heap_bases > 0) {
1736
1978
# ifdef MSWINCE
1737
1979
word GC_n_heap_bases = 0;
1738
1980
 
1739
 
ptr_t GC_wince_get_mem(bytes)
1740
 
word bytes;
 
1981
ptr_t GC_wince_get_mem(word bytes)
1741
1982
{
1742
1983
    ptr_t result;
1743
1984
    word i;
1759
2000
        /* Reserve more pages */
1760
2001
        word res_bytes = (bytes + GC_sysinfo.dwAllocationGranularity-1)
1761
2002
                         & ~(GC_sysinfo.dwAllocationGranularity-1);
1762
 
        /* If we ever support MPROTECT_VDB here, we will probably need to       */
1763
 
        /* ensure that res_bytes is strictly > bytes, so that VirtualProtect    */
1764
 
        /* never spans regions.  It seems to be OK for a VirtualFree argument   */
1765
 
        /* to span regions, so we should be OK for now.                         */
 
2003
        /* If we ever support MPROTECT_VDB here, we will probably need to    */
 
2004
        /* ensure that res_bytes is strictly > bytes, so that VirtualProtect */
 
2005
        /* never spans regions.  It seems to be OK for a VirtualFree         */
 
2006
        /* argument to span regions, so we should be OK for now.             */
1766
2007
        result = (ptr_t) VirtualAlloc(NULL, res_bytes,
1767
2008
                                      MEM_RESERVE | MEM_TOP_DOWN,
1768
2009
                                      PAGE_EXECUTE_READWRITE);
1807
2048
/* Compute a page aligned starting address for the unmap        */
1808
2049
/* operation on a block of size bytes starting at start.        */
1809
2050
/* Return 0 if the block is too small to make this feasible.    */
1810
 
ptr_t GC_unmap_start(ptr_t start, word bytes)
 
2051
ptr_t GC_unmap_start(ptr_t start, size_t bytes)
1811
2052
{
1812
2053
    ptr_t result = start;
1813
2054
    /* Round start to next page boundary.       */
1819
2060
 
1820
2061
/* Compute end address for an unmap operation on the indicated  */
1821
2062
/* block.                                                       */
1822
 
ptr_t GC_unmap_end(ptr_t start, word bytes)
 
2063
ptr_t GC_unmap_end(ptr_t start, size_t bytes)
1823
2064
{
1824
2065
    ptr_t end_addr = start + bytes;
1825
2066
    end_addr = (ptr_t)((word)end_addr & ~(GC_page_size - 1));
1837
2078
/* We assume that GC_remap is called on exactly the same range  */
1838
2079
/* as a previous call to GC_unmap.  It is safe to consistently  */
1839
2080
/* round the endpoints in both places.                          */
1840
 
void GC_unmap(ptr_t start, word bytes)
 
2081
void GC_unmap(ptr_t start, size_t bytes)
1841
2082
{
1842
2083
    ptr_t start_addr = GC_unmap_start(start, bytes);
1843
2084
    ptr_t end_addr = GC_unmap_end(start, bytes);
1872
2113
}
1873
2114
 
1874
2115
 
1875
 
void GC_remap(ptr_t start, word bytes)
 
2116
void GC_remap(ptr_t start, size_t bytes)
1876
2117
{
1877
2118
    ptr_t start_addr = GC_unmap_start(start, bytes);
1878
2119
    ptr_t end_addr = GC_unmap_end(start, bytes);
1907
2148
      result = mprotect(start_addr, len,
1908
2149
                        PROT_READ | PROT_WRITE | OPT_PROT_EXEC);
1909
2150
      if (result != 0) {
1910
 
          GC_err_printf3(
1911
 
                "Mprotect failed at 0x%lx (length %ld) with errno %ld\n",
1912
 
                start_addr, len, errno);
 
2151
          GC_err_printf(
 
2152
                "Mprotect failed at %p (length %ld) with errno %d\n",
 
2153
                start_addr, (unsigned long)len, errno);
1913
2154
          ABORT("Mprotect remapping failed");
1914
2155
      }
1915
2156
      GC_unmapped_bytes -= len;
1920
2161
/* be merged.  Unmap the whole block.  This typically requires          */
1921
2162
/* that we unmap a small section in the middle that was not previously  */
1922
2163
/* unmapped due to alignment constraints.                               */
1923
 
void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t start2, word bytes2)
 
2164
void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2, size_t bytes2)
1924
2165
{
1925
2166
    ptr_t start1_addr = GC_unmap_start(start1, bytes1);
1926
2167
    ptr_t end1_addr = GC_unmap_end(start1, bytes1);
1928
2169
    ptr_t end2_addr = GC_unmap_end(start2, bytes2);
1929
2170
    ptr_t start_addr = end1_addr;
1930
2171
    ptr_t end_addr = start2_addr;
1931
 
    word len;
 
2172
    size_t len;
1932
2173
    GC_ASSERT(start1 + bytes1 == start2);
1933
2174
    if (0 == start1_addr) start_addr = GC_unmap_start(start1, bytes1 + bytes2);
1934
2175
    if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2);
1960
2201
/* environment, this is also responsible for marking from       */
1961
2202
/* thread stacks.                                               */
1962
2203
#ifndef THREADS
1963
 
void (*GC_push_other_roots)() = 0;
 
2204
void (*GC_push_other_roots)(void) = 0;
1964
2205
#else /* THREADS */
1965
2206
 
1966
2207
# ifdef PCR
1985
2226
}
1986
2227
 
1987
2228
 
1988
 
void GC_default_push_other_roots GC_PROTO((void))
 
2229
void GC_default_push_other_roots(void)
1989
2230
{
1990
2231
    /* Traverse data allocated by previous memory managers.             */
1991
2232
        {
2007
2248
 
2008
2249
# endif /* PCR */
2009
2250
 
2010
 
# ifdef SRC_M3
2011
 
 
2012
 
# ifdef ALL_INTERIOR_POINTERS
2013
 
    --> misconfigured
2014
 
# endif
2015
 
 
2016
 
void GC_push_thread_structures GC_PROTO((void))
2017
 
{
2018
 
    /* Not our responsibibility. */
2019
 
}
2020
 
 
2021
 
extern void ThreadF__ProcessStacks();
2022
 
 
2023
 
void GC_push_thread_stack(start, stop)
2024
 
word start, stop;
2025
 
{
2026
 
   GC_push_all_stack((ptr_t)start, (ptr_t)stop + sizeof(word));
2027
 
}
2028
 
 
2029
 
/* Push routine with M3 specific calling convention. */
2030
 
GC_m3_push_root(dummy1, p, dummy2, dummy3)
2031
 
word *p;
2032
 
ptr_t dummy1, dummy2;
2033
 
int dummy3;
2034
 
{
2035
 
    word q = *p;
2036
 
    
2037
 
    GC_PUSH_ONE_STACK(q, p);
2038
 
}
2039
 
 
2040
 
/* M3 set equivalent to RTHeap.TracedRefTypes */
2041
 
typedef struct { int elts[1]; }  RefTypeSet;
2042
 
RefTypeSet GC_TracedRefTypes = {{0x1}};
2043
 
 
2044
 
void GC_default_push_other_roots GC_PROTO((void))
2045
 
{
2046
 
    /* Use the M3 provided routine for finding static roots.     */
2047
 
    /* This is a bit dubious, since it presumes no C roots.      */
2048
 
    /* We handle the collector roots explicitly in GC_push_roots */
2049
 
        RTMain__GlobalMapProc(GC_m3_push_root, 0, GC_TracedRefTypes);
2050
 
        if (GC_words_allocd > 0) {
2051
 
            ThreadF__ProcessStacks(GC_push_thread_stack);
2052
 
        }
2053
 
        /* Otherwise this isn't absolutely necessary, and we have       */
2054
 
        /* startup ordering problems.                                   */
2055
 
}
2056
 
 
2057
 
# endif /* SRC_M3 */
2058
 
 
2059
 
# if defined(GC_SOLARIS_THREADS) || defined(GC_PTHREADS) || \
2060
 
     defined(GC_WIN32_THREADS)
2061
 
 
2062
 
extern void GC_push_all_stacks();
2063
 
 
2064
 
void GC_default_push_other_roots GC_PROTO((void))
 
2251
 
 
2252
# if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
 
2253
 
 
2254
extern void GC_push_all_stacks(void);
 
2255
 
 
2256
void GC_default_push_other_roots(void)
2065
2257
{
2066
2258
    GC_push_all_stacks();
2067
2259
}
2068
2260
 
2069
 
# endif /* GC_SOLARIS_THREADS || GC_PTHREADS */
 
2261
# endif /* GC_WIN32_THREADS || GC_PTHREADS */
2070
2262
 
2071
 
void (*GC_push_other_roots) GC_PROTO((void)) = GC_default_push_other_roots;
 
2263
void (*GC_push_other_roots)(void) = GC_default_push_other_roots;
2072
2264
 
2073
2265
#endif /* THREADS */
2074
2266
 
2075
2267
/*
2076
2268
 * Routines for accessing dirty  bits on virtual pages.
2077
 
 * We plan to eventually implement four strategies for doing so:
 
2269
 * There are six ways to maintain this information:
2078
2270
 * DEFAULT_VDB: A simple dummy implementation that treats every page
2079
2271
 *              as possibly dirty.  This makes incremental collection
2080
2272
 *              useless, but the implementation is still correct.
 
2273
 * MANUAL_VDB:  Stacks and static data are always considered dirty.
 
2274
 *              Heap pages are considered dirty if GC_dirty(p) has been
 
2275
 *              called on some pointer p pointing to somewhere inside
 
2276
 *              an object on that page.  A GC_dirty() call on a large
 
2277
 *              object directly dirties only a single page, but for
 
2278
 *              MANUAL_VDB we are careful to treat an object with a dirty
 
2279
 *              page as completely dirty.
 
2280
 *              In order to avoid races, an object must be marked dirty
 
2281
 *              after it is written, and a reference to the object
 
2282
 *              must be kept on a stack or in a register in the interim.
 
2283
 *              With threads enabled, an object directly reachable from the
 
2284
 *              stack at the time of a collection is treated as dirty.
 
2285
 *              In single-threaded mode, it suffices to ensure that no
 
2286
 *              collection can take place between the pointer assignment
 
2287
 *              and the GC_dirty() call.
2081
2288
 * PCR_VDB:     Use PPCRs virtual dirty bit facility.
2082
2289
 * PROC_VDB:    Use the /proc facility for reading dirty bits.  Only
2083
2290
 *              works under some SVR4 variants.  Even then, it may be
2091
2298
 *              call from doing so.  It is the clients responsibility to
2092
2299
 *              make sure that other system calls are similarly protected
2093
2300
 *              or write only to the stack.
 
2301
 * GWW_VDB:     Use the Win32 GetWriteWatch functions, if available, to
 
2302
 *              read dirty bits.  In case it is not available (because we
 
2303
 *              are running on Windows 95, Windows 2000 or earlier),
 
2304
 *              MPROTECT_VDB may be defined as a fallback strategy.
2094
2305
 */
2095
2306
GC_bool GC_dirty_maintained = FALSE;
2096
2307
 
 
2308
#if defined(PROC_VDB) || defined(GWW_VDB)
 
2309
 
 
2310
/* Add all pages in pht2 to pht1 */
 
2311
void GC_or_pages(page_hash_table pht1, page_hash_table pht2)
 
2312
{
 
2313
    register int i;
 
2314
    
 
2315
    for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
 
2316
}
 
2317
 
 
2318
#endif
 
2319
 
 
2320
#ifdef GWW_VDB
 
2321
 
 
2322
# define GC_GWW_BUF_LEN 1024
 
2323
  static PVOID gww_buf[GC_GWW_BUF_LEN];
 
2324
 
 
2325
# ifdef MPROTECT_VDB
 
2326
    GC_bool GC_gww_dirty_init(void)
 
2327
    {
 
2328
      detect_GetWriteWatch();
 
2329
      return GC_GWW_AVAILABLE();
 
2330
    }
 
2331
# else
 
2332
    void GC_dirty_init(void)
 
2333
    {
 
2334
      detect_GetWriteWatch();
 
2335
      GC_dirty_maintained = GC_GWW_AVAILABLE();
 
2336
    }
 
2337
# endif
 
2338
 
 
2339
# ifdef MPROTECT_VDB
 
2340
    static void GC_gww_read_dirty(void)
 
2341
# else
 
2342
    void GC_read_dirty(void)
 
2343
# endif
 
2344
  {
 
2345
    word i;
 
2346
 
 
2347
    BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
 
2348
 
 
2349
    for (i = 0; i != GC_n_heap_sects; ++i) {
 
2350
      ULONG_PTR count;
 
2351
 
 
2352
      do {
 
2353
        PVOID * pages, * pages_end;
 
2354
        DWORD page_size;
 
2355
 
 
2356
        pages = gww_buf;
 
2357
        count = GC_GWW_BUF_LEN;
 
2358
        /*
 
2359
        * GetWriteWatch is documented as returning non-zero when it fails,
 
2360
        * but the documentation doesn't explicitly say why it would fail or
 
2361
        * what its behaviour will be if it fails.
 
2362
        * It does appear to fail, at least on recent W2K instances, if
 
2363
        * the underlying memory was not allocated with the appropriate
 
2364
        * flag.  This is common if GC_enable_incremental is called
 
2365
        * shortly after GC initialization.  To avoid modifying the
 
2366
        * interface, we silently work around such a failure, it it only
 
2367
        * affects the initial (small) heap allocation.
 
2368
        * If there are more dirty
 
2369
        * pages than will fit in the buffer, this is not treated as a
 
2370
        * failure; we must check the page count in the loop condition.
 
2371
        * Since each partial call will reset the status of some
 
2372
        * pages, this should eventually terminate even in the overflow
 
2373
        * case.
 
2374
        */
 
2375
        if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
 
2376
                               GC_heap_sects[i].hs_start,
 
2377
                               GC_heap_sects[i].hs_bytes,
 
2378
                               pages,
 
2379
                               &count,
 
2380
                               &page_size) != 0) {
 
2381
          static int warn_count = 0;
 
2382
          unsigned j;
 
2383
          struct hblk * start = (struct hblk *)GC_heap_sects[i].hs_start;
 
2384
          static struct hblk *last_warned = 0;
 
2385
          size_t nblocks = divHBLKSZ(GC_heap_sects[i].hs_bytes);
 
2386
 
 
2387
          if ( i != 0 && last_warned != start && warn_count++ < 5) {
 
2388
            last_warned = start;
 
2389
            WARN(
 
2390
              "GC_gww_read_dirty unexpectedly failed at %ld: "
 
2391
              "Falling back to marking all pages dirty\n", start);
 
2392
          }
 
2393
          for (j = 0; j < nblocks; ++j) {
 
2394
              word hash = PHT_HASH(start + j);
 
2395
              set_pht_entry_from_index(GC_grungy_pages, hash);
 
2396
          }
 
2397
          count = 1;  /* Done with this section. */
 
2398
        } else /* succeeded */{
 
2399
          pages_end = pages + count;
 
2400
          while (pages != pages_end) {
 
2401
            struct hblk * h = (struct hblk *) *pages++;
 
2402
            struct hblk * h_end = (struct hblk *) ((char *) h + page_size);
 
2403
            do
 
2404
              set_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
 
2405
            while (++h < h_end);
 
2406
          }
 
2407
        }
 
2408
      } while (count == GC_GWW_BUF_LEN);
 
2409
    }
 
2410
 
 
2411
    GC_or_pages(GC_written_pages, GC_grungy_pages);
 
2412
  }
 
2413
 
 
2414
# ifdef MPROTECT_VDB
 
2415
    static GC_bool GC_gww_page_was_dirty(struct hblk * h)
 
2416
# else
 
2417
    GC_bool GC_page_was_dirty(struct hblk * h)
 
2418
# endif
 
2419
  {
 
2420
    return HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
 
2421
  }
 
2422
 
 
2423
# ifdef MPROTECT_VDB
 
2424
    static GC_bool GC_gww_page_was_ever_dirty(struct hblk * h)
 
2425
# else
 
2426
    GC_bool GC_page_was_ever_dirty(struct hblk * h)
 
2427
# endif
 
2428
  {
 
2429
    return HDR(h) == 0 || get_pht_entry_from_index(GC_written_pages, PHT_HASH(h));
 
2430
  }
 
2431
 
 
2432
# ifndef MPROTECT_VDB
 
2433
    void GC_remove_protection(struct hblk *h, word nblocks, GC_bool is_ptrfree)
 
2434
    {}
 
2435
# endif
 
2436
 
 
2437
# endif /* GWW_VDB */
 
2438
 
2097
2439
# ifdef DEFAULT_VDB
2098
2440
 
2099
2441
/* All of the following assume the allocation lock is held, and */
2103
2445
/* written.                                                             */
2104
2446
 
2105
2447
/* Initialize virtual dirty bit implementation.                 */
2106
 
void GC_dirty_init()
 
2448
void GC_dirty_init(void)
2107
2449
{
2108
 
#   ifdef PRINTSTATS
2109
 
      GC_printf0("Initializing DEFAULT_VDB...\n");
2110
 
#   endif
 
2450
    if (GC_print_stats == VERBOSE)
 
2451
      GC_log_printf("Initializing DEFAULT_VDB...\n");
2111
2452
    GC_dirty_maintained = TRUE;
2112
2453
}
2113
2454
 
2114
2455
/* Retrieve system dirty bits for heap to a local buffer.       */
2115
2456
/* Restore the systems notion of which pages are dirty.         */
2116
 
void GC_read_dirty()
 
2457
void GC_read_dirty(void)
2117
2458
{}
2118
2459
 
2119
2460
/* Is the HBLKSIZE sized page at h marked dirty in the local buffer?    */
2121
2462
/* of the pages overlapping h are dirty.  This routine may err on the   */
2122
2463
/* side of labelling pages as dirty (and this implementation does).     */
2123
2464
/*ARGSUSED*/
2124
 
GC_bool GC_page_was_dirty(h)
2125
 
struct hblk *h;
 
2465
GC_bool GC_page_was_dirty(struct hblk *h)
2126
2466
{
2127
2467
    return(TRUE);
2128
2468
}
2136
2476
 
2137
2477
/* Could any valid GC heap pointer ever have been written to this page? */
2138
2478
/*ARGSUSED*/
2139
 
GC_bool GC_page_was_ever_dirty(h)
2140
 
struct hblk *h;
 
2479
GC_bool GC_page_was_ever_dirty(struct hblk *h)
2141
2480
{
2142
2481
    return(TRUE);
2143
2482
}
2144
2483
 
2145
 
/* Reset the n pages starting at h to "was never dirty" status. */
2146
 
void GC_is_fresh(h, n)
2147
 
struct hblk *h;
2148
 
word n;
2149
 
{
2150
 
}
2151
 
 
2152
2484
/* A call that:                                         */
2153
2485
/* I) hints that [h, h+nblocks) is about to be written. */
2154
2486
/* II) guarantees that protection is removed.           */
2157
2489
/* pointer-free system call buffers in the heap are     */
2158
2490
/* not protected.                                       */
2159
2491
/*ARGSUSED*/
2160
 
void GC_remove_protection(h, nblocks, is_ptrfree)
2161
 
struct hblk *h;
2162
 
word nblocks;
2163
 
GC_bool is_ptrfree;
 
2492
void GC_remove_protection(struct hblk *h, word nblocks, GC_bool is_ptrfree)
2164
2493
{
2165
2494
}
2166
2495
 
2167
2496
# endif /* DEFAULT_VDB */
2168
2497
 
 
2498
# ifdef MANUAL_VDB
 
2499
 
 
2500
/* Initialize virtual dirty bit implementation.                 */
 
2501
void GC_dirty_init(void)
 
2502
{
 
2503
    if (GC_print_stats == VERBOSE)
 
2504
      GC_log_printf("Initializing MANUAL_VDB...\n");
 
2505
    /* GC_dirty_pages and GC_grungy_pages are already cleared. */
 
2506
    GC_dirty_maintained = TRUE;
 
2507
}
 
2508
 
 
2509
/* Retrieve system dirty bits for heap to a local buffer.       */
 
2510
/* Restore the systems notion of which pages are dirty.         */
 
2511
void GC_read_dirty(void)
 
2512
{
 
2513
    BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
 
2514
          (sizeof GC_dirty_pages));
 
2515
    BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
 
2516
}
 
2517
 
 
2518
/* Is the HBLKSIZE sized page at h marked dirty in the local buffer?    */
 
2519
/* If the actual page size is different, this returns TRUE if any       */
 
2520
/* of the pages overlapping h are dirty.  This routine may err on the   */
 
2521
/* side of labelling pages as dirty (and this implementation does).     */
 
2522
/*ARGSUSED*/
 
2523
GC_bool GC_page_was_dirty(struct hblk *h)
 
2524
{
 
2525
    register word index;
 
2526
    
 
2527
    index = PHT_HASH(h);
 
2528
    return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
 
2529
}
 
2530
 
 
2531
/* Could any valid GC heap pointer ever have been written to this page? */
 
2532
/*ARGSUSED*/
 
2533
GC_bool GC_page_was_ever_dirty(struct hblk *h)
 
2534
{
 
2535
    /* FIXME - implement me.    */
 
2536
    return(TRUE);
 
2537
}
 
2538
 
 
2539
/* Mark the page containing p as dirty.  Logically, this dirties the    */
 
2540
/* entire object.                                                       */
 
2541
void GC_dirty(ptr_t p)
 
2542
{
 
2543
    word index = PHT_HASH(p);
 
2544
    async_set_pht_entry_from_index(GC_dirty_pages, index);
 
2545
}
 
2546
 
 
2547
/*ARGSUSED*/
 
2548
void GC_remove_protection(struct hblk *h, word nblocks, GC_bool is_ptrfree)
 
2549
{
 
2550
}
 
2551
 
 
2552
# endif /* MANUAL_VDB */
 
2553
 
2169
2554
 
2170
2555
# ifdef MPROTECT_VDB
2171
2556
 
2183
2568
 * heap, and do even that only if we are on a platform on which those
2184
2569
 * are not protected.  Another alternative is to wrap system calls
2185
2570
 * (see example for read below), but the current implementation holds
2186
 
 * a lock across blocking calls, making it problematic for multithreaded
2187
2571
 * applications. 
2188
2572
 * We assume the page size is a multiple of HBLKSIZE.
2189
2573
 * We prefer them to be the same.  We avoid protecting POINTERFREE
2235
2619
          if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READ, \
2236
2620
                              &protect_junk)) { \
2237
2621
            DWORD last_error = GetLastError(); \
2238
 
            GC_printf1("Last error code: %lx\n", last_error); \
 
2622
            GC_printf("Last error code: %lx\n", last_error); \
2239
2623
            ABORT("VirtualProtect failed"); \
2240
2624
          }
2241
2625
#   define UNPROTECT(addr, len) \
2246
2630
# endif /* !DARWIN */
2247
2631
# endif /* MSWIN32 || MSWINCE || DARWIN */
2248
2632
 
2249
 
#if defined(SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS))
2250
 
    typedef void (* SIG_PF)();
2251
 
#endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */
2252
 
 
2253
 
#if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
2254
 
    || defined(HURD)
2255
 
# ifdef __STDC__
2256
 
    typedef void (* SIG_PF)(int);
2257
 
# else
2258
 
    typedef void (* SIG_PF)();
2259
 
# endif
2260
 
#endif /* SUNOS5SIGS || OSF1 || LINUX || HURD */
2261
 
 
2262
2633
#if defined(MSWIN32)
2263
 
    typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
 
2634
    typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_HNDLR_PTR;
2264
2635
#   undef SIG_DFL
2265
2636
#   define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER) (-1)
2266
 
#endif
2267
 
#if defined(MSWINCE)
2268
 
    typedef LONG (WINAPI *SIG_PF)(struct _EXCEPTION_POINTERS *);
 
2637
#elif defined(MSWINCE)
 
2638
    typedef LONG (WINAPI *SIG_HNDLR_PTR)(struct _EXCEPTION_POINTERS *);
2269
2639
#   undef SIG_DFL
2270
 
#   define SIG_DFL (SIG_PF) (-1)
 
2640
#   define SIG_DFL (SIG_HNDLR_PTR) (-1)
 
2641
#elif defined(DARWIN)
 
2642
    typedef void (* SIG_HNDLR_PTR)();
 
2643
#else
 
2644
    typedef void (* SIG_HNDLR_PTR)(int, siginfo_t *, void *);
 
2645
    typedef void (* PLAIN_HNDLR_PTR)(int);
2271
2646
#endif
2272
2647
 
2273
 
#if defined(IRIX5) || defined(OSF1) || defined(HURD)
2274
 
    typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
2275
 
#endif /* IRIX5 || OSF1 || HURD */
2276
 
 
2277
 
#if defined(SUNOS5SIGS)
2278
 
# if defined(HPUX) || defined(FREEBSD)
2279
 
#   define SIGINFO_T siginfo_t
2280
 
# else
2281
 
#   define SIGINFO_T struct siginfo
2282
 
# endif
2283
 
# ifdef __STDC__
2284
 
    typedef void (* REAL_SIG_PF)(int, SIGINFO_T *, void *);
2285
 
# else
2286
 
    typedef void (* REAL_SIG_PF)();
2287
 
# endif
2288
 
#endif /* SUNOS5SIGS */
2289
 
 
2290
 
#if defined(LINUX)
2291
 
#   if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
2292
 
      typedef struct sigcontext s_c;
2293
 
#   else  /* glibc < 2.2 */
2294
 
#     include <linux/version.h>
2295
 
#     if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA) || defined(ARM32)
2296
 
        typedef struct sigcontext s_c;
2297
 
#     else
2298
 
        typedef struct sigcontext_struct s_c;
2299
 
#     endif
2300
 
#   endif  /* glibc < 2.2 */
2301
 
#   if defined(ALPHA) || defined(M68K)
2302
 
      typedef void (* REAL_SIG_PF)(int, int, s_c *);
2303
 
#   else
2304
 
#     if defined(IA64) || defined(HP_PA) || defined(X86_64)
2305
 
        typedef void (* REAL_SIG_PF)(int, siginfo_t *, s_c *);
2306
 
        /* FIXME:                                                 */
2307
 
        /* According to SUSV3, the last argument should have type */
2308
 
        /* void * or ucontext_t *                                 */
2309
 
#     else
2310
 
        typedef void (* REAL_SIG_PF)(int, s_c);
2311
 
#     endif
 
2648
#if defined(__GLIBC__)
 
2649
#   if __GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 2
 
2650
#       error glibc too old?
2312
2651
#   endif
2313
 
#   ifdef ALPHA
2314
 
    /* Retrieve fault address from sigcontext structure by decoding     */
2315
 
    /* instruction.                                                     */
2316
 
    char * get_fault_addr(s_c *sc) {
2317
 
        unsigned instr;
2318
 
        word faultaddr;
2319
 
 
2320
 
        instr = *((unsigned *)(sc->sc_pc));
2321
 
        faultaddr = sc->sc_regs[(instr >> 16) & 0x1f];
2322
 
        faultaddr += (word) (((int)instr << 16) >> 16);
2323
 
        return (char *)faultaddr;
2324
 
    }
2325
 
#   endif /* !ALPHA */
2326
 
# endif /* LINUX */
 
2652
#endif
2327
2653
 
2328
2654
#ifndef DARWIN
2329
 
SIG_PF GC_old_bus_handler;
2330
 
SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */
 
2655
SIG_HNDLR_PTR GC_old_bus_handler;
 
2656
GC_bool GC_old_bus_handler_used_si;
 
2657
SIG_HNDLR_PTR GC_old_segv_handler;
 
2658
                        /* Also old MSWIN32 ACCESS_VIOLATION filter */
 
2659
GC_bool GC_old_segv_handler_used_si;
2331
2660
#endif /* !DARWIN */
2332
2661
 
2333
2662
#if defined(THREADS)
2338
2667
/* safe fallback algorithm of setting all bits in the word.             */
2339
2668
/* Contention should be very rare, so we do the minimum to handle it    */
2340
2669
/* correctly.                                                           */
2341
 
#ifdef GC_TEST_AND_SET_DEFINED
2342
 
  static VOLATILE unsigned int fault_handler_lock = 0;
2343
 
  void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
2344
 
    while (GC_test_and_set(&fault_handler_lock)) {}
 
2670
#ifdef AO_HAVE_test_and_set_acquire
 
2671
  static volatile AO_TS_t fault_handler_lock = 0;
 
2672
  void async_set_pht_entry_from_index(volatile page_hash_table db, size_t index) {
 
2673
    while (AO_test_and_set_acquire(&fault_handler_lock) == AO_TS_SET) {}
2345
2674
    /* Could also revert to set_pht_entry_from_index_safe if initial    */
2346
2675
    /* GC_test_and_set fails.                                           */
2347
2676
    set_pht_entry_from_index(db, index);
2348
 
    GC_clear(&fault_handler_lock);
 
2677
    AO_CLEAR(&fault_handler_lock);
2349
2678
  }
2350
 
#else /* !GC_TEST_AND_SET_DEFINED */
2351
 
  /* THIS IS INCORRECT! The dirty bit vector may be temporarily wrong,  */
 
2679
#else /* !AO_have_test_and_set_acquire */
 
2680
# error No test_and_set operation: Introduces a race.
 
2681
  /* THIS WOULD BE INCORRECT!                                           */
 
2682
  /* The dirty bit vector may be temporarily wrong,                     */
2352
2683
  /* just before we notice the conflict and correct it. We may end up   */
2353
2684
  /* looking at it while it's wrong.  But this requires contention      */
2354
2685
  /* exactly when a GC is triggered, which seems far less likely to     */
2355
2686
  /* fail than the old code, which had no reported failures.  Thus we   */
2356
2687
  /* leave it this way while we think of something better, or support   */
2357
2688
  /* GC_test_and_set on the remaining platforms.                        */
2358
 
  static VOLATILE word currently_updating = 0;
2359
 
  void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
 
2689
  static volatile word currently_updating = 0;
 
2690
  void async_set_pht_entry_from_index(volatile page_hash_table db, size_t index) {
2360
2691
    unsigned int update_dummy;
2361
2692
    currently_updating = (word)(&update_dummy);
2362
2693
    set_pht_entry_from_index(db, index);
2372
2703
        /* returning us to a safe state, though not soon enough.        */
2373
2704
    }
2374
2705
  }
2375
 
#endif /* !GC_TEST_AND_SET_DEFINED */
 
2706
#endif /* !AO_HAVE_test_and_set_acquire */
2376
2707
#else /* !THREADS */
2377
2708
# define async_set_pht_entry_from_index(db, index) \
2378
2709
        set_pht_entry_from_index(db, index)
2379
2710
#endif /* !THREADS */
2380
2711
 
2381
 
/*ARGSUSED*/
2382
2712
#if !defined(DARWIN)
2383
 
# if defined (SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS))
2384
 
    void GC_write_fault_handler(sig, code, scp, addr)
2385
 
    int sig, code;
2386
 
    struct sigcontext *scp;
2387
 
    char * addr;
2388
 
#   ifdef SUNOS4
2389
 
#     define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
2390
 
#     define CODE_OK (FC_CODE(code) == FC_PROT \
2391
 
                    || (FC_CODE(code) == FC_OBJERR \
2392
 
                       && FC_ERRNO(code) == FC_PROT))
2393
 
#   endif
2394
 
#   ifdef FREEBSD
2395
 
#     define SIG_OK (sig == SIGBUS)
2396
 
#     define CODE_OK TRUE
2397
 
#   endif
2398
 
# endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */
2399
 
 
2400
 
# if defined(IRIX5) || defined(OSF1) || defined(HURD)
2401
2713
#   include <errno.h>
2402
 
    void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
2403
 
#   ifdef OSF1
 
2714
#   if defined(FREEBSD)
 
2715
#     define SIG_OK TRUE
 
2716
#     define CODE_OK (code == BUS_PAGE_FAULT)
 
2717
#   elif defined(OSF1)
2404
2718
#     define SIG_OK (sig == SIGSEGV)
2405
2719
#     define CODE_OK (code == 2 /* experimentally determined */)
2406
 
#   endif
2407
 
#   ifdef IRIX5
 
2720
#   elif defined(IRIX5)
2408
2721
#     define SIG_OK (sig == SIGSEGV)
2409
2722
#     define CODE_OK (code == EACCES)
2410
 
#   endif
2411
 
#   ifdef HURD
 
2723
#   elif defined(HURD)
2412
2724
#     define SIG_OK (sig == SIGBUS || sig == SIGSEGV)   
2413
2725
#     define CODE_OK  TRUE
2414
 
#   endif
2415
 
# endif /* IRIX5 || OSF1 || HURD */
2416
 
 
2417
 
# if defined(LINUX)
2418
 
#   if defined(ALPHA) || defined(M68K)
2419
 
      void GC_write_fault_handler(int sig, int code, s_c * sc)
2420
 
#   else
2421
 
#     if defined(IA64) || defined(HP_PA) || defined(X86_64)
2422
 
        void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp)
2423
 
#     else
2424
 
#       if defined(ARM32)
2425
 
          void GC_write_fault_handler(int sig, int a2, int a3, int a4, s_c sc)
2426
 
#       else
2427
 
          void GC_write_fault_handler(int sig, s_c sc)
2428
 
#       endif
2429
 
#     endif
2430
 
#   endif
2431
 
#   define SIG_OK (sig == SIGSEGV)
2432
 
#   define CODE_OK TRUE
 
2726
#   elif defined(LINUX)
 
2727
#     define SIG_OK (sig == SIGSEGV)
 
2728
#     define CODE_OK TRUE
2433
2729
        /* Empirically c.trapno == 14, on IA32, but is that useful?     */
2434
2730
        /* Should probably consider alignment issues on other           */
2435
2731
        /* architectures.                                               */
2436
 
# endif /* LINUX */
2437
 
 
2438
 
# if defined(SUNOS5SIGS)
2439
 
#  ifdef __STDC__
2440
 
    void GC_write_fault_handler(int sig, SIGINFO_T *scp, void * context)
2441
 
#  else
2442
 
    void GC_write_fault_handler(sig, scp, context)
2443
 
    int sig;
2444
 
    SIGINFO_T *scp;
2445
 
    void * context;
2446
 
#  endif
2447
 
#   ifdef HPUX
 
2732
#   elif defined(HPUX)
2448
2733
#     define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
2449
 
#     define CODE_OK (scp -> si_code == SEGV_ACCERR) \
2450
 
                     || (scp -> si_code == BUS_ADRERR) \
2451
 
                     || (scp -> si_code == BUS_UNKNOWN) \
2452
 
                     || (scp -> si_code == SEGV_UNKNOWN) \
2453
 
                     || (scp -> si_code == BUS_OBJERR)
2454
 
#   else
2455
 
#     ifdef FREEBSD
2456
 
#       define SIG_OK (sig == SIGBUS)
2457
 
#       define CODE_OK (scp -> si_code == BUS_PAGE_FAULT)
2458
 
#     else
2459
 
#       define SIG_OK (sig == SIGSEGV)
2460
 
#       define CODE_OK (scp -> si_code == SEGV_ACCERR)
2461
 
#     endif
 
2734
#     define CODE_OK (si -> si_code == SEGV_ACCERR) \
 
2735
                     || (si -> si_code == BUS_ADRERR) \
 
2736
                     || (si -> si_code == BUS_UNKNOWN) \
 
2737
                     || (si -> si_code == SEGV_UNKNOWN) \
 
2738
                     || (si -> si_code == BUS_OBJERR)
 
2739
#   elif defined(FREEBSD)
 
2740
#     define SIG_OK (sig == SIGBUS)
 
2741
#     define CODE_OK (si -> si_code == BUS_PAGE_FAULT)
 
2742
#   elif defined(SUNOS5SIGS)
 
2743
#     define SIG_OK (sig == SIGSEGV)
 
2744
#     define CODE_OK (si -> si_code == SEGV_ACCERR)
 
2745
#   elif defined(MSWIN32) || defined(MSWINCE)
 
2746
#     define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode \
 
2747
                     == STATUS_ACCESS_VIOLATION)
 
2748
#     define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] \
 
2749
                      == 1) /* Write fault */
2462
2750
#   endif    
2463
 
# endif /* SUNOS5SIGS */
2464
2751
 
2465
2752
# if defined(MSWIN32) || defined(MSWINCE)
2466
2753
    LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
2467
 
#   define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \
2468
 
                        STATUS_ACCESS_VIOLATION)
2469
 
#   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
2470
 
                        /* Write fault */
 
2754
# else
 
2755
#   include <ucontext.h>
 
2756
    /*ARGSUSED*/
 
2757
    void GC_write_fault_handler(int sig, siginfo_t *si, void *raw_sc)
2471
2758
# endif /* MSWIN32 || MSWINCE */
2472
2759
{
2473
 
    register unsigned i;
2474
 
#   if defined(HURD) 
2475
 
        char *addr = (char *) code;
2476
 
#   endif
2477
 
#   ifdef IRIX5
2478
 
        char * addr = (char *) (size_t) (scp -> sc_badvaddr);
2479
 
#   endif
2480
 
#   if defined(OSF1) && defined(ALPHA)
2481
 
        char * addr = (char *) (scp -> sc_traparg_a0);
2482
 
#   endif
2483
 
#   ifdef SUNOS5SIGS
2484
 
        char * addr = (char *) (scp -> si_addr);
2485
 
#   endif
2486
 
#   ifdef LINUX
2487
 
#     if defined(I386)
2488
 
        char * addr = (char *) (sc.cr2);
2489
 
#     else
2490
 
#       if defined(M68K)
2491
 
          char * addr = NULL;
2492
 
 
2493
 
          struct sigcontext *scp = (struct sigcontext *)(sc);
2494
 
 
2495
 
          int format = (scp->sc_formatvec >> 12) & 0xf;
2496
 
          unsigned long *framedata = (unsigned long *)(scp + 1); 
2497
 
          unsigned long ea;
2498
 
 
2499
 
          if (format == 0xa || format == 0xb) {
2500
 
                /* 68020/030 */
2501
 
                ea = framedata[2];
2502
 
          } else if (format == 7) {
2503
 
                /* 68040 */
2504
 
                ea = framedata[3];
2505
 
                if (framedata[1] & 0x08000000) {
2506
 
                        /* correct addr on misaligned access */
2507
 
                        ea = (ea+4095)&(~4095);
2508
 
                }
2509
 
          } else if (format == 4) {
2510
 
                /* 68060 */
2511
 
                ea = framedata[0];
2512
 
                if (framedata[1] & 0x08000000) {
2513
 
                        /* correct addr on misaligned access */
2514
 
                        ea = (ea+4095)&(~4095);
2515
 
                }
2516
 
          }     
2517
 
          addr = (char *)ea;
2518
 
#       else
2519
 
#         ifdef ALPHA
2520
 
            char * addr = get_fault_addr(sc);
2521
 
#         else
2522
 
#           if defined(IA64) || defined(HP_PA) || defined(X86_64)
2523
 
              char * addr = si -> si_addr;
2524
 
              /* I believe this is claimed to work on all platforms for */
2525
 
              /* Linux 2.3.47 and later.  Hopefully we don't have to    */
2526
 
              /* worry about earlier kernels on IA64.                   */
2527
 
#           else
2528
 
#             if defined(POWERPC)
2529
 
                char * addr = (char *) (sc.regs->dar);
2530
 
#             else
2531
 
#               if defined(ARM32)
2532
 
                  char * addr = (char *)sc.fault_address;
2533
 
#               else
2534
 
#                 if defined(CRIS)
2535
 
                    char * addr = (char *)sc.regs.csraddr;
2536
 
#                 else
2537
 
                    --> architecture not supported
2538
 
#                 endif
2539
 
#               endif
2540
 
#             endif
2541
 
#           endif
2542
 
#         endif
2543
 
#       endif
2544
 
#     endif
 
2760
#   if !defined(MSWIN32) && !defined(MSWINCE)
 
2761
      int code = si -> si_code;  /* Ignore gcc unused var. warning. */
 
2762
      ucontext_t * scp = (ucontext_t *)raw_sc;
 
2763
                                /* Ignore gcc unused var. warning. */
 
2764
      char *addr = si -> si_addr;
2545
2765
#   endif
2546
2766
#   if defined(MSWIN32) || defined(MSWINCE)
2547
2767
        char * addr = (char *) (exc_info -> ExceptionRecord
2548
2768
                                -> ExceptionInformation[1]);
2549
2769
#       define sig SIGSEGV
2550
2770
#   endif
 
2771
    unsigned i;
2551
2772
    
2552
2773
    if (SIG_OK && CODE_OK) {
2553
2774
        register struct hblk * h =
2571
2792
            /* sequence, which often depends on SA_SIGINFO.     */
2572
2793
 
2573
2794
            /* Heap blocks now begin and end on page boundaries */
2574
 
            SIG_PF old_handler;
 
2795
            SIG_HNDLR_PTR old_handler;
 
2796
            GC_bool used_si;
2575
2797
            
2576
2798
            if (sig == SIGSEGV) {
2577
2799
                old_handler = GC_old_segv_handler;
 
2800
                used_si = GC_old_segv_handler_used_si;
2578
2801
            } else {
2579
2802
                old_handler = GC_old_bus_handler;
 
2803
                used_si = GC_old_bus_handler_used_si;
2580
2804
            }
2581
 
            if (old_handler == SIG_DFL) {
 
2805
            if (old_handler == (SIG_HNDLR_PTR)SIG_DFL) {
2582
2806
#               if !defined(MSWIN32) && !defined(MSWINCE)
2583
 
                    GC_err_printf1("Segfault at 0x%lx\n", addr);
 
2807
                    GC_err_printf("Segfault at %p\n", addr);
2584
2808
                    ABORT("Unexpected bus error or segmentation fault");
2585
2809
#               else
2586
2810
                    return(EXCEPTION_CONTINUE_SEARCH);
2587
2811
#               endif
2588
2812
            } else {
2589
 
#               if defined (SUNOS4) \
2590
 
                    || (defined(FREEBSD) && !defined(SUNOS5SIGS))
2591
 
                    (*old_handler) (sig, code, scp, addr);
2592
 
                    return;
2593
 
#               endif
2594
 
#               if defined (SUNOS5SIGS)
2595
 
                    /*
2596
 
                     * FIXME: For FreeBSD, this code should check if the 
2597
 
                     * old signal handler used the traditional BSD style and
2598
 
                     * if so call it using that style.
2599
 
                     */
2600
 
                    (*(REAL_SIG_PF)old_handler) (sig, scp, context);
2601
 
                    return;
2602
 
#               endif
2603
 
#               if defined (LINUX)
2604
 
#                   if defined(ALPHA) || defined(M68K)
2605
 
                        (*(REAL_SIG_PF)old_handler) (sig, code, sc);
2606
 
#                   else 
2607
 
#                     if defined(IA64) || defined(HP_PA) || defined(X86_64)
2608
 
                        (*(REAL_SIG_PF)old_handler) (sig, si, scp);
2609
 
#                     else
2610
 
                        (*(REAL_SIG_PF)old_handler) (sig, sc);
2611
 
#                     endif
2612
 
#                   endif
2613
 
                    return;
2614
 
#               endif
2615
 
#               if defined (IRIX5) || defined(OSF1) || defined(HURD)
2616
 
                    (*(REAL_SIG_PF)old_handler) (sig, code, scp);
2617
 
                    return;
2618
 
#               endif
 
2813
                /*
 
2814
                 * FIXME: This code should probably check if the 
 
2815
                 * old signal handler used the traditional style and
 
2816
                 * if so call it using that style.
 
2817
                 */
2619
2818
#               ifdef MSWIN32
2620
2819
                    return((*old_handler)(exc_info));
 
2820
#               else
 
2821
                    if (used_si)
 
2822
                      ((SIG_HNDLR_PTR)old_handler) (sig, si, raw_sc);
 
2823
                    else
 
2824
                      /* FIXME: should pass nonstandard args as well. */
 
2825
                      ((PLAIN_HNDLR_PTR)old_handler) (sig);
 
2826
                    return;
2621
2827
#               endif
2622
2828
            }
2623
2829
        }
2634
2840
        /* and then to have the thread stopping code set the dirty      */
2635
2841
        /* flag, if necessary.                                          */
2636
2842
        for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
2637
 
            register int index = PHT_HASH(h+i);
 
2843
            size_t index = PHT_HASH(h+i);
2638
2844
            
2639
2845
            async_set_pht_entry_from_index(GC_dirty_pages, index);
2640
2846
        }
2641
 
#       if defined(OSF1)
2642
 
            /* These reset the signal handler each time by default. */
2643
 
            signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);
2644
 
#       endif
2645
2847
        /* The write may not take place before dirty bits are read.     */
2646
2848
        /* But then we'll fault again ...                               */
2647
2849
#       if defined(MSWIN32) || defined(MSWINCE)
2653
2855
#if defined(MSWIN32) || defined(MSWINCE)
2654
2856
    return EXCEPTION_CONTINUE_SEARCH;
2655
2857
#else
2656
 
    GC_err_printf1("Segfault at 0x%lx\n", addr);
 
2858
    GC_err_printf("Segfault at %p\n", addr);
2657
2859
    ABORT("Unexpected bus error or segmentation fault");
2658
2860
#endif
2659
2861
}
2665
2867
 * starting at h are no longer protected.  If is_ptrfree is false,
2666
2868
 * also ensure that they will subsequently appear to be dirty.
2667
2869
 */
2668
 
void GC_remove_protection(h, nblocks, is_ptrfree)
2669
 
struct hblk *h;
2670
 
word nblocks;
2671
 
GC_bool is_ptrfree;
 
2870
void GC_remove_protection(struct hblk *h, word nblocks, GC_bool is_ptrfree)
2672
2871
{
2673
2872
    struct hblk * h_trunc;  /* Truncated to page boundary */
2674
2873
    struct hblk * h_end;    /* Page boundary following block end */
2675
2874
    struct hblk * current;
2676
2875
    GC_bool found_clean;
2677
2876
    
 
2877
#   if defined(GWW_VDB)
 
2878
      if (GC_GWW_AVAILABLE()) return;
 
2879
#   endif
2678
2880
    if (!GC_dirty_maintained) return;
2679
2881
    h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));
2680
2882
    h_end = (struct hblk *)(((word)(h + nblocks) + GC_page_size-1)
2681
2883
                            & ~(GC_page_size-1));
2682
2884
    found_clean = FALSE;
2683
2885
    for (current = h_trunc; current < h_end; ++current) {
2684
 
        int index = PHT_HASH(current);
 
2886
        size_t index = PHT_HASH(current);
2685
2887
            
2686
2888
        if (!is_ptrfree || current < h || current >= h + nblocks) {
2687
2889
            async_set_pht_entry_from_index(GC_dirty_pages, index);
2691
2893
}
2692
2894
 
2693
2895
#if !defined(DARWIN)
2694
 
void GC_dirty_init()
 
2896
void GC_dirty_init(void)
2695
2897
{
2696
 
#   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
2697
 
       defined(OSF1) || defined(HURD)
 
2898
#   if !defined(MSWIN32) && !defined(MSWINCE)
2698
2899
      struct sigaction  act, oldact;
2699
 
      /* We should probably specify SA_SIGINFO for Linux, and handle    */
2700
 
      /* the different architectures more uniformly.                    */
2701
 
#     if defined(IRIX5) || defined(LINUX) && !defined(X86_64) \
2702
 
         || defined(OSF1) || defined(HURD)
2703
 
        act.sa_flags    = SA_RESTART;
2704
 
        act.sa_handler  = (SIG_PF)GC_write_fault_handler;
2705
 
#     else
2706
 
        act.sa_flags    = SA_RESTART | SA_SIGINFO;
2707
 
        act.sa_sigaction = GC_write_fault_handler;
2708
 
#     endif
 
2900
      act.sa_flags      = SA_RESTART | SA_SIGINFO;
 
2901
      act.sa_sigaction = GC_write_fault_handler;
2709
2902
      (void)sigemptyset(&act.sa_mask);
2710
2903
#     ifdef SIG_SUSPEND
2711
2904
        /* Arrange to postpone SIG_SUSPEND while we're in a write fault */
2713
2906
        /* stopping the world for GC.                                   */
2714
2907
        (void)sigaddset(&act.sa_mask, SIG_SUSPEND);
2715
2908
#     endif /* SIG_SUSPEND */
2716
 
#    endif
2717
 
#   ifdef PRINTSTATS
2718
 
        GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
2719
2909
#   endif
 
2910
    if (GC_print_stats == VERBOSE)
 
2911
        GC_log_printf(
 
2912
                "Initializing mprotect virtual dirty bit implementation\n");
2720
2913
    GC_dirty_maintained = TRUE;
2721
2914
    if (GC_page_size % HBLKSIZE != 0) {
2722
 
        GC_err_printf0("Page size not multiple of HBLKSIZE\n");
 
2915
        GC_err_printf("Page size not multiple of HBLKSIZE\n");
2723
2916
        ABORT("Page size not multiple of HBLKSIZE");
2724
2917
    }
2725
 
#   if defined(SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS))
2726
 
      GC_old_bus_handler = signal(SIGBUS, GC_write_fault_handler);
2727
 
      if (GC_old_bus_handler == SIG_IGN) {
2728
 
        GC_err_printf0("Previously ignored bus error!?");
2729
 
        GC_old_bus_handler = SIG_DFL;
2730
 
      }
2731
 
      if (GC_old_bus_handler != SIG_DFL) {
2732
 
#       ifdef PRINTSTATS
2733
 
          GC_err_printf0("Replaced other SIGBUS handler\n");
2734
 
#       endif
2735
 
      }
2736
 
#   endif
2737
 
#   if defined(SUNOS4)
2738
 
      GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler);
2739
 
      if (GC_old_segv_handler == SIG_IGN) {
2740
 
        GC_err_printf0("Previously ignored segmentation violation!?");
2741
 
        GC_old_segv_handler = SIG_DFL;
2742
 
      }
2743
 
      if (GC_old_segv_handler != SIG_DFL) {
2744
 
#       ifdef PRINTSTATS
2745
 
          GC_err_printf0("Replaced other SIGSEGV handler\n");
2746
 
#       endif
2747
 
      }
2748
 
#   endif
2749
 
#   if (defined(SUNOS5SIGS) && !defined(FREEBSD)) || defined(IRIX5) \
2750
 
       || defined(LINUX) || defined(OSF1) || defined(HURD)
2751
 
      /* SUNOS5SIGS includes HPUX */
 
2918
#   if !defined(MSWIN32) && !defined(MSWINCE)
2752
2919
#     if defined(GC_IRIX_THREADS)
2753
2920
        sigaction(SIGSEGV, 0, &oldact);
2754
2921
        sigaction(SIGSEGV, &act, 0);
2758
2925
          if (res != 0) ABORT("Sigaction failed");
2759
2926
        }
2760
2927
#     endif
2761
 
#     if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
2762
 
        /* This is Irix 5.x, not 6.x.  Irix 5.x does not have   */
2763
 
        /* sa_sigaction.                                        */
2764
 
        GC_old_segv_handler = oldact.sa_handler;
2765
 
#     else /* Irix 6.x or SUNOS5SIGS or LINUX */
2766
 
        if (oldact.sa_flags & SA_SIGINFO) {
2767
 
          GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction);
2768
 
        } else {
2769
 
          GC_old_segv_handler = oldact.sa_handler;
2770
 
        }
2771
 
#     endif
2772
 
      if (GC_old_segv_handler == SIG_IGN) {
2773
 
             GC_err_printf0("Previously ignored segmentation violation!?");
2774
 
             GC_old_segv_handler = SIG_DFL;
2775
 
      }
2776
 
      if (GC_old_segv_handler != SIG_DFL) {
2777
 
#       ifdef PRINTSTATS
2778
 
          GC_err_printf0("Replaced other SIGSEGV handler\n");
2779
 
#       endif
2780
 
      }
2781
 
#   endif /* (SUNOS5SIGS && !FREEBSD) || IRIX5 || LINUX || OSF1 || HURD */
 
2928
      if (oldact.sa_flags & SA_SIGINFO) {
 
2929
        GC_old_segv_handler = oldact.sa_sigaction;
 
2930
        GC_old_segv_handler_used_si = TRUE;
 
2931
      } else {
 
2932
        GC_old_segv_handler = (SIG_HNDLR_PTR)oldact.sa_handler;
 
2933
        GC_old_segv_handler_used_si = FALSE;
 
2934
      }
 
2935
      if (GC_old_segv_handler == (SIG_HNDLR_PTR)SIG_IGN) {
 
2936
        GC_err_printf("Previously ignored segmentation violation!?");
 
2937
        GC_old_segv_handler = (SIG_HNDLR_PTR)SIG_DFL;
 
2938
      }
 
2939
      if (GC_old_segv_handler != (SIG_HNDLR_PTR)SIG_DFL) {
 
2940
        if (GC_print_stats == VERBOSE)
 
2941
          GC_log_printf("Replaced other SIGSEGV handler\n");
 
2942
      }
 
2943
#   endif /* ! MS windows */
2782
2944
#   if defined(HPUX) || defined(LINUX) || defined(HURD) \
2783
2945
      || (defined(FREEBSD) && defined(SUNOS5SIGS))
2784
2946
      sigaction(SIGBUS, &act, &oldact);
2785
 
      GC_old_bus_handler = oldact.sa_handler;
2786
 
      if (GC_old_bus_handler == SIG_IGN) {
2787
 
             GC_err_printf0("Previously ignored bus error!?");
2788
 
             GC_old_bus_handler = SIG_DFL;
2789
 
      }
2790
 
      if (GC_old_bus_handler != SIG_DFL) {
2791
 
#       ifdef PRINTSTATS
2792
 
          GC_err_printf0("Replaced other SIGBUS handler\n");
2793
 
#       endif
 
2947
      if (oldact.sa_flags & SA_SIGINFO) {
 
2948
        GC_old_bus_handler = oldact.sa_sigaction;
 
2949
        GC_old_bus_handler_used_si = TRUE;
 
2950
      } else {
 
2951
        GC_old_bus_handler = (SIG_HNDLR_PTR)oldact.sa_handler;
 
2952
        GC_old_bus_handler_used_si = FALSE;
 
2953
      }
 
2954
      if (GC_old_bus_handler == (SIG_HNDLR_PTR)SIG_IGN) {
 
2955
             GC_err_printf("Previously ignored bus error!?");
 
2956
             GC_old_bus_handler = (SIG_HNDLR_PTR)SIG_DFL;
 
2957
      }
 
2958
      if (GC_old_bus_handler != (SIG_HNDLR_PTR)SIG_DFL) {
 
2959
        if (GC_print_stats == VERBOSE)
 
2960
          GC_log_printf("Replaced other SIGBUS handler\n");
2794
2961
      }
2795
2962
#   endif /* HPUX || LINUX || HURD || (FREEBSD && SUNOS5SIGS) */
2796
2963
#   if defined(MSWIN32)
 
2964
#     if defined(GWW_VDB)
 
2965
        if (GC_gww_dirty_init())
 
2966
          return;
 
2967
#     endif
2797
2968
      GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
2798
2969
      if (GC_old_segv_handler != NULL) {
2799
 
#       ifdef PRINTSTATS
2800
 
          GC_err_printf0("Replaced other UnhandledExceptionFilter\n");
2801
 
#       endif
 
2970
        if (GC_print_stats)
 
2971
          GC_log_printf("Replaced other UnhandledExceptionFilter\n");
2802
2972
      } else {
2803
2973
          GC_old_segv_handler = SIG_DFL;
2804
2974
      }
2806
2976
}
2807
2977
#endif /* !DARWIN */
2808
2978
 
2809
 
int GC_incremental_protection_needs()
 
2979
int GC_incremental_protection_needs(void)
2810
2980
{
2811
2981
    if (GC_page_size == HBLKSIZE) {
2812
2982
        return GC_PROTECTS_POINTER_HEAP;
2820
2990
#define IS_PTRFREE(hhdr) ((hhdr)->hb_descr == 0)
2821
2991
 
2822
2992
#define PAGE_ALIGNED(x) !((word)(x) & (GC_page_size - 1))
2823
 
void GC_protect_heap()
 
2993
void GC_protect_heap(void)
2824
2994
{
2825
2995
    ptr_t start;
2826
 
    word len;
 
2996
    size_t len;
2827
2997
    struct hblk * current;
2828
2998
    struct hblk * current_start;  /* Start of block to be protected. */
2829
2999
    struct hblk * limit;
2882
3052
 
2883
3053
/* We assume that either the world is stopped or its OK to lose dirty   */
2884
3054
/* bits while this is happenning (as in GC_enable_incremental).         */
2885
 
void GC_read_dirty()
 
3055
void GC_read_dirty(void)
2886
3056
{
 
3057
#   if defined(GWW_VDB)
 
3058
      if (GC_GWW_AVAILABLE()) {
 
3059
        GC_gww_read_dirty();
 
3060
        return;
 
3061
      }
 
3062
#   endif
2887
3063
    BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
2888
3064
          (sizeof GC_dirty_pages));
2889
3065
    BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
2890
3066
    GC_protect_heap();
2891
3067
}
2892
3068
 
2893
 
GC_bool GC_page_was_dirty(h)
2894
 
struct hblk * h;
 
3069
GC_bool GC_page_was_dirty(struct hblk *h)
2895
3070
{
2896
 
    register word index = PHT_HASH(h);
 
3071
    register word index;
2897
3072
    
 
3073
#   if defined(GWW_VDB)
 
3074
      if (GC_GWW_AVAILABLE())
 
3075
        return GC_gww_page_was_dirty(h);
 
3076
#   endif
 
3077
 
 
3078
    index = PHT_HASH(h);
2898
3079
    return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
2899
3080
}
2900
3081
 
2908
3089
 
2909
3090
static GC_bool syscall_acquired_lock = FALSE;   /* Protected by GC lock. */
2910
3091
 
2911
 
void GC_begin_syscall()
 
3092
#if 0
 
3093
void GC_begin_syscall(void)
2912
3094
{
 
3095
    /* FIXME: Resurrecting this code would require fixing the   */
 
3096
    /* test, which can spuriously return TRUE.                  */
2913
3097
    if (!I_HOLD_LOCK()) {
2914
3098
        LOCK();
2915
3099
        syscall_acquired_lock = TRUE;
2916
3100
    }
2917
3101
}
2918
3102
 
2919
 
void GC_end_syscall()
 
3103
void GC_end_syscall(void)
2920
3104
{
2921
3105
    if (syscall_acquired_lock) {
2922
3106
        syscall_acquired_lock = FALSE;
2924
3108
    }
2925
3109
}
2926
3110
 
2927
 
void GC_unprotect_range(addr, len)
2928
 
ptr_t addr;
2929
 
word len;
 
3111
void GC_unprotect_range(ptr_t addr, word len)
2930
3112
{
2931
3113
    struct hblk * start_block;
2932
3114
    struct hblk * end_block;
2951
3133
              ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
2952
3134
}
2953
3135
 
2954
 
#if 0
2955
3136
 
2956
3137
/* We no longer wrap read by default, since that was causing too many   */
2957
3138
/* problems.  It is preferred that the client instead avoids writing    */
2968
3149
/* make sure that input is available.                                     */
2969
3150
/* Another, preferred alternative is to ensure that system calls never    */
2970
3151
/* write to the protected heap (see above).                               */
2971
 
# if defined(__STDC__) && !defined(SUNOS4)
2972
 
#   include <unistd.h>
2973
 
#   include <sys/uio.h>
2974
 
    ssize_t read(int fd, void *buf, size_t nbyte)
2975
 
# else
2976
 
#   ifndef LINT
2977
 
      int read(fd, buf, nbyte)
2978
 
#   else
2979
 
      int GC_read(fd, buf, nbyte)
2980
 
#   endif
2981
 
    int fd;
2982
 
    char *buf;
2983
 
    int nbyte;
2984
 
# endif
 
3152
# include <unistd.h>
 
3153
# include <sys/uio.h>
 
3154
ssize_t read(int fd, void *buf, size_t nbyte)
2985
3155
{
2986
3156
    int result;
2987
3157
    
3040
3210
#endif /* 0 */
3041
3211
 
3042
3212
/*ARGSUSED*/
3043
 
GC_bool GC_page_was_ever_dirty(h)
3044
 
struct hblk *h;
 
3213
GC_bool GC_page_was_ever_dirty(struct hblk *h)
3045
3214
{
 
3215
#   if defined(GWW_VDB)
 
3216
      if (GC_GWW_AVAILABLE())
 
3217
        return GC_gww_page_was_ever_dirty(h);
 
3218
#   endif
3046
3219
    return(TRUE);
3047
3220
}
3048
3221
 
3049
 
/* Reset the n pages starting at h to "was never dirty" status. */
3050
 
/*ARGSUSED*/
3051
 
void GC_is_fresh(h, n)
3052
 
struct hblk *h;
3053
 
word n;
3054
 
{
3055
 
}
3056
 
 
3057
3222
# endif /* MPROTECT_VDB */
3058
3223
 
3059
3224
# ifdef PROC_VDB
3081
3246
word GC_proc_buf_size = INITIAL_BUF_SZ;
3082
3247
char *GC_proc_buf;
3083
3248
 
3084
 
#ifdef GC_SOLARIS_THREADS
3085
 
/* We don't have exact sp values for threads.  So we count on   */
3086
 
/* occasionally declaring stack pages to be fresh.  Thus we     */
3087
 
/* need a real implementation of GC_is_fresh.  We can't clear   */
3088
 
/* entries in GC_written_pages, since that would declare all    */
3089
 
/* pages with the given hash address to be fresh.               */
3090
 
#   define MAX_FRESH_PAGES 8*1024       /* Must be power of 2 */
3091
 
    struct hblk ** GC_fresh_pages;      /* A direct mapped cache.       */
3092
 
                                        /* Collisions are dropped.      */
3093
 
 
3094
 
#   define FRESH_PAGE_SLOT(h) (divHBLKSZ((word)(h)) & (MAX_FRESH_PAGES-1))
3095
 
#   define ADD_FRESH_PAGE(h) \
3096
 
        GC_fresh_pages[FRESH_PAGE_SLOT(h)] = (h)
3097
 
#   define PAGE_IS_FRESH(h) \
3098
 
        (GC_fresh_pages[FRESH_PAGE_SLOT(h)] == (h) && (h) != 0)
3099
 
#endif
3100
 
 
3101
 
/* Add all pages in pht2 to pht1 */
3102
 
void GC_or_pages(pht1, pht2)
3103
 
page_hash_table pht1, pht2;
3104
 
{
3105
 
    register int i;
3106
 
    
3107
 
    for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
3108
 
}
3109
 
 
3110
3249
int GC_proc_fd;
3111
3250
 
3112
 
void GC_dirty_init()
 
3251
void GC_dirty_init(void)
3113
3252
{
3114
3253
    int fd;
3115
3254
    char buf[30];
3116
3255
 
3117
3256
    GC_dirty_maintained = TRUE;
3118
 
    if (GC_words_allocd != 0 || GC_words_allocd_before_gc != 0) {
 
3257
    if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) {
3119
3258
        register int i;
3120
3259
    
3121
3260
        for (i = 0; i < PHT_SIZE; i++) GC_written_pages[i] = (word)(-1);
3122
 
#       ifdef PRINTSTATS
3123
 
            GC_printf1("Allocated words:%lu:all pages may have been written\n",
3124
 
                       (unsigned long)
3125
 
                                (GC_words_allocd + GC_words_allocd_before_gc));
3126
 
#       endif       
 
3261
        if (GC_print_stats == VERBOSE)
 
3262
            GC_log_printf(
 
3263
                      "Allocated bytes:%lu:all pages may have been written\n",
 
3264
                      (unsigned long)
 
3265
                                (GC_bytes_allocd + GC_bytes_allocd_before_gc));
3127
3266
    }
3128
3267
    sprintf(buf, "/proc/%d", getpid());
3129
3268
    fd = open(buf, O_RDONLY);
3137
3276
        ABORT("/proc ioctl failed");
3138
3277
    }
3139
3278
    GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
3140
 
#   ifdef GC_SOLARIS_THREADS
3141
 
        GC_fresh_pages = (struct hblk **)
3142
 
          GC_scratch_alloc(MAX_FRESH_PAGES * sizeof (struct hblk *));
3143
 
        if (GC_fresh_pages == 0) {
3144
 
            GC_err_printf0("No space for fresh pages\n");
3145
 
            EXIT();
3146
 
        }
3147
 
        BZERO(GC_fresh_pages, MAX_FRESH_PAGES * sizeof (struct hblk *));
3148
 
#   endif
3149
3279
}
3150
3280
 
3151
3281
/* Ignore write hints. They don't help us here. */
3157
3287
{
3158
3288
}
3159
3289
 
3160
 
#ifdef GC_SOLARIS_THREADS
3161
 
#   define READ(fd,buf,nbytes) syscall(SYS_read, fd, buf, nbytes)
3162
 
#else
3163
 
#   define READ(fd,buf,nbytes) read(fd, buf, nbytes)
3164
 
#endif
 
3290
# define READ(fd,buf,nbytes) read(fd, buf, nbytes)
3165
3291
 
3166
 
void GC_read_dirty()
 
3292
void GC_read_dirty(void)
3167
3293
{
3168
3294
    unsigned long ps, np;
3169
3295
    int nmaps;
3172
3298
    char * bufp;
3173
3299
    ptr_t current_addr, limit;
3174
3300
    int i;
3175
 
int dummy;
3176
3301
 
3177
3302
    BZERO(GC_grungy_pages, (sizeof GC_grungy_pages));
3178
3303
    
3179
3304
    bufp = GC_proc_buf;
3180
3305
    if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
3181
 
#       ifdef PRINTSTATS
3182
 
            GC_printf1("/proc read failed: GC_proc_buf_size = %lu\n",
3183
 
                       GC_proc_buf_size);
3184
 
#       endif       
 
3306
        if (GC_print_stats)
 
3307
            GC_log_printf("/proc read failed: GC_proc_buf_size = %lu\n",
 
3308
                          (unsigned long)GC_proc_buf_size);
3185
3309
        {
3186
3310
            /* Retry with larger buffer. */
3187
3311
            word new_size = 2 * GC_proc_buf_size;
3196
3320
                /* Punt:        */
3197
3321
                memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
3198
3322
                memset(GC_written_pages, 0xff, sizeof(page_hash_table));
3199
 
#               ifdef GC_SOLARIS_THREADS
3200
 
                    BZERO(GC_fresh_pages,
3201
 
                          MAX_FRESH_PAGES * sizeof (struct hblk *)); 
3202
 
#               endif
3203
3323
                return;
3204
3324
            }
3205
3325
        }
3226
3346
                        register word index = PHT_HASH(h);
3227
3347
                        
3228
3348
                        set_pht_entry_from_index(GC_grungy_pages, index);
3229
 
#                       ifdef GC_SOLARIS_THREADS
3230
 
                          {
3231
 
                            register int slot = FRESH_PAGE_SLOT(h);
3232
 
                            
3233
 
                            if (GC_fresh_pages[slot] == h) {
3234
 
                                GC_fresh_pages[slot] = 0;
3235
 
                            }
3236
 
                          }
3237
 
#                       endif
3238
3349
                        h++;
3239
3350
                    }
3240
3351
                }
3244
3355
        }
3245
3356
    /* Update GC_written_pages. */
3246
3357
        GC_or_pages(GC_written_pages, GC_grungy_pages);
3247
 
#   ifdef GC_SOLARIS_THREADS
3248
 
      /* Make sure that old stacks are considered completely clean      */
3249
 
      /* unless written again.                                          */
3250
 
        GC_old_stacks_are_fresh();
3251
 
#   endif
3252
3358
}
3253
3359
 
3254
3360
#undef READ
3255
3361
 
3256
 
GC_bool GC_page_was_dirty(h)
3257
 
struct hblk *h;
 
3362
GC_bool GC_page_was_dirty(struct hblk *h)
3258
3363
{
3259
3364
    register word index = PHT_HASH(h);
3260
3365
    register GC_bool result;
3261
3366
    
3262
3367
    result = get_pht_entry_from_index(GC_grungy_pages, index);
3263
 
#   ifdef GC_SOLARIS_THREADS
3264
 
        if (result && PAGE_IS_FRESH(h)) result = FALSE;
3265
 
        /* This happens only if page was declared fresh since   */
3266
 
        /* the read_dirty call, e.g. because it's in an unused  */
3267
 
        /* thread stack.  It's OK to treat it as clean, in      */
3268
 
        /* that case.  And it's consistent with                 */
3269
 
        /* GC_page_was_ever_dirty.                              */
3270
 
#   endif
3271
3368
    return(result);
3272
3369
}
3273
3370
 
3274
 
GC_bool GC_page_was_ever_dirty(h)
3275
 
struct hblk *h;
 
3371
GC_bool GC_page_was_ever_dirty(struct hblk *h)
3276
3372
{
3277
3373
    register word index = PHT_HASH(h);
3278
3374
    register GC_bool result;
3279
3375
    
3280
3376
    result = get_pht_entry_from_index(GC_written_pages, index);
3281
 
#   ifdef GC_SOLARIS_THREADS
3282
 
        if (result && PAGE_IS_FRESH(h)) result = FALSE;
3283
 
#   endif
3284
3377
    return(result);
3285
3378
}
3286
3379
 
3287
 
/* Caller holds allocation lock.        */
3288
 
void GC_is_fresh(h, n)
3289
 
struct hblk *h;
3290
 
word n;
3291
 
{
3292
 
 
3293
 
    register word index;
3294
 
    
3295
 
#   ifdef GC_SOLARIS_THREADS
3296
 
      register word i;
3297
 
      
3298
 
      if (GC_fresh_pages != 0) {
3299
 
        for (i = 0; i < n; i++) {
3300
 
          ADD_FRESH_PAGE(h + i);
3301
 
        }
3302
 
      }
3303
 
#   endif
3304
 
}
3305
 
 
3306
3380
# endif /* PROC_VDB */
3307
3381
 
3308
3382
 
3317
3391
ptr_t GC_vd_base;       /* Address corresponding to GC_grungy_bits[0]   */
3318
3392
                        /* HBLKSIZE aligned.                            */
3319
3393
 
3320
 
void GC_dirty_init()
 
3394
void GC_dirty_init(void)
3321
3395
{
3322
3396
    GC_dirty_maintained = TRUE;
3323
3397
    /* For the time being, we assume the heap generally grows up */
3331
3405
    }
3332
3406
}
3333
3407
 
3334
 
void GC_read_dirty()
 
3408
void GC_read_dirty(void)
3335
3409
{
3336
3410
    /* lazily enable dirty bits on newly added heap sects */
3337
3411
    {
3351
3425
    }
3352
3426
}
3353
3427
 
3354
 
GC_bool GC_page_was_dirty(h)
3355
 
struct hblk *h;
 
3428
GC_bool GC_page_was_dirty(struct hblk *h)
3356
3429
{
3357
3430
    if((ptr_t)h < GC_vd_base || (ptr_t)h >= GC_vd_base + NPAGES*HBLKSIZE) {
3358
3431
        return(TRUE);
3361
3434
}
3362
3435
 
3363
3436
/*ARGSUSED*/
3364
 
void GC_remove_protection(h, nblocks, is_ptrfree)
3365
 
struct hblk *h;
3366
 
word nblocks;
3367
 
GC_bool is_ptrfree;
 
3437
void GC_remove_protection(struct hblk *h, word nblocks, GC_bool is_ptrfree)
3368
3438
{
3369
3439
    PCR_VD_WriteProtectDisable(h, nblocks*HBLKSIZE);
3370
3440
    PCR_VD_WriteProtectEnable(h, nblocks*HBLKSIZE);
3377
3447
   code:
3378
3448
      1. Apple's mach/xnu documentation
3379
3449
      2. Timothy J. Wood's "Mach Exception Handlers 101" post to the
3380
 
         omnigroup's macosx-dev list. 
3381
 
         www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html
 
3450
         omnigroup's macosx-dev list.
 
3451
         www.omnigroup.com/mailman/archive/macosx-dev/2000-June/014178.html
3382
3452
      3. macosx-nat.c from Apple's GDB source code.
3383
3453
*/
3384
 
   
 
3454
 
3385
3455
/* The bug that caused all this trouble should now be fixed. This should
3386
3456
   eventually be removed if all goes well. */
3387
 
/* define BROKEN_EXCEPTION_HANDLING */
3388
 
    
 
3457
 
 
3458
/* #define BROKEN_EXCEPTION_HANDLING */
 
3459
 
3389
3460
#include <mach/mach.h>
3390
3461
#include <mach/mach_error.h>
3391
3462
#include <mach/thread_status.h>
3393
3464
#include <mach/task.h>
3394
3465
#include <pthread.h>
3395
3466
 
 
3467
extern void GC_darwin_register_mach_handler_thread(mach_port_t);
 
3468
 
3396
3469
/* These are not defined in any header, although they are documented */
3397
 
extern boolean_t exc_server(mach_msg_header_t *,mach_msg_header_t *);
3398
 
extern kern_return_t exception_raise(
3399
 
    mach_port_t,mach_port_t,mach_port_t,
3400
 
    exception_type_t,exception_data_t,mach_msg_type_number_t);
3401
 
extern kern_return_t exception_raise_state(
3402
 
    mach_port_t,mach_port_t,mach_port_t,
3403
 
    exception_type_t,exception_data_t,mach_msg_type_number_t,
3404
 
    thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
3405
 
    thread_state_t,mach_msg_type_number_t*);
3406
 
extern kern_return_t exception_raise_state_identity(
3407
 
    mach_port_t,mach_port_t,mach_port_t,
3408
 
    exception_type_t,exception_data_t,mach_msg_type_number_t,
3409
 
    thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
3410
 
    thread_state_t,mach_msg_type_number_t*);
 
3470
extern boolean_t
 
3471
exc_server(mach_msg_header_t *, mach_msg_header_t *);
 
3472
 
 
3473
extern kern_return_t
 
3474
exception_raise(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
 
3475
                exception_data_t, mach_msg_type_number_t);
 
3476
 
 
3477
extern kern_return_t
 
3478
exception_raise_state(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
 
3479
                      exception_data_t, mach_msg_type_number_t,
 
3480
                      thread_state_flavor_t*, thread_state_t,
 
3481
                      mach_msg_type_number_t, thread_state_t,
 
3482
                      mach_msg_type_number_t*);
 
3483
 
 
3484
extern kern_return_t
 
3485
exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
 
3486
                               exception_type_t, exception_data_t,
 
3487
                               mach_msg_type_number_t, thread_state_flavor_t*,
 
3488
                               thread_state_t, mach_msg_type_number_t,
 
3489
                               thread_state_t, mach_msg_type_number_t*);
3411
3490
 
3412
3491
 
3413
3492
#define MAX_EXCEPTION_PORTS 16
3449
3528
GC_mprotect_state_t GC_mprotect_state;
3450
3529
 
3451
3530
/* The following should ONLY be called when the world is stopped  */
3452
 
static void GC_mprotect_thread_notify(mach_msg_id_t id) {
3453
 
    struct {
3454
 
        GC_msg_t msg;
3455
 
        mach_msg_trailer_t trailer;
3456
 
    } buf;
3457
 
    mach_msg_return_t r;
3458
 
    /* remote, local */
3459
 
    buf.msg.head.msgh_bits = 
3460
 
        MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
3461
 
    buf.msg.head.msgh_size = sizeof(buf.msg);
3462
 
    buf.msg.head.msgh_remote_port = GC_ports.exception;
3463
 
    buf.msg.head.msgh_local_port = MACH_PORT_NULL;
3464
 
    buf.msg.head.msgh_id = id;
3465
 
            
3466
 
    r = mach_msg(
3467
 
        &buf.msg.head,
3468
 
        MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_LARGE,
3469
 
        sizeof(buf.msg),
3470
 
        sizeof(buf),
3471
 
        GC_ports.reply,
3472
 
        MACH_MSG_TIMEOUT_NONE,
3473
 
        MACH_PORT_NULL);
3474
 
    if(r != MACH_MSG_SUCCESS)
3475
 
        ABORT("mach_msg failed in GC_mprotect_thread_notify");
3476
 
    if(buf.msg.head.msgh_id != ID_ACK)
3477
 
        ABORT("invalid ack in GC_mprotect_thread_notify");
 
3531
static void GC_mprotect_thread_notify(mach_msg_id_t id)
 
3532
{
 
3533
 
 
3534
  struct {
 
3535
    GC_msg_t msg;
 
3536
    mach_msg_trailer_t trailer;
 
3537
  } buf;
 
3538
 
 
3539
  mach_msg_return_t r;
 
3540
  /* remote, local */
 
3541
  buf.msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
 
3542
  buf.msg.head.msgh_size = sizeof(buf.msg);
 
3543
  buf.msg.head.msgh_remote_port = GC_ports.exception;
 
3544
  buf.msg.head.msgh_local_port = MACH_PORT_NULL;
 
3545
  buf.msg.head.msgh_id = id;
 
3546
 
 
3547
  r = mach_msg(&buf.msg.head, MACH_SEND_MSG | MACH_RCV_MSG | MACH_RCV_LARGE,
 
3548
               sizeof(buf.msg), sizeof(buf), GC_ports.reply,
 
3549
               MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
 
3550
  if(r != MACH_MSG_SUCCESS)
 
3551
    ABORT("mach_msg failed in GC_mprotect_thread_notify");
 
3552
  if(buf.msg.head.msgh_id != ID_ACK)
 
3553
    ABORT("invalid ack in GC_mprotect_thread_notify");
3478
3554
}
3479
3555
 
3480
3556
/* Should only be called by the mprotect thread */
3481
 
static void GC_mprotect_thread_reply() {
3482
 
    GC_msg_t msg;
3483
 
    mach_msg_return_t r;
3484
 
    /* remote, local */
3485
 
    msg.head.msgh_bits = 
3486
 
        MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
3487
 
    msg.head.msgh_size = sizeof(msg);
3488
 
    msg.head.msgh_remote_port = GC_ports.reply;
3489
 
    msg.head.msgh_local_port = MACH_PORT_NULL;
3490
 
    msg.head.msgh_id = ID_ACK;
3491
 
            
3492
 
    r = mach_msg(
3493
 
        &msg.head,
3494
 
        MACH_SEND_MSG,
3495
 
        sizeof(msg),
3496
 
        0,
3497
 
        MACH_PORT_NULL,
3498
 
        MACH_MSG_TIMEOUT_NONE,
3499
 
        MACH_PORT_NULL);
3500
 
    if(r != MACH_MSG_SUCCESS)
3501
 
        ABORT("mach_msg failed in GC_mprotect_thread_reply");
3502
 
}
3503
 
 
3504
 
void GC_mprotect_stop() {
3505
 
    GC_mprotect_thread_notify(ID_STOP);
3506
 
}
3507
 
void GC_mprotect_resume() {
3508
 
    GC_mprotect_thread_notify(ID_RESUME);
 
3557
static void GC_mprotect_thread_reply(void)
 
3558
{
 
3559
 
 
3560
  GC_msg_t msg;
 
3561
  mach_msg_return_t r;
 
3562
  /* remote, local */
 
3563
  msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
 
3564
  msg.head.msgh_size = sizeof(msg);
 
3565
  msg.head.msgh_remote_port = GC_ports.reply;
 
3566
  msg.head.msgh_local_port = MACH_PORT_NULL;
 
3567
  msg.head.msgh_id = ID_ACK;
 
3568
 
 
3569
  r = mach_msg(&msg.head, MACH_SEND_MSG, sizeof(msg), 0, MACH_PORT_NULL,
 
3570
               MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
 
3571
  if(r != MACH_MSG_SUCCESS)
 
3572
    ABORT("mach_msg failed in GC_mprotect_thread_reply");
 
3573
}
 
3574
 
 
3575
void GC_mprotect_stop(void)
 
3576
{
 
3577
  GC_mprotect_thread_notify(ID_STOP);
 
3578
}
 
3579
void GC_mprotect_resume(void)
 
3580
{
 
3581
  GC_mprotect_thread_notify(ID_RESUME);
3509
3582
}
3510
3583
 
3511
3584
#else /* !THREADS */
3513
3586
#define GC_mprotect_state GC_MP_NORMAL
3514
3587
#endif
3515
3588
 
3516
 
static void *GC_mprotect_thread(void *arg) {
3517
 
    mach_msg_return_t r;
3518
 
    /* These two structures contain some private kernel data. We don't need to
3519
 
       access any of it so we don't bother defining a proper struct. The
3520
 
       correct definitions are in the xnu source code. */
3521
 
    struct {
3522
 
        mach_msg_header_t head;
3523
 
        char data[256];
3524
 
    } reply;
3525
 
    struct {
3526
 
        mach_msg_header_t head;
3527
 
        mach_msg_body_t msgh_body;
3528
 
        char data[1024];
3529
 
    } msg;
3530
 
 
3531
 
    mach_msg_id_t id;
3532
 
 
3533
 
    GC_darwin_register_mach_handler_thread(mach_thread_self());
3534
 
    
3535
 
    for(;;) {
3536
 
        r = mach_msg(
3537
 
            &msg.head,
3538
 
            MACH_RCV_MSG|MACH_RCV_LARGE|
3539
 
                (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 0),
3540
 
            0,
3541
 
            sizeof(msg),
3542
 
            GC_ports.exception,
3543
 
            GC_mprotect_state == GC_MP_DISCARDING ? 0 : MACH_MSG_TIMEOUT_NONE,
3544
 
            MACH_PORT_NULL);
3545
 
        
3546
 
        id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
3547
 
        
3548
 
#if defined(THREADS)
3549
 
        if(GC_mprotect_state == GC_MP_DISCARDING) {
3550
 
            if(r == MACH_RCV_TIMED_OUT) {
3551
 
                GC_mprotect_state = GC_MP_STOPPED;
3552
 
                GC_mprotect_thread_reply();
3553
 
                continue;
3554
 
            }
3555
 
            if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
3556
 
                ABORT("out of order mprotect thread request");
3557
 
        }
3558
 
#endif
3559
 
        
3560
 
        if(r != MACH_MSG_SUCCESS) {
3561
 
            GC_err_printf2("mach_msg failed with %d %s\n", 
3562
 
                (int)r,mach_error_string(r));
3563
 
            ABORT("mach_msg failed");
3564
 
        }
3565
 
        
3566
 
        switch(id) {
3567
 
#if defined(THREADS)
3568
 
            case ID_STOP:
3569
 
                if(GC_mprotect_state != GC_MP_NORMAL)
3570
 
                    ABORT("Called mprotect_stop when state wasn't normal");
3571
 
                GC_mprotect_state = GC_MP_DISCARDING;
3572
 
                break;
3573
 
            case ID_RESUME:
3574
 
                if(GC_mprotect_state != GC_MP_STOPPED)
3575
 
                    ABORT("Called mprotect_resume when state wasn't stopped");
3576
 
                GC_mprotect_state = GC_MP_NORMAL;
3577
 
                GC_mprotect_thread_reply();
3578
 
                break;
3579
 
#endif /* THREADS */
3580
 
            default:
3581
 
                    /* Handle the message (calls catch_exception_raise) */
3582
 
                if(!exc_server(&msg.head,&reply.head))
3583
 
                    ABORT("exc_server failed");
3584
 
                /* Send the reply */
3585
 
                r = mach_msg(
3586
 
                    &reply.head,
3587
 
                    MACH_SEND_MSG,
3588
 
                    reply.head.msgh_size,
3589
 
                    0,
3590
 
                    MACH_PORT_NULL,
3591
 
                    MACH_MSG_TIMEOUT_NONE,
3592
 
                    MACH_PORT_NULL);
3593
 
                if(r != MACH_MSG_SUCCESS) {
3594
 
                        /* This will fail if the thread dies, but the thread shouldn't
3595
 
                           die... */
3596
 
                        #ifdef BROKEN_EXCEPTION_HANDLING
3597
 
                        GC_err_printf2(
3598
 
                        "mach_msg failed with %d %s while sending exc reply\n",
3599
 
                        (int)r,mach_error_string(r));
3600
 
                #else
3601
 
                        ABORT("mach_msg failed while sending exception reply");
3602
 
                #endif
3603
 
                }
3604
 
        } /* switch */
3605
 
    } /* for(;;) */
 
3589
static void *GC_mprotect_thread(void *arg)
 
3590
{
 
3591
  mach_msg_return_t r;
 
3592
  /* These two structures contain some private kernel data. We don't need to
 
3593
     access any of it so we don't bother defining a proper struct. The
 
3594
     correct definitions are in the xnu source code. */
 
3595
  struct {
 
3596
    mach_msg_header_t head;
 
3597
    char data[256];
 
3598
  } reply;
 
3599
  struct {
 
3600
    mach_msg_header_t head;
 
3601
    mach_msg_body_t msgh_body;
 
3602
    char data[1024];
 
3603
  } msg;
 
3604
 
 
3605
  mach_msg_id_t id;
 
3606
 
 
3607
  GC_darwin_register_mach_handler_thread(mach_thread_self());
 
3608
 
 
3609
  for(;;) {
 
3610
    r = mach_msg(&msg.head, MACH_RCV_MSG | MACH_RCV_LARGE |
 
3611
                 (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 0),
 
3612
                 0, sizeof(msg), GC_ports.exception,
 
3613
                 GC_mprotect_state == GC_MP_DISCARDING ? 0
 
3614
                 : MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
 
3615
 
 
3616
    id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
 
3617
 
 
3618
#   if defined(THREADS)
 
3619
      if(GC_mprotect_state == GC_MP_DISCARDING) {
 
3620
        if(r == MACH_RCV_TIMED_OUT) {
 
3621
          GC_mprotect_state = GC_MP_STOPPED;
 
3622
          GC_mprotect_thread_reply();
 
3623
          continue;
 
3624
        }
 
3625
        if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
 
3626
          ABORT("out of order mprotect thread request");
 
3627
      }
 
3628
#   endif /* THREADS */
 
3629
 
 
3630
    if(r != MACH_MSG_SUCCESS) {
 
3631
      GC_err_printf("mach_msg failed with %d %s\n", (int)r,
 
3632
                    mach_error_string(r));
 
3633
      ABORT("mach_msg failed");
 
3634
    }
 
3635
 
 
3636
    switch(id) {
 
3637
#     if defined(THREADS)
 
3638
        case ID_STOP:
 
3639
          if(GC_mprotect_state != GC_MP_NORMAL)
 
3640
            ABORT("Called mprotect_stop when state wasn't normal");
 
3641
          GC_mprotect_state = GC_MP_DISCARDING;
 
3642
          break;
 
3643
        case ID_RESUME:
 
3644
          if(GC_mprotect_state != GC_MP_STOPPED)
 
3645
            ABORT("Called mprotect_resume when state wasn't stopped");
 
3646
          GC_mprotect_state = GC_MP_NORMAL;
 
3647
          GC_mprotect_thread_reply();
 
3648
          break;
 
3649
#     endif /* THREADS */
 
3650
        default:
 
3651
          /* Handle the message (calls catch_exception_raise) */
 
3652
          if(!exc_server(&msg.head, &reply.head))
 
3653
            ABORT("exc_server failed");
 
3654
          /* Send the reply */
 
3655
          r = mach_msg(&reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0,
 
3656
                       MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
 
3657
                       MACH_PORT_NULL);
 
3658
          if(r != MACH_MSG_SUCCESS) {
 
3659
            /* This will fail if the thread dies, but the thread */
 
3660
            /* shouldn't die... */
 
3661
#           ifdef BROKEN_EXCEPTION_HANDLING
 
3662
              GC_err_printf("mach_msg failed with %d %s while sending"
 
3663
                            "exc reply\n", (int)r,mach_error_string(r));
 
3664
#           else
 
3665
              ABORT("mach_msg failed while sending exception reply");
 
3666
#           endif
 
3667
          }
 
3668
    } /* switch */
 
3669
  } /* for(;;) */
3606
3670
    /* NOT REACHED */
3607
 
    return NULL;
 
3671
  return NULL;
3608
3672
}
3609
3673
 
3610
3674
/* All this SIGBUS code shouldn't be necessary. All protection faults should
3613
3677
   meaningless and safe to ignore. */
3614
3678
#ifdef BROKEN_EXCEPTION_HANDLING
3615
3679
 
3616
 
typedef void (* SIG_PF)();
3617
 
static SIG_PF GC_old_bus_handler;
 
3680
static SIG_HNDLR_PTR GC_old_bus_handler;
3618
3681
 
3619
3682
/* Updates to this aren't atomic, but the SIGBUSs seem pretty rare.
3620
3683
   Even if this doesn't get updated property, it isn't really a problem */
3621
3684
static int GC_sigbus_count;
3622
3685
 
3623
 
static void GC_darwin_sigbus(int num,siginfo_t *sip,void *context) {
3624
 
    if(num != SIGBUS) ABORT("Got a non-sigbus signal in the sigbus handler");
3625
 
    
3626
 
    /* Ugh... some seem safe to ignore, but too many in a row probably means
3627
 
       trouble. GC_sigbus_count is reset for each mach exception that is
3628
 
       handled */
3629
 
    if(GC_sigbus_count >= 8) {
3630
 
        ABORT("Got more than 8 SIGBUSs in a row!");
3631
 
    } else {
3632
 
        GC_sigbus_count++;
3633
 
        GC_err_printf0("GC: WARNING: Ignoring SIGBUS.\n");
3634
 
    }
 
3686
static void GC_darwin_sigbus(int num, siginfo_t *sip, void *context)
 
3687
{
 
3688
  if(num != SIGBUS)
 
3689
    ABORT("Got a non-sigbus signal in the sigbus handler");
 
3690
 
 
3691
  /* Ugh... some seem safe to ignore, but too many in a row probably means
 
3692
     trouble. GC_sigbus_count is reset for each mach exception that is
 
3693
     handled */
 
3694
  if(GC_sigbus_count >= 8) {
 
3695
    ABORT("Got more than 8 SIGBUSs in a row!");
 
3696
  } else {
 
3697
    GC_sigbus_count++;
 
3698
    WARN("Ignoring SIGBUS.\n", 0);
 
3699
  }
3635
3700
}
3636
3701
#endif /* BROKEN_EXCEPTION_HANDLING */
3637
3702
 
3638
 
void GC_dirty_init() {
3639
 
    kern_return_t r;
3640
 
    mach_port_t me;
3641
 
    pthread_t thread;
3642
 
    pthread_attr_t attr;
3643
 
    exception_mask_t mask;
3644
 
    
3645
 
#   ifdef PRINTSTATS
3646
 
        GC_printf0("Inititalizing mach/darwin mprotect virtual dirty bit "
3647
 
            "implementation\n");
3648
 
#   endif  
3649
 
#       ifdef BROKEN_EXCEPTION_HANDLING
3650
 
        GC_err_printf0("GC: WARNING: Enabling workarounds for various darwin "
3651
 
            "exception handling bugs.\n");
3652
 
#       endif
3653
 
    GC_dirty_maintained = TRUE;
3654
 
    if (GC_page_size % HBLKSIZE != 0) {
3655
 
        GC_err_printf0("Page size not multiple of HBLKSIZE\n");
3656
 
        ABORT("Page size not multiple of HBLKSIZE");
3657
 
    }
3658
 
    
3659
 
    GC_task_self = me = mach_task_self();
3660
 
    
3661
 
    r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.exception);
3662
 
    if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (exception port)");
3663
 
    
3664
 
    r = mach_port_insert_right(me,GC_ports.exception,GC_ports.exception,
3665
 
        MACH_MSG_TYPE_MAKE_SEND);
3666
 
    if(r != KERN_SUCCESS)
3667
 
        ABORT("mach_port_insert_right failed (exception port)");
3668
 
 
3669
 
    #if defined(THREADS)
3670
 
        r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.reply);
3671
 
        if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (reply port)");
3672
 
    #endif
3673
 
 
3674
 
    /* The exceptions we want to catch */  
3675
 
    mask = EXC_MASK_BAD_ACCESS;
3676
 
 
3677
 
    r = task_get_exception_ports(
3678
 
        me,
3679
 
        mask,
3680
 
        GC_old_exc_ports.masks,
3681
 
        &GC_old_exc_ports.count,
3682
 
        GC_old_exc_ports.ports,
3683
 
        GC_old_exc_ports.behaviors,
3684
 
        GC_old_exc_ports.flavors
3685
 
    );
3686
 
    if(r != KERN_SUCCESS) ABORT("task_get_exception_ports failed");
3687
 
        
3688
 
    r = task_set_exception_ports(
3689
 
        me,
3690
 
        mask,
3691
 
        GC_ports.exception,
3692
 
        EXCEPTION_DEFAULT,
3693
 
        MACHINE_THREAD_STATE
3694
 
    );
3695
 
    if(r != KERN_SUCCESS) ABORT("task_set_exception_ports failed");
3696
 
 
3697
 
    if(pthread_attr_init(&attr) != 0) ABORT("pthread_attr_init failed");
3698
 
    if(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED) != 0) 
3699
 
        ABORT("pthread_attr_setdetachedstate failed");
3700
 
 
3701
 
#       undef pthread_create
3702
 
    /* This will call the real pthread function, not our wrapper */
3703
 
    if(pthread_create(&thread,&attr,GC_mprotect_thread,NULL) != 0)
3704
 
        ABORT("pthread_create failed");
3705
 
    pthread_attr_destroy(&attr);
3706
 
    
3707
 
    /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
3708
 
    #ifdef BROKEN_EXCEPTION_HANDLING 
 
3703
void GC_dirty_init(void)
 
3704
{
 
3705
  kern_return_t r;
 
3706
  mach_port_t me;
 
3707
  pthread_t thread;
 
3708
  pthread_attr_t attr;
 
3709
  exception_mask_t mask;
 
3710
 
 
3711
  if (GC_print_stats == VERBOSE)
 
3712
    GC_log_printf("Inititalizing mach/darwin mprotect virtual dirty bit "
 
3713
                  "implementation\n");
 
3714
# ifdef BROKEN_EXCEPTION_HANDLING
 
3715
    WARN("Enabling workarounds for various darwin "
 
3716
         "exception handling bugs.\n", 0);
 
3717
# endif
 
3718
  GC_dirty_maintained = TRUE;
 
3719
  if (GC_page_size % HBLKSIZE != 0) {
 
3720
    GC_err_printf("Page size not multiple of HBLKSIZE\n");
 
3721
    ABORT("Page size not multiple of HBLKSIZE");
 
3722
  }
 
3723
 
 
3724
  GC_task_self = me = mach_task_self();
 
3725
 
 
3726
  r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.exception);
 
3727
  if(r != KERN_SUCCESS)
 
3728
    ABORT("mach_port_allocate failed (exception port)");
 
3729
 
 
3730
  r = mach_port_insert_right(me, GC_ports.exception, GC_ports.exception,
 
3731
                             MACH_MSG_TYPE_MAKE_SEND);
 
3732
  if(r != KERN_SUCCESS)
 
3733
    ABORT("mach_port_insert_right failed (exception port)");
 
3734
 
 
3735
#  if defined(THREADS)
 
3736
     r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.reply);
 
3737
     if(r != KERN_SUCCESS)
 
3738
       ABORT("mach_port_allocate failed (reply port)");
 
3739
#  endif
 
3740
 
 
3741
  /* The exceptions we want to catch */
 
3742
  mask = EXC_MASK_BAD_ACCESS;
 
3743
 
 
3744
  r = task_get_exception_ports(me, mask, GC_old_exc_ports.masks,
 
3745
                               &GC_old_exc_ports.count, GC_old_exc_ports.ports,
 
3746
                               GC_old_exc_ports.behaviors,
 
3747
                               GC_old_exc_ports.flavors);
 
3748
  if(r != KERN_SUCCESS)
 
3749
    ABORT("task_get_exception_ports failed");
 
3750
 
 
3751
  r = task_set_exception_ports(me, mask, GC_ports.exception, EXCEPTION_DEFAULT,
 
3752
                               GC_MACH_THREAD_STATE);
 
3753
  if(r != KERN_SUCCESS)
 
3754
    ABORT("task_set_exception_ports failed");
 
3755
  if(pthread_attr_init(&attr) != 0)
 
3756
    ABORT("pthread_attr_init failed");
 
3757
  if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
 
3758
    ABORT("pthread_attr_setdetachedstate failed");
 
3759
 
 
3760
# undef pthread_create
 
3761
  /* This will call the real pthread function, not our wrapper */
 
3762
  if(pthread_create(&thread, &attr, GC_mprotect_thread, NULL) != 0)
 
3763
    ABORT("pthread_create failed");
 
3764
  pthread_attr_destroy(&attr);
 
3765
 
 
3766
  /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
 
3767
# ifdef BROKEN_EXCEPTION_HANDLING
3709
3768
    {
3710
 
        struct sigaction sa, oldsa;
3711
 
        sa.sa_handler = (SIG_PF)GC_darwin_sigbus;
3712
 
        sigemptyset(&sa.sa_mask);
3713
 
        sa.sa_flags = SA_RESTART|SA_SIGINFO;
3714
 
        if(sigaction(SIGBUS,&sa,&oldsa) < 0) ABORT("sigaction");
3715
 
        GC_old_bus_handler = (SIG_PF)oldsa.sa_handler;
3716
 
        if (GC_old_bus_handler != SIG_DFL) {
3717
 
#               ifdef PRINTSTATS
3718
 
                GC_err_printf0("Replaced other SIGBUS handler\n");
3719
 
#               endif
3720
 
        }
 
3769
      struct sigaction sa, oldsa;
 
3770
      sa.sa_handler = (SIG_HNDLR_PTR)GC_darwin_sigbus;
 
3771
      sigemptyset(&sa.sa_mask);
 
3772
      sa.sa_flags = SA_RESTART|SA_SIGINFO;
 
3773
      if(sigaction(SIGBUS, &sa, &oldsa) < 0)
 
3774
        ABORT("sigaction");
 
3775
      GC_old_bus_handler = (SIG_HNDLR_PTR)oldsa.sa_handler;
 
3776
      if (GC_old_bus_handler != SIG_DFL) {
 
3777
        if (GC_print_stats == VERBOSE)
 
3778
          GC_err_printf("Replaced other SIGBUS handler\n");
 
3779
      }
3721
3780
    }
3722
 
    #endif /* BROKEN_EXCEPTION_HANDLING  */
 
3781
#  endif /* BROKEN_EXCEPTION_HANDLING  */
3723
3782
}
3724
 
 
 
3783
 
3725
3784
/* The source code for Apple's GDB was used as a reference for the exception
3726
 
   forwarding code. This code is similar to be GDB code only because there is 
 
3785
   forwarding code. This code is similar to be GDB code only because there is
3727
3786
   only one way to do it. */
3728
 
static kern_return_t GC_forward_exception(
3729
 
        mach_port_t thread,
3730
 
        mach_port_t task,
3731
 
        exception_type_t exception,
3732
 
        exception_data_t data,
3733
 
        mach_msg_type_number_t data_count
3734
 
) {
3735
 
    int i;
3736
 
    kern_return_t r;
3737
 
    mach_port_t port;
3738
 
    exception_behavior_t behavior;
3739
 
    thread_state_flavor_t flavor;
3740
 
    
3741
 
    thread_state_t thread_state;
3742
 
    mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
3743
 
        
3744
 
    for(i=0;i<GC_old_exc_ports.count;i++)
3745
 
        if(GC_old_exc_ports.masks[i] & (1 << exception))
3746
 
            break;
3747
 
    if(i==GC_old_exc_ports.count) ABORT("No handler for exception!");
3748
 
    
3749
 
    port = GC_old_exc_ports.ports[i];
3750
 
    behavior = GC_old_exc_ports.behaviors[i];
3751
 
    flavor = GC_old_exc_ports.flavors[i];
3752
 
 
3753
 
    if(behavior != EXCEPTION_DEFAULT) {
3754
 
        r = thread_get_state(thread,flavor,thread_state,&thread_state_count);
3755
 
        if(r != KERN_SUCCESS)
3756
 
            ABORT("thread_get_state failed in forward_exception");
3757
 
    }
3758
 
    
3759
 
    switch(behavior) {
3760
 
        case EXCEPTION_DEFAULT:
3761
 
            r = exception_raise(port,thread,task,exception,data,data_count);
3762
 
            break;
3763
 
        case EXCEPTION_STATE:
3764
 
            r = exception_raise_state(port,thread,task,exception,data,
3765
 
                data_count,&flavor,thread_state,thread_state_count,
3766
 
                thread_state,&thread_state_count);
3767
 
            break;
3768
 
        case EXCEPTION_STATE_IDENTITY:
3769
 
            r = exception_raise_state_identity(port,thread,task,exception,data,
3770
 
                data_count,&flavor,thread_state,thread_state_count,
3771
 
                thread_state,&thread_state_count);
3772
 
            break;
3773
 
        default:
3774
 
            r = KERN_FAILURE; /* make gcc happy */
3775
 
            ABORT("forward_exception: unknown behavior");
3776
 
            break;
3777
 
    }
3778
 
    
3779
 
    if(behavior != EXCEPTION_DEFAULT) {
3780
 
        r = thread_set_state(thread,flavor,thread_state,thread_state_count);
3781
 
        if(r != KERN_SUCCESS)
3782
 
            ABORT("thread_set_state failed in forward_exception");
3783
 
    }
3784
 
    
3785
 
    return r;
 
3787
static kern_return_t GC_forward_exception(mach_port_t thread, mach_port_t task,
 
3788
                                          exception_type_t exception,
 
3789
                                          exception_data_t data,
 
3790
                                          mach_msg_type_number_t data_count)
 
3791
{
 
3792
  unsigned int i;
 
3793
  kern_return_t r;
 
3794
  mach_port_t port;
 
3795
  exception_behavior_t behavior;
 
3796
  thread_state_flavor_t flavor;
 
3797
 
 
3798
  thread_state_t thread_state = NULL;
 
3799
  mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
 
3800
 
 
3801
  for(i=0; i < GC_old_exc_ports.count; i++)
 
3802
    if(GC_old_exc_ports.masks[i] & (1 << exception))
 
3803
      break;
 
3804
  if(i==GC_old_exc_ports.count)
 
3805
    ABORT("No handler for exception!");
 
3806
 
 
3807
  port = GC_old_exc_ports.ports[i];
 
3808
  behavior = GC_old_exc_ports.behaviors[i];
 
3809
  flavor = GC_old_exc_ports.flavors[i];
 
3810
 
 
3811
  if(behavior != EXCEPTION_DEFAULT) {
 
3812
    r = thread_get_state(thread, flavor, thread_state, &thread_state_count);
 
3813
    if(r != KERN_SUCCESS)
 
3814
      ABORT("thread_get_state failed in forward_exception");
 
3815
    }
 
3816
 
 
3817
  switch(behavior) {
 
3818
    case EXCEPTION_DEFAULT:
 
3819
      r = exception_raise(port, thread, task, exception, data, data_count);
 
3820
      break;
 
3821
    case EXCEPTION_STATE:
 
3822
      r = exception_raise_state(port, thread, task, exception, data, data_count,
 
3823
                                &flavor, thread_state, thread_state_count,
 
3824
                                thread_state, &thread_state_count);
 
3825
      break;
 
3826
    case EXCEPTION_STATE_IDENTITY:
 
3827
      r = exception_raise_state_identity(port, thread, task, exception, data,
 
3828
                                         data_count, &flavor, thread_state,
 
3829
                                         thread_state_count, thread_state,
 
3830
                                         &thread_state_count);
 
3831
      break;
 
3832
    default:
 
3833
      r = KERN_FAILURE; /* make gcc happy */
 
3834
      ABORT("forward_exception: unknown behavior");
 
3835
      break;
 
3836
  }
 
3837
 
 
3838
  if(behavior != EXCEPTION_DEFAULT) {
 
3839
    r = thread_set_state(thread, flavor, thread_state, thread_state_count);
 
3840
    if(r != KERN_SUCCESS)
 
3841
      ABORT("thread_set_state failed in forward_exception");
 
3842
  }
 
3843
 
 
3844
  return r;
3786
3845
}
3787
3846
 
3788
 
#define FWD() GC_forward_exception(thread,task,exception,code,code_count)
 
3847
#define FWD() GC_forward_exception(thread, task, exception, code, code_count)
3789
3848
 
3790
3849
/* This violates the namespace rules but there isn't anything that can be done
3791
3850
   about it. The exception handling stuff is hard coded to call this */
3792
3851
kern_return_t
3793
 
catch_exception_raise(
3794
 
   mach_port_t exception_port,mach_port_t thread,mach_port_t task,
3795
 
   exception_type_t exception,exception_data_t code,
3796
 
   mach_msg_type_number_t code_count
3797
 
) {
3798
 
    kern_return_t r;
3799
 
    char *addr;
3800
 
    struct hblk *h;
3801
 
    int i;
3802
 
#   if defined(POWERPC)
3803
 
#     if CPP_WORDSZ == 32
3804
 
        thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
3805
 
        mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
3806
 
        ppc_exception_state_t exc_state;
3807
 
#     else
3808
 
        thread_state_flavor_t flavor = PPC_EXCEPTION_STATE64;
3809
 
        mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE64_COUNT;
3810
 
        ppc_exception_state64_t exc_state;
3811
 
#     endif
3812
 
#   elif defined(I386)
3813
 
        thread_state_flavor_t flavor = i386_EXCEPTION_STATE;
3814
 
        mach_msg_type_number_t exc_state_count = i386_EXCEPTION_STATE_COUNT;
3815
 
        i386_exception_state_t exc_state;
3816
 
#   else
3817
 
#       error FIXME for non-ppc/x86 darwin
3818
 
#   endif
3819
 
 
3820
 
    
3821
 
    if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
3822
 
        #ifdef DEBUG_EXCEPTION_HANDLING
3823
 
        /* We aren't interested, pass it on to the old handler */
3824
 
        GC_printf3("Exception: 0x%x Code: 0x%x 0x%x in catch....\n",
3825
 
            exception,
3826
 
            code_count > 0 ? code[0] : -1,
3827
 
            code_count > 1 ? code[1] : -1); 
3828
 
        #endif
3829
 
        return FWD();
3830
 
    }
3831
 
 
3832
 
    r = thread_get_state(thread,flavor,
3833
 
        (natural_t*)&exc_state,&exc_state_count);
3834
 
    if(r != KERN_SUCCESS) {
3835
 
        /* The thread is supposed to be suspended while the exception handler
3836
 
           is called. This shouldn't fail. */
3837
 
        #ifdef BROKEN_EXCEPTION_HANDLING
3838
 
            GC_err_printf0("thread_get_state failed in "
3839
 
                "catch_exception_raise\n");
3840
 
            return KERN_SUCCESS;
3841
 
        #else
3842
 
            ABORT("thread_get_state failed in catch_exception_raise");
3843
 
        #endif
3844
 
    }
3845
 
    
 
3852
catch_exception_raise(mach_port_t exception_port, mach_port_t thread,
 
3853
                      mach_port_t task, exception_type_t exception,
 
3854
                      exception_data_t code, mach_msg_type_number_t code_count)
 
3855
{
 
3856
  kern_return_t r;
 
3857
  char *addr;
 
3858
  struct hblk *h;
 
3859
  unsigned int i;
 
3860
# if defined(POWERPC)
 
3861
#   if CPP_WORDSZ == 32
 
3862
      thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
 
3863
      mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
 
3864
      ppc_exception_state_t exc_state;
 
3865
#   else
 
3866
      thread_state_flavor_t flavor = PPC_EXCEPTION_STATE64;
 
3867
      mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE64_COUNT;
 
3868
      ppc_exception_state64_t exc_state;
 
3869
#   endif
 
3870
# elif defined(I386) || defined(X86_64)
 
3871
#   if CPP_WORDSZ == 32
 
3872
      thread_state_flavor_t flavor = x86_EXCEPTION_STATE32;
 
3873
      mach_msg_type_number_t exc_state_count = x86_EXCEPTION_STATE32_COUNT;
 
3874
      x86_exception_state32_t exc_state;
 
3875
#   else
 
3876
      thread_state_flavor_t flavor = x86_EXCEPTION_STATE64;
 
3877
      mach_msg_type_number_t exc_state_count = x86_EXCEPTION_STATE64_COUNT;
 
3878
      x86_exception_state64_t exc_state;
 
3879
#   endif
 
3880
# else
 
3881
#   error FIXME for non-ppc/x86 darwin
 
3882
# endif
 
3883
 
 
3884
 
 
3885
  if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
 
3886
#   ifdef DEBUG_EXCEPTION_HANDLING
 
3887
      /* We aren't interested, pass it on to the old handler */
 
3888
      GC_printf("Exception: 0x%x Code: 0x%x 0x%x in catch....\n", exception,
 
3889
                code_count > 0 ? code[0] : -1, code_count > 1 ? code[1] : -1);
 
3890
#   endif
 
3891
    return FWD();
 
3892
  }
 
3893
 
 
3894
  r = thread_get_state(thread, flavor, (natural_t*)&exc_state,
 
3895
                       &exc_state_count);
 
3896
  if(r != KERN_SUCCESS) {
 
3897
    /* The thread is supposed to be suspended while the exception handler
 
3898
       is called. This shouldn't fail. */
 
3899
#   ifdef BROKEN_EXCEPTION_HANDLING
 
3900
      GC_err_printf("thread_get_state failed in catch_exception_raise\n");
 
3901
      return KERN_SUCCESS;
 
3902
#   else
 
3903
      ABORT("thread_get_state failed in catch_exception_raise");
 
3904
#   endif
 
3905
  }
 
3906
 
3846
3907
    /* This is the address that caused the fault */
3847
 
#if defined(POWERPC)
3848
 
    addr = (char*) exc_state.dar;
3849
 
#elif defined (I386)
3850
 
    addr = (char*) exc_state.faultvaddr;
3851
 
#else
 
3908
# if defined(POWERPC)
 
3909
    addr = (char*) exc_state. THREAD_FLD(dar);
 
3910
# elif defined (I386) || defined (X86_64)
 
3911
    addr = (char*) exc_state. THREAD_FLD(faultvaddr);
 
3912
# else
3852
3913
#   error FIXME for non POWERPC/I386
3853
 
#endif
3854
 
        
 
3914
# endif
 
3915
 
3855
3916
    if((HDR(addr)) == 0) {
3856
 
        /* Ugh... just like the SIGBUS problem above, it seems we get a bogus 
3857
 
           KERN_PROTECTION_FAILURE every once and a while. We wait till we get
3858
 
           a bunch in a row before doing anything about it. If a "real" fault 
3859
 
           ever occurres it'll just keep faulting over and over and we'll hit
3860
 
           the limit pretty quickly. */
3861
 
        #ifdef BROKEN_EXCEPTION_HANDLING
3862
 
            static char *last_fault;
3863
 
            static int last_fault_count;
3864
 
            
3865
 
            if(addr != last_fault) {
3866
 
                last_fault = addr;
3867
 
                last_fault_count = 0;
3868
 
            }
3869
 
            if(++last_fault_count < 32) {
3870
 
                if(last_fault_count == 1)
3871
 
                    GC_err_printf1(
3872
 
                        "GC: WARNING: Ignoring KERN_PROTECTION_FAILURE at %p\n",
3873
 
                        addr);
3874
 
                return KERN_SUCCESS;
3875
 
            }
3876
 
            
3877
 
            GC_err_printf1("Unexpected KERN_PROTECTION_FAILURE at %p\n",addr);
3878
 
            /* Can't pass it along to the signal handler because that is
3879
 
               ignoring SIGBUS signals. We also shouldn't call ABORT here as
3880
 
               signals don't always work too well from the exception handler. */
3881
 
            GC_err_printf0("Aborting\n");
3882
 
            exit(EXIT_FAILURE);
3883
 
        #else /* BROKEN_EXCEPTION_HANDLING */
3884
 
            /* Pass it along to the next exception handler 
3885
 
               (which should call SIGBUS/SIGSEGV) */
3886
 
            return FWD();
3887
 
        #endif /* !BROKEN_EXCEPTION_HANDLING */
 
3917
      /* Ugh... just like the SIGBUS problem above, it seems we get a bogus
 
3918
         KERN_PROTECTION_FAILURE every once and a while. We wait till we get
 
3919
         a bunch in a row before doing anything about it. If a "real" fault
 
3920
         ever occurres it'll just keep faulting over and over and we'll hit
 
3921
         the limit pretty quickly. */
 
3922
#     ifdef BROKEN_EXCEPTION_HANDLING
 
3923
        static char *last_fault;
 
3924
        static int last_fault_count;
 
3925
 
 
3926
        if(addr != last_fault) {
 
3927
          last_fault = addr;
 
3928
          last_fault_count = 0;
 
3929
        }
 
3930
        if(++last_fault_count < 32) {
 
3931
          if(last_fault_count == 1)
 
3932
            WARN("Ignoring KERN_PROTECTION_FAILURE at %lx\n", (GC_word)addr);
 
3933
          return KERN_SUCCESS;
 
3934
        }
 
3935
 
 
3936
        GC_err_printf("Unexpected KERN_PROTECTION_FAILURE at %p\n",addr);
 
3937
        /* Can't pass it along to the signal handler because that is
 
3938
           ignoring SIGBUS signals. We also shouldn't call ABORT here as
 
3939
           signals don't always work too well from the exception handler. */
 
3940
        GC_err_printf("Aborting\n");
 
3941
        exit(EXIT_FAILURE);
 
3942
#     else /* BROKEN_EXCEPTION_HANDLING */
 
3943
        /* Pass it along to the next exception handler
 
3944
           (which should call SIGBUS/SIGSEGV) */
 
3945
        return FWD();
 
3946
#     endif /* !BROKEN_EXCEPTION_HANDLING */
3888
3947
    }
3889
3948
 
3890
 
    #ifdef BROKEN_EXCEPTION_HANDLING
3891
 
        /* Reset the number of consecutive SIGBUSs */
3892
 
        GC_sigbus_count = 0;
3893
 
    #endif
3894
 
    
 
3949
#   ifdef BROKEN_EXCEPTION_HANDLING
 
3950
      /* Reset the number of consecutive SIGBUSs */
 
3951
      GC_sigbus_count = 0;
 
3952
#   endif
 
3953
 
3895
3954
    if(GC_mprotect_state == GC_MP_NORMAL) { /* common case */
3896
 
        h = (struct hblk*)((word)addr & ~(GC_page_size-1));
3897
 
        UNPROTECT(h, GC_page_size);     
3898
 
        for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
3899
 
            register int index = PHT_HASH(h+i);
3900
 
            async_set_pht_entry_from_index(GC_dirty_pages, index);
3901
 
        }
 
3955
      h = (struct hblk*)((word)addr & ~(GC_page_size-1));
 
3956
      UNPROTECT(h, GC_page_size);
 
3957
      for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
 
3958
        register int index = PHT_HASH(h+i);
 
3959
        async_set_pht_entry_from_index(GC_dirty_pages, index);
 
3960
      }
3902
3961
    } else if(GC_mprotect_state == GC_MP_DISCARDING) {
3903
 
        /* Lie to the thread for now. No sense UNPROTECT()ing the memory
3904
 
           when we're just going to PROTECT() it again later. The thread
3905
 
           will just fault again once it resumes */
 
3962
      /* Lie to the thread for now. No sense UNPROTECT()ing the memory
 
3963
         when we're just going to PROTECT() it again later. The thread
 
3964
         will just fault again once it resumes */
3906
3965
    } else {
3907
 
        /* Shouldn't happen, i don't think */
3908
 
        GC_printf0("KERN_PROTECTION_FAILURE while world is stopped\n");
3909
 
        return FWD();
 
3966
      /* Shouldn't happen, i don't think */
 
3967
      GC_printf("KERN_PROTECTION_FAILURE while world is stopped\n");
 
3968
      return FWD();
3910
3969
    }
3911
3970
    return KERN_SUCCESS;
3912
3971
}
3913
3972
#undef FWD
3914
3973
 
3915
3974
/* These should never be called, but just in case...  */
3916
 
kern_return_t catch_exception_raise_state(mach_port_name_t exception_port,
3917
 
    int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
3918
 
    int flavor, thread_state_t old_state, int old_stateCnt,
3919
 
    thread_state_t new_state, int new_stateCnt)
 
3975
kern_return_t
 
3976
catch_exception_raise_state(mach_port_name_t exception_port, int exception,
 
3977
                            exception_data_t code,
 
3978
                            mach_msg_type_number_t codeCnt, int flavor,
 
3979
                            thread_state_t old_state, int old_stateCnt,
 
3980
                            thread_state_t new_state, int new_stateCnt)
3920
3981
{
3921
 
    ABORT("catch_exception_raise_state");
3922
 
    return(KERN_INVALID_ARGUMENT);
 
3982
  ABORT("catch_exception_raise_state");
 
3983
  return(KERN_INVALID_ARGUMENT);
3923
3984
}
3924
 
kern_return_t catch_exception_raise_state_identity(
3925
 
    mach_port_name_t exception_port, mach_port_t thread, mach_port_t task,
3926
 
    int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
3927
 
    int flavor, thread_state_t old_state, int old_stateCnt, 
3928
 
    thread_state_t new_state, int new_stateCnt)
 
3985
 
 
3986
kern_return_t
 
3987
catch_exception_raise_state_identity(mach_port_name_t exception_port,
 
3988
                                     mach_port_t thread, mach_port_t task,
 
3989
                                     int exception, exception_data_t code,
 
3990
                                     mach_msg_type_number_t codeCnt, int flavor,
 
3991
                                     thread_state_t old_state, int old_stateCnt,
 
3992
                                     thread_state_t new_state, int new_stateCnt)
3929
3993
{
3930
 
    ABORT("catch_exception_raise_state_identity");
3931
 
    return(KERN_INVALID_ARGUMENT);
 
3994
  ABORT("catch_exception_raise_state_identity");
 
3995
  return(KERN_INVALID_ARGUMENT);
3932
3996
}
3933
3997
 
3934
3998
 
3974
4038
        long    fr_argd[6];
3975
4039
        long    fr_argx[0];
3976
4040
     };
 
4041
#  elif defined (DRSNX)
 
4042
#    include <sys/sparc/frame.h>
 
4043
#  elif defined(OPENBSD)
 
4044
#    include <frame.h>
 
4045
#  elif defined(FREEBSD) || defined(NETBSD)
 
4046
#    include <machine/frame.h>
3977
4047
#  else
3978
 
#    if defined(SUNOS4)
3979
 
#      include <machine/frame.h>
3980
 
#    else
3981
 
#      if defined (DRSNX)
3982
 
#        include <sys/sparc/frame.h>
3983
 
#      else
3984
 
#        if defined(OPENBSD)
3985
 
#          include <frame.h>
3986
 
#        else
3987
 
#          if defined(FREEBSD) || defined(NETBSD)
3988
 
#            include <machine/frame.h>
3989
 
#          else
3990
 
#            include <sys/frame.h>
3991
 
#          endif
3992
 
#        endif
3993
 
#      endif
3994
 
#    endif
 
4048
#    include <sys/frame.h>
3995
4049
#  endif
3996
4050
#  if NARGS > 6
3997
 
        --> We only know how to to get the first 6 arguments
 
4051
#    error We only know how to to get the first 6 arguments
3998
4052
#  endif
3999
4053
#endif /* SPARC */
4000
4054
 
4009
4063
#endif /* NEED_CALLINFO */
4010
4064
 
4011
4065
#if defined(GC_HAVE_BUILTIN_BACKTRACE)
4012
 
# include <execinfo.h>
 
4066
# ifdef _MSC_VER
 
4067
#  include "private/msvc_dbg.h"
 
4068
# else
 
4069
#  include <execinfo.h>
 
4070
# endif
4013
4071
#endif
4014
4072
 
4015
4073
#ifdef SAVE_CALL_CHAIN
4027
4085
  GC_in_save_callers = FALSE;
4028
4086
#endif
4029
4087
 
4030
 
void GC_save_callers (info) 
4031
 
struct callinfo info[NFRAMES];
 
4088
void GC_save_callers (struct callinfo info[NFRAMES]) 
4032
4089
{
4033
4090
  void * tmp_info[NFRAMES + 1];
4034
4091
  int npcs, i;
4069
4126
#   define BIAS 0
4070
4127
#endif
4071
4128
 
4072
 
void GC_save_callers (info) 
4073
 
struct callinfo info[NFRAMES];
 
4129
void GC_save_callers (struct callinfo info[NFRAMES]) 
4074
4130
{
4075
4131
  struct frame *frame;
4076
4132
  struct frame *fp;
4106
4162
#ifdef NEED_CALLINFO
4107
4163
 
4108
4164
/* Print info to stderr.  We do NOT hold the allocation lock */
4109
 
void GC_print_callers (info)
4110
 
struct callinfo info[NFRAMES];
 
4165
void GC_print_callers (struct callinfo info[NFRAMES])
4111
4166
{
4112
4167
    register int i;
4113
4168
    static int reentry_count = 0;
4120
4175
    UNLOCK();
4121
4176
    
4122
4177
#   if NFRAMES == 1
4123
 
      GC_err_printf0("\tCaller at allocation:\n");
 
4178
      GC_err_printf("\tCaller at allocation:\n");
4124
4179
#   else
4125
 
      GC_err_printf0("\tCall chain at allocation:\n");
 
4180
      GC_err_printf("\tCall chain at allocation:\n");
4126
4181
#   endif
4127
4182
    for (i = 0; i < NFRAMES && !stop ; i++) {
4128
4183
        if (info[i].ci_pc == 0) break;
4130
4185
        {
4131
4186
          int j;
4132
4187
 
4133
 
          GC_err_printf0("\t\targs: ");
 
4188
          GC_err_printf("\t\targs: ");
4134
4189
          for (j = 0; j < NARGS; j++) {
4135
 
            if (j != 0) GC_err_printf0(", ");
4136
 
            GC_err_printf2("%d (0x%X)", ~(info[i].ci_arg[j]),
 
4190
            if (j != 0) GC_err_printf(", ");
 
4191
            GC_err_printf("%d (0x%X)", ~(info[i].ci_arg[j]),
4137
4192
                                        ~(info[i].ci_arg[j]));
4138
4193
          }
4139
 
          GC_err_printf0("\n");
 
4194
          GC_err_printf("\n");
4140
4195
        }
4141
4196
#       endif
4142
4197
        if (reentry_count > 1) {
4143
4198
            /* We were called during an allocation during       */
4144
4199
            /* a previous GC_print_callers call; punt.          */
4145
 
            GC_err_printf1("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
 
4200
            GC_err_printf("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
4146
4201
            continue;
4147
4202
        }
4148
4203
        {
4217
4272
                if (result_buf[result_len - 1] == '\n') --result_len;
4218
4273
                result_buf[result_len] = 0;
4219
4274
                if (result_buf[0] == '?'
4220
 
                    || result_buf[result_len-2] == ':' 
4221
 
                       && result_buf[result_len-1] == '0') {
 
4275
                    || (result_buf[result_len-2] == ':' 
 
4276
                        && result_buf[result_len-1] == '0')) {
4222
4277
                    pclose(pipe);
4223
4278
                    goto out;
4224
4279
                }
4242
4297
                out:;
4243
4298
            }
4244
4299
#         endif /* LINUX */
4245
 
          GC_err_printf1("\t\t%s\n", name);
 
4300
          GC_err_printf("\t\t%s\n", name);
4246
4301
#         if defined(GC_HAVE_BUILTIN_BACKTRACE) \
4247
4302
             && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
4248
4303
            free(sym_name);  /* May call GC_free; that's OK */
4269
4324
    return 1;
4270
4325
}
4271
4326
 
4272
 
void GC_print_address_map()
 
4327
void GC_print_address_map(void)
4273
4328
{
4274
 
    GC_err_printf0("---------- Begin address map ----------\n");
4275
 
    GC_apply_to_maps(dump_maps);
4276
 
    GC_err_printf0("---------- End address map ----------\n");
 
4329
    GC_err_printf("---------- Begin address map ----------\n");
 
4330
    dump_maps(GC_get_maps());
 
4331
    GC_err_printf("---------- End address map ----------\n");
4277
4332
}
4278
4333
 
4279
4334
#endif