~ubuntu-branches/debian/lenny/mono/lenny

« back to all changes in this revision

Viewing changes to libgc/os_dep.c

  • Committer: Bazaar Package Importer
  • Author(s): Debian Mono Group
  • Date: 2004-06-19 14:38:57 UTC
  • Revision ID: james.westby@ubuntu.com-20040619143857-pycck6oxgwd172zc
Tags: upstream-0.96
ImportĀ upstreamĀ versionĀ 0.96

Show diffs side-by-side

added added

removed removed

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