📄 os_dep.c
字号:
/* * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. * * Permission is hereby granted to use or copy this program * for any purpose, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */# include "private/gc_priv.h"# if defined(LINUX) && !defined(POWERPC)# include <linux/version.h># if (LINUX_VERSION_CODE <= 0x10400) /* Ugly hack to get struct sigcontext_struct definition. Required */ /* for some early 1.3.X releases. Will hopefully go away soon. */ /* in some later Linux releases, asm/sigcontext.h may have to */ /* be included instead. */# define __KERNEL__# include <asm/signal.h># undef __KERNEL__# else /* Kernels prior to 2.1.1 defined struct sigcontext_struct instead of */ /* struct sigcontext. libc6 (glibc2) uses "struct sigcontext" in */ /* prototypes, so we have to include the top-level sigcontext.h to */ /* make sure the former gets defined to be the latter if appropriate. */# include <features.h># if 2 <= __GLIBC__# if 2 == __GLIBC__ && 0 == __GLIBC_MINOR__ /* glibc 2.1 no longer has sigcontext.h. But signal.h */ /* has the right declaration for glibc 2.1. */# include <sigcontext.h># endif /* 0 == __GLIBC_MINOR__ */# else /* not 2 <= __GLIBC__ */ /* libc5 doesn't have <sigcontext.h>: go directly with the kernel */ /* one. Check LINUX_VERSION_CODE to see which we should reference. */# include <asm/sigcontext.h># endif /* 2 <= __GLIBC__ */# endif# endif# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \ && !defined(MSWINCE)# include <sys/types.h># if !defined(MSWIN32) && !defined(SUNOS4)# include <unistd.h># endif# endif# include <stdio.h># if defined(MSWINCE)# define SIGSEGV 0 /* value is irrelevant */# else# include <signal.h># endif#if defined(LINUX) || defined(LINUX_STACKBOTTOM)# include <ctype.h>#endif/* Blatantly OS dependent routines, except for those that are related *//* to dynamic loading. */# if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START)# define NEED_FIND_LIMIT# endif# if !defined(STACKBOTTOM) && defined(HEURISTIC2)# define NEED_FIND_LIMIT# endif# if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR)# define NEED_FIND_LIMIT# endif# if (defined(SVR4) || defined(AUX) || defined(DGUX) \ || (defined(LINUX) && defined(SPARC))) && !defined(PCR)# define NEED_FIND_LIMIT# endif#if defined(FREEBSD) && (defined(I386) || defined(powerpc) || defined(__powerpc__))# include <machine/trap.h># if !defined(PCR)# define NEED_FIND_LIMIT# endif#endif#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) \ && !defined(NEED_FIND_LIMIT) /* Used by GC_init_netbsd_elf() below. */# define NEED_FIND_LIMIT#endif#ifdef NEED_FIND_LIMIT# include <setjmp.h>#endif#ifdef AMIGA# define GC_AMIGA_DEF# include "AmigaOS.c"# undef GC_AMIGA_DEF#endif#if defined(MSWIN32) || defined(MSWINCE)# define WIN32_LEAN_AND_MEAN# define NOSERVICE# include <windows.h>#endif#ifdef MACOS# include <Processes.h>#endif#ifdef IRIX5# include <sys/uio.h># include <malloc.h> /* for locking */#endif#if defined(USE_MMAP) || defined(USE_MUNMAP)# ifndef USE_MMAP --> USE_MUNMAP requires USE_MMAP# endif# include <sys/types.h># include <sys/mman.h># include <sys/stat.h># include <errno.h>#endif#ifdef UNIX_LIKE# include <fcntl.h># if defined(SUNOS5SIGS) && !defined(FREEBSD)# include <sys/siginfo.h># endif /* Define SETJMP and friends to be the version that restores */ /* the signal mask. */# define SETJMP(env) sigsetjmp(env, 1)# define LONGJMP(env, val) siglongjmp(env, val)# define JMP_BUF sigjmp_buf#else# define SETJMP(env) setjmp(env)# define LONGJMP(env, val) longjmp(env, val)# define JMP_BUF jmp_buf#endif#ifdef DARWIN/* for get_etext and friends */#include <mach-o/getsect.h>#endif#ifdef DJGPP /* Apparently necessary for djgpp 2.01. May cause problems with */ /* other versions. */ typedef long unsigned int caddr_t;#endif#ifdef PCR# include "il/PCR_IL.h"# include "th/PCR_ThCtl.h"# include "mm/PCR_MM.h"#endif#if !defined(NO_EXECUTE_PERMISSION)# define OPT_PROT_EXEC PROT_EXEC#else# define OPT_PROT_EXEC 0#endif#if defined(LINUX) && \ (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) || !defined(SMALL_CONFIG))/* We need to parse /proc/self/maps, either to find dynamic libraries, *//* and/or to find the register backing store base (IA64). Do it once *//* here. */#define READ read/* Repeatedly perform a read call until the buffer is filled or *//* we encounter EOF. */ssize_t GC_repeat_read(int fd, char *buf, size_t count){ ssize_t num_read = 0; ssize_t result; while (num_read < count) { result = READ(fd, buf + num_read, count - num_read); if (result < 0) return result; if (result == 0) break; num_read += result; } return num_read;}/* * Apply fn to a buffer containing the contents of /proc/self/maps. * Return the result of fn or, if we failed, 0. * We currently do nothing to /proc/self/maps other than simply read * it. This code could be simplified if we could determine its size * ahead of time. */word GC_apply_to_maps(word (*fn)(char *)){ int f; int result; size_t maps_size = 4000; /* Initial guess. */ static char init_buf[1]; static char *maps_buf = init_buf; static size_t maps_buf_sz = 1; /* Read /proc/self/maps, growing maps_buf as necessary. */ /* Note that we may not allocate conventionally, and */ /* thus can't use stdio. */ do { if (maps_size >= maps_buf_sz) { /* Grow only by powers of 2, since we leak "too small" buffers. */ while (maps_size >= maps_buf_sz) maps_buf_sz *= 2; maps_buf = GC_scratch_alloc(maps_buf_sz); if (maps_buf == 0) return 0; } f = open("/proc/self/maps", O_RDONLY); if (-1 == f) return 0; maps_size = 0; do { result = GC_repeat_read(f, maps_buf, maps_buf_sz-1); if (result <= 0) return 0; maps_size += result; } while (result == maps_buf_sz-1); close(f); } while (maps_size >= maps_buf_sz); maps_buf[maps_size] = '\0'; /* Apply fn to result. */ return fn(maps_buf);}#endif /* Need GC_apply_to_maps */#if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64))//// GC_parse_map_entry parses an entry from /proc/self/maps so we can// locate all writable data segments that belong to shared libraries.// The format of one of these entries and the fields we care about// is as follows:// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^// start end prot maj_dev//// Note that since about auguat 2003 kernels, the columns no longer have// fixed offsets on 64-bit kernels. Hence we no longer rely on fixed offsets// anywhere, which is safer anyway.///* * Assign various fields of the first line in buf_ptr to *start, *end, * *prot_buf and *maj_dev. Only *prot_buf may be set for unwritable maps. */char *GC_parse_map_entry(char *buf_ptr, word *start, word *end, char *prot_buf, unsigned int *maj_dev){ char *start_start, *end_start, *prot_start, *maj_dev_start; char *p; char *endp; if (buf_ptr == NULL || *buf_ptr == '\0') { return NULL; } p = buf_ptr; while (isspace(*p)) ++p; start_start = p; GC_ASSERT(isxdigit(*start_start)); *start = strtoul(start_start, &endp, 16); p = endp; GC_ASSERT(*p=='-'); ++p; end_start = p; GC_ASSERT(isxdigit(*end_start)); *end = strtoul(end_start, &endp, 16); p = endp; GC_ASSERT(isspace(*p)); while (isspace(*p)) ++p; prot_start = p; GC_ASSERT(*prot_start == 'r' || *prot_start == '-'); memcpy(prot_buf, prot_start, 4); prot_buf[4] = '\0'; if (prot_buf[1] == 'w') {/* we can skip the rest if it's not writable. */ /* Skip past protection field to offset field */ while (!isspace(*p)) ++p; while (isspace(*p)) ++p; GC_ASSERT(isxdigit(*p)); /* Skip past offset field, which we ignore */ while (!isspace(*p)) ++p; while (isspace(*p)) ++p; maj_dev_start = p; GC_ASSERT(isxdigit(*maj_dev_start)); *maj_dev = strtoul(maj_dev_start, NULL, 16); } while (*p && *p++ != '\n'); return p;}#endif /* Need to parse /proc/self/maps. */ #if defined(SEARCH_FOR_DATA_START) /* The I386 case can be handled without a search. The Alpha case */ /* used to be handled differently as well, but the rules changed */ /* for recent Linux versions. This seems to be the easiest way to */ /* cover all versions. */# ifdef LINUX /* Some Linux distributions arrange to define __data_start. Some */ /* define data_start as a weak symbol. The latter is technically */ /* broken, since the user program may define data_start, in which */ /* case we lose. Nonetheless, we try both, prefering __data_start. */ /* We assume gcc-compatible pragmas. */# pragma weak __data_start extern int __data_start[];# pragma weak data_start extern int data_start[];# endif /* LINUX */ extern int _end[]; ptr_t GC_data_start; void GC_init_linux_data_start() { extern ptr_t GC_find_limit();# ifdef LINUX /* Try the easy approaches first: */ if ((ptr_t)__data_start != 0) { GC_data_start = (ptr_t)(__data_start); return; } if ((ptr_t)data_start != 0) { GC_data_start = (ptr_t)(data_start); return; }# endif /* LINUX */ GC_data_start = GC_find_limit((ptr_t)(_end), FALSE); }#endif# ifdef ECOS# ifndef ECOS_GC_MEMORY_SIZE# define ECOS_GC_MEMORY_SIZE (448 * 1024)# endif /* ECOS_GC_MEMORY_SIZE */// setjmp() function, as described in ANSI para 7.6.1.1#undef SETJMP#define SETJMP( __env__ ) hal_setjmp( __env__ )// FIXME: This is a simple way of allocating memory which is// compatible with ECOS early releases. Later releases use a more// sophisticated means of allocating memory than this simple static// allocator, but this method is at least bound to work.static char memory[ECOS_GC_MEMORY_SIZE];static char *brk = memory;static void *tiny_sbrk(ptrdiff_t increment){ void *p = brk; brk += increment; if (brk > memory + sizeof memory) { brk -= increment; return NULL; } return p;}#define sbrk tiny_sbrk# endif /* ECOS */#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) ptr_t GC_data_start; void GC_init_netbsd_elf() { extern ptr_t GC_find_limit(); extern char **environ; /* This may need to be environ, without the underscore, for */ /* some versions. */ GC_data_start = GC_find_limit((ptr_t)&environ, FALSE); }#endif# ifdef OS2# include <stddef.h># if !defined(__IBMC__) && !defined(__WATCOMC__) /* e.g. EMX */struct exe_hdr { unsigned short magic_number; unsigned short padding[29]; long new_exe_offset;};#define E_MAGIC(x) (x).magic_number#define EMAGIC 0x5A4D #define E_LFANEW(x) (x).new_exe_offsetstruct e32_exe { unsigned char magic_number[2]; unsigned char byte_order; unsigned char word_order; unsigned long exe_format_level; unsigned short cpu; unsigned short os; unsigned long padding1[13]; unsigned long object_table_offset; unsigned long object_count; unsigned long padding2[31];};#define E32_MAGIC1(x) (x).magic_number[0]#define E32MAGIC1 'L'#define E32_MAGIC2(x) (x).magic_number[1]#define E32MAGIC2 'X'#define E32_BORDER(x) (x).byte_order#define E32LEBO 0#define E32_WORDER(x) (x).word_order#define E32LEWO 0#define E32_CPU(x) (x).cpu#define E32CPU286 1#define E32_OBJTAB(x) (x).object_table_offset#define E32_OBJCNT(x) (x).object_countstruct o32_obj { unsigned long size; unsigned long base; unsigned long flags; unsigned long pagemap;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -