📄 memory.c
字号:
/* * mpatrol * A library for controlling and tracing dynamic memory allocations. * Copyright (C) 1997-2002 Graeme S. Roy <graeme.roy@analog.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307, USA. *//* * Memory handling. All memory access or handling routines that directly * access the system memory are interfaced from this module. For UNIX SVR4 * systems, a useful reference book on operating system memory management is * The Magic Garden Explained, First Edition by Goodheart and Cox (Prentice * Hall, 1994, ISBN 0-130-98138-9). */#include "memory.h"#include "stack.h"#include "utils.h"#include <stdio.h>#include <errno.h>#include <limits.h>#if TARGET == TARGET_UNIX#if SYSTEM == SYSTEM_LYNXOS#ifndef POSIX4_D14_MEMCTL#define POSIX4_D14_MEMCTL 1#endif /* POSIX4_D14_MEMCTL */#elif SYSTEM == SYSTEM_SUNOS#ifndef _POSIX_ARG_MAX#define _POSIX_ARG_MAX 4096#endif /* _POSIX_ARG_MAX */#endif /* SYSTEM */#include <setjmp.h>#include <signal.h>#if MP_SIGINFO_SUPPORT#include <siginfo.h>#endif /* MP_SIGINFO_SUPPORT */#include <fcntl.h>#include <unistd.h>#include <sys/mman.h>#if SYSTEM == SYSTEM_FREEBSD || SYSTEM == SYSTEM_NETBSD || \ SYSTEM == SYSTEM_OPENBSD#ifndef MAP_ANONYMOUS#define MAP_ANONYMOUS MAP_ANON#endif /* MAP_ANONYMOUS */#endif /* SYSTEM */#if MP_WATCH_SUPPORT#if SYSTEM == SYSTEM_SOLARIS#include <procfs.h>#else /* SYSTEM */#include <sys/procfs.h>#endif /* SYSTEM */#endif /* MP_WATCH_SUPPORT */#elif TARGET == TARGET_AMIGA#include <proto/dos.h>#include <proto/exec.h>#include <exec/memory.h>#elif TARGET == TARGET_WINDOWS#include <windows.h>#include <winbase.h>#include <process.h>#elif TARGET == TARGET_NETWARE#include <nwthread.h>#include <nks/memory.h>#endif /* TARGET */#if MP_IDENT_SUPPORT#ident "$Id: memory.c,v 1.59 2002/01/08 20:13:59 graeme Exp $"#else /* MP_IDENT_SUPPORT */static MP_CONST MP_VOLATILE char *memory_id = "$Id: memory.c,v 1.59 2002/01/08 20:13:59 graeme Exp $";#endif /* MP_IDENT_SUPPORT */#if MP_WATCH_SUPPORT/* This structure is used to simplify the building of the watch command before * it is written to the control file of the /proc filesystem. */typedef struct watchcmd{ long cmd; /* the command to set a watch point */ prwatch_t data; /* details of addresses to watch */}watchcmd;#endif /* MP_WATCH_SUPPORT */#ifdef __cplusplusextern "C"{#endif /* __cplusplus */#if MP_ARRAY_SUPPORT/* The static memory array used to implement a simulated heap. This is * most likely to be zero-initialised at the beginning of program execution, * but this should not be relied upon as the memory it contains will be reused. */static char memoryarray[MP_ARRAY_SIZE];/* The current number of bytes that have been allocated from the static memory * array. This will never be allowed to increase beyond MP_ARRAY_SIZE. */static size_t memorysize;#endif /* MP_ARRAY_SUPPORT */#if TARGET == TARGET_UNIXstatic jmp_buf memorystate;#if MP_SIGINFO_SUPPORTstatic struct sigaction membushandler;static struct sigaction memsegvhandler;#else /* MP_SIGINFO_SUPPORT */static void (*membushandler)(int);static void (*memsegvhandler)(int);#endif /* MP_SIGINFO_SUPPORT */#endif /* TARGET *//* Determine the minimum alignment for a general-purpose memory allocation * on this system. */staticsize_tminalign(void){ size_t a; long n; { /* Hopefully the largest integral type. If the compiler supports * long long, it doesn't necessarily mean that it will have a more * restrictive alignment than a long integer, but we allow that * check anyway. */#if MP_LONGLONG_SUPPORT struct { char x; long long y; } z;#else /* MP_LONGLONG_SUPPORT */ struct { char x; long y; } z;#endif /* MP_LONGLONG_SUPPORT */ n = (char *) &z.y - &z.x; } a = n; { /* Hopefully the largest floating point type. The long double * type appeared with the ANSI standard and this code is written * in ANSI C so we shouldn't need to worry about not supporting it. */ struct { char x; long double y; } z; n = (char *) &z.y - &z.x; } if (a < (unsigned long) n) a = n; { /* A generic pointer type. The assumption in this case is that * a pointer to void is the most restrictive pointer type on this * system. */ struct { char x; void *y; } z; n = (char *) &z.y - &z.x; } if (a < (unsigned long) n) a = n; return __mp_poweroftwo(a);}/* Return the system page size. */staticsize_tpagesize(void){#if TARGET == TARGET_WINDOWS SYSTEM_INFO i;#endif /* TARGET */#if TARGET == TARGET_UNIX /* This call could also be getpagesize() but it is more POSIX-conforming * to call sysconf(). Unfortunately, SunOS and the BSD systems only have * getpagesize(). */#if SYSTEM == SYSTEM_FREEBSD || SYSTEM == SYSTEM_NETBSD || \ SYSTEM == SYSTEM_OPENBSD || SYSTEM == SYSTEM_SUNOS return getpagesize();#else /* SYSTEM */ return sysconf(_SC_PAGESIZE);#endif /* SYSTEM */#elif TARGET == TARGET_AMIGA /* The Amiga has no virtual memory system (at least not supplied with * AmigaOS), so we return a fixed value here because it doesn't really * matter what the page size is. */ return 4096;#elif TARGET == TARGET_WINDOWS GetSystemInfo(&i); return i.dwPageSize;#elif TARGET == TARGET_NETWARE return NXGetPageSize();#else /* TARGET */ /* We just assume that any other operating systems have no virtual * memory support and so anything we return here is irrelevant. */ return 1024;#endif /* TARGET */}/* Determine the stack direction on this system. */staticintstackdirection(void *p){ unsigned long n; n = (unsigned long) &p; if (p == NULL) return stackdirection(&n); else if (&n < (unsigned long *) p) return -1; else return 1;}/* Return the executable file name that the program was invoked with. * Note that this function will not be reentrant if the return value is * a pointer to a local static string buffer. */staticchar *progname(void){#if TARGET == TARGET_UNIX#if SYSTEM == SYSTEM_AIX extern char **p_xargv;#elif SYSTEM == SYSTEM_HPUX extern char **__argv_value;#elif SYSTEM == SYSTEM_IRIX || SYSTEM == SYSTEM_SINIX || SYSTEM == SYSTEM_TRU64 extern char **__Argv;#elif SYSTEM == SYSTEM_UNIXWARE extern char **___Argv;#elif SYSTEM == SYSTEM_FREEBSD || SYSTEM == SYSTEM_LINUX || \ SYSTEM == SYSTEM_NETBSD || SYSTEM == SYSTEM_OPENBSD static char c[256]; ssize_t l; int f;#elif SYSTEM == SYSTEM_DGUX || SYSTEM == SYSTEM_DRSNX || \ SYSTEM == SYSTEM_DYNIX || SYSTEM == SYSTEM_LYNXOS || \ SYSTEM == SYSTEM_SOLARIS || SYSTEM == SYSTEM_SUNOS extern char **environ; char **e; char *t;#endif /* SYSTEM */#if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT && \ (ARCH == ARCH_IX86 || ARCH == ARCH_M68K || ARCH == ARCH_MIPS || \ ARCH == ARCH_POWER || ARCH == ARCH_POWERPC || ARCH == ARCH_SPARC) unsigned long *p; stackinfo s;#endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT && ARCH */#ifdef MP_PROCFS_EXENAME static char b[64];#endif /* MP_PROCFS_EXENAME */#elif TARGET == TARGET_AMIGA || TARGET == TARGET_WINDOWS static char p[256];#elif TARGET == TARGET_NETWARE char *p, *t;#endif /* TARGET */#if TARGET == TARGET_UNIX /* AIX, HP/UX, IRIX, SINIX, Tru64 and UnixWare have global variables * containing argc and argv which we can use to determine the filename * that the program was invoked with. */#if SYSTEM == SYSTEM_AIX if (p_xargv[0] != NULL) return p_xargv[0];#elif SYSTEM == SYSTEM_HPUX if (__argv_value[0] != NULL) return __argv_value[0];#elif SYSTEM == SYSTEM_IRIX || SYSTEM == SYSTEM_SINIX || SYSTEM == SYSTEM_TRU64 if (__Argv[0] != NULL) return __Argv[0];#elif SYSTEM == SYSTEM_UNIXWARE if (___Argv[0] != NULL) return ___Argv[0];#elif SYSTEM == SYSTEM_FREEBSD || SYSTEM == SYSTEM_LINUX || \ SYSTEM == SYSTEM_NETBSD || SYSTEM == SYSTEM_OPENBSD /* The BSD variants and Linux have a file in the /proc filesystem which * contains the argument vector that a process was invoked with. */ l = 0; sprintf(b, MP_PROCFS_CMDNAME, __mp_processid()); if ((f = open(b, O_RDONLY)) != -1) { if ((l = read(f, c, sizeof(c) - 1)) == -1) l = 0; close(f); } if (l > 0) { c[l] = '\0'; return c; }#elif SYSTEM == SYSTEM_DGUX || SYSTEM == SYSTEM_DRSNX || \ SYSTEM == SYSTEM_DYNIX || SYSTEM == SYSTEM_LYNXOS || \ SYSTEM == SYSTEM_SOLARIS || SYSTEM == SYSTEM_SUNOS /* We can access the argument vector from the pointer to the environment * array on all other UNIX systems. On DG/UX Intel, DRS/NX, DYNIX/ptx, * Solaris and SunOS we stop scanning backwards along the array when we * reach argc. On DG/UX M88K and LynxOS we stop scanning forwards along * the array when we reach a NULL pointer. The contents of the argument * vector then follow. */#if (SYSTEM == SYSTEM_DGUX && ARCH == ARCH_M88K) || SYSTEM == SYSTEM_LYNXOS for (e = environ; *e != NULL; e++); t = (char *) (e + 1);#else /* SYSTEM && ARCH */ for (t = NULL, e = environ - 2; *e > (char *) _POSIX_ARG_MAX; t = *e--);#endif /* SYSTEM && ARCH */ if (t != NULL) return t;#endif /* SYSTEM */#if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT && \ (ARCH == ARCH_IX86 || ARCH == ARCH_M68K || ARCH == ARCH_MIPS || \ ARCH == ARCH_POWER || ARCH == ARCH_POWERPC || ARCH == ARCH_SPARC) /* Because there is no function to return the executable filename * of a process on UNIX, we need to cheat and rely on the ABI by walking * up the process stack till we reach the startup code and then find * argv[0]. This is very OS-specific and is not my first choice for * doing this, but unfortunately it seemed to be the only way. */ __mp_newframe(&s, NULL); for (p = NULL; __mp_getframe(&s); p = (unsigned long *) s.frame); if (p != NULL) {#if ARCH == ARCH_IX86#if SYSTEM == SYSTEM_FREEBSD || SYSTEM == SYSTEM_LINUX || \ SYSTEM == SYSTEM_NETBSD || SYSTEM == SYSTEM_OPENBSD if (p = (unsigned long *) p[4]) return (char *) *p;#elif SYSTEM == SYSTEM_LYNXOS if (p = (unsigned long *) p[3]) return (char *) *p;#else /* SYSTEM */ if (p = (unsigned long *) p[3]) return (char *) p;#endif /* SYSTEM */#elif ARCH == ARCH_M68K if (p = (unsigned long *) p[3]) return (char *) *p;#elif ARCH == ARCH_MIPS if (p = (unsigned long *) p[7]) return (char *) p;#elif ARCH == ARCH_POWER || ARCH == ARCH_POWERPC#if SYSTEM == SYSTEM_AIX if (p = (unsigned long *) p[7]) return (char *) p;#else /* SYSTEM */ if (p = (unsigned long *) p[23]) return (char *) *p;#endif /* SYSTEM */#elif ARCH == ARCH_SPARC#if ENVIRON == ENVIRON_64 if (p = (unsigned long *) *(((unsigned long *) (*p + 0x7FF)) + 1))#else /* ENVIRON */ if (p = (unsigned long *) *(((unsigned long *) *p) + 1))#endif /* ENVIRON */ return (char *) *p;#endif /* ARCH */ }#endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT && ARCH */#ifdef MP_PROCFS_EXENAME /* If the /proc filesystem is supported then we can usually access the * actual executable file that contains the current program through a * special file in the current /proc entry. */ sprintf(b, MP_PROCFS_EXENAME, __mp_processid()); return b;#endif /* MP_PROCFS_EXENAME */#elif TARGET == TARGET_AMIGA if (GetProgramName(p, sizeof(p))) return p;#elif TARGET == TARGET_WINDOWS if (GetModuleFileName(NULL, p, sizeof(p))) return p;#elif TARGET == TARGET_NETWARE if (GetNLMNameFromNLMID(GetNLMID(), &p, &t) == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -