Browse Source
hooks and set up to enforce the requirements. However, we still allow unconditional installation until some complications are resolved.gdb-4_18-branch
3 changed files with 412 additions and 0 deletions
@ -0,0 +1,208 @@ |
|||
/* Initialization for access to a mmap'd malloc managed region.
|
|||
Copyright 1992 Free Software Foundation, Inc. |
|||
|
|||
Contributed by Fred Fish at Cygnus Support. fnf@cygnus.com |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; either version 2 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program 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 General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|||
|
|||
|
|||
#include <fcntl.h> |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include "mmalloc.h" |
|||
|
|||
#ifndef SEEK_SET |
|||
#define SEEK_SET 0 |
|||
#endif |
|||
|
|||
/* Forward declarations/prototypes for local functions */ |
|||
|
|||
static struct mdesc *reuse PARAMS ((int)); |
|||
|
|||
/* Initialize access to a mmalloc managed region.
|
|||
|
|||
If FD is a valid file descriptor for an open file then data for the |
|||
mmalloc managed region is mapped to that file, otherwise "/dev/zero" |
|||
is used and the data will not exist in any filesystem object. |
|||
|
|||
If the open file corresponding to FD is from a previous use of |
|||
mmalloc and passes some basic sanity checks to ensure that it is |
|||
compatible with the current mmalloc package, then it's data is |
|||
mapped in and is immediately accessible at the same addresses in |
|||
the current process as the process that created the file. |
|||
|
|||
If BASEADDR is not NULL, the mapping is established starting at the |
|||
specified address in the process address space. If BASEADDR is NULL, |
|||
the mmalloc package chooses a suitable address at which to start the |
|||
mapped region, which will be the value of the previous mapping if |
|||
opening an existing file which was previously built by mmalloc, or |
|||
for new files will be a value chosen by mmap. |
|||
|
|||
Specifying BASEADDR provides more control over where the regions |
|||
start and how big they can be before bumping into existing mapped |
|||
regions or future mapped regions. |
|||
|
|||
On success, returns a "malloc descriptor" which is used in subsequent |
|||
calls to other mmalloc package functions. It is explicitly "void *" |
|||
("char *" for systems that don't fully support void) so that users |
|||
of the package don't have to worry about the actual implementation |
|||
details. |
|||
|
|||
On failure returns NULL. */ |
|||
|
|||
|
|||
#if defined(HAVE_MMAP) |
|||
|
|||
PTR |
|||
mmalloc_attach (fd, baseaddr) |
|||
int fd; |
|||
PTR baseaddr; |
|||
{ |
|||
struct mdesc mtemp; |
|||
struct mdesc *mdp; |
|||
PTR mbase; |
|||
struct stat sbuf; |
|||
|
|||
/* First check to see if FD is a valid file descriptor, and if so, see
|
|||
if the file has any current contents (size > 0). If it does, then |
|||
attempt to reuse the file. If we can't reuse the file, either |
|||
because it isn't a valid mmalloc produced file, was produced by an |
|||
obsolete version, or any other reason, then we fail to attach to |
|||
this file. */ |
|||
|
|||
if (fd >= 0) |
|||
{ |
|||
if (fstat (fd, &sbuf) < 0) |
|||
{ |
|||
return (NULL); |
|||
} |
|||
else if (sbuf.st_size > 0) |
|||
{ |
|||
return ((PTR) reuse (fd)); |
|||
} |
|||
} |
|||
|
|||
/* We start off with the malloc descriptor allocated on the stack, until
|
|||
we build it up enough to call _mmalloc_mmap_morecore() to allocate the |
|||
first page of the region and copy it there. Ensure that it is zero'd and |
|||
then initialize the fields that we know values for. */ |
|||
|
|||
mdp = &mtemp; |
|||
memset ((char *) mdp, 0, sizeof (mtemp)); |
|||
strncpy (mdp -> magic, MMALLOC_MAGIC, MMALLOC_MAGIC_SIZE); |
|||
mdp -> headersize = sizeof (mtemp); |
|||
mdp -> version = MMALLOC_VERSION; |
|||
mdp -> morecore = __mmalloc_mmap_morecore; |
|||
mdp -> fd = fd; |
|||
mdp -> base = mdp -> breakval = mdp -> top = baseaddr; |
|||
|
|||
/* If we have not been passed a valid open file descriptor for the file
|
|||
to map to, then open /dev/zero and use that to map to. */ |
|||
|
|||
if (mdp -> fd < 0) |
|||
{ |
|||
if ((mdp -> fd = open ("/dev/zero", O_RDWR)) < 0) |
|||
{ |
|||
return (NULL); |
|||
} |
|||
else |
|||
{ |
|||
mdp -> flags |= MMALLOC_DEVZERO; |
|||
} |
|||
} |
|||
|
|||
/* Now try to map in the first page, copy the malloc descriptor structure
|
|||
there, and arrange to return a pointer to this new copy. If the mapping |
|||
fails, then close the file descriptor if it was opened by us, and arrange |
|||
to return a NULL. */ |
|||
|
|||
if ((mbase = mdp -> morecore (mdp, sizeof (mtemp))) != NULL) |
|||
{ |
|||
memcpy (mbase, mdp, sizeof (mtemp)); |
|||
mdp = (struct mdesc *) mbase; |
|||
} |
|||
else |
|||
{ |
|||
if (mdp -> flags & MMALLOC_DEVZERO) |
|||
{ |
|||
close (mdp -> fd); |
|||
} |
|||
mdp = NULL; |
|||
} |
|||
|
|||
return ((PTR) mdp); |
|||
} |
|||
|
|||
/* Given an valid file descriptor on an open file, test to see if that file
|
|||
is a valid mmalloc produced file, and if so, attempt to remap it into the |
|||
current process at the same address to which it was previously mapped. |
|||
|
|||
Note that we have to update the file descriptor number in the malloc- |
|||
descriptor read from the file to match the current valid one, before |
|||
trying to map the file in, and again after a successful mapping and |
|||
after we've switched over to using the mapped in malloc descriptor |
|||
rather than the temporary one on the stack. |
|||
|
|||
Also note that if the heap being remapped previously used the mmcheck() |
|||
routines, we need to update the hooks since their target functions |
|||
will have certainly moved if the executable has changed in any way. |
|||
We do this by calling mmcheck() internally. |
|||
|
|||
Returns a pointer to the malloc descriptor if successful, or NULL if |
|||
unsuccessful for some reason. */ |
|||
|
|||
static struct mdesc * |
|||
reuse (fd) |
|||
int fd; |
|||
{ |
|||
struct mdesc mtemp; |
|||
struct mdesc *mdp = NULL; |
|||
|
|||
if ((lseek (fd, 0L, SEEK_SET) == 0) && |
|||
(read (fd, (char *) &mtemp, sizeof (mtemp)) == sizeof (mtemp)) && |
|||
(mtemp.headersize == sizeof (mtemp)) && |
|||
(strcmp (mtemp.magic, MMALLOC_MAGIC) == 0) && |
|||
(mtemp.version <= MMALLOC_VERSION)) |
|||
{ |
|||
mtemp.fd = fd; |
|||
if (__mmalloc_remap_core (&mtemp) == mtemp.base) |
|||
{ |
|||
mdp = (struct mdesc *) mtemp.base; |
|||
mdp -> fd = fd; |
|||
if (mdp -> mfree_hook != NULL) |
|||
{ |
|||
(void) mmcheck ((PTR) mdp, (void (*) PARAMS ((void))) NULL); |
|||
} |
|||
} |
|||
} |
|||
return (mdp); |
|||
} |
|||
|
|||
#else /* !defined (HAVE_MMAP) */ |
|||
|
|||
/* For systems without mmap, the library still supplies an entry point
|
|||
to link to, but trying to initialize access to an mmap'd managed region |
|||
always fails. */ |
|||
|
|||
PTR |
|||
mmalloc_attach (fd, baseaddr) |
|||
int fd; |
|||
PTR baseaddr; |
|||
{ |
|||
return (NULL); |
|||
} |
|||
|
|||
#endif /* defined (HAVE_MMAP) */ |
|||
|
|||
@ -0,0 +1,196 @@ |
|||
/* Standard debugging hooks for `mmalloc'.
|
|||
Copyright 1990, 1991, 1992 Free Software Foundation |
|||
|
|||
Written May 1989 by Mike Haertel. |
|||
Heavily modified Mar 1992 by Fred Fish (fnf@cygnus.com) |
|||
|
|||
The GNU C 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. |
|||
|
|||
The GNU C 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 the GNU C Library; see the file COPYING.LIB. If |
|||
not, write to the Free Software Foundation, Inc., 675 Mass Ave, |
|||
Cambridge, MA 02139, USA. |
|||
|
|||
The author may be reached (Email) at the address mike@ai.mit.edu, |
|||
or (US mail) as Mike Haertel c/o Free Software Foundation. */ |
|||
|
|||
#include "mmalloc.h" |
|||
|
|||
/* Default function to call when something awful happens. The application
|
|||
can specify an alternate function to be called instead (and probably will |
|||
want to). */ |
|||
|
|||
extern void abort PARAMS ((void)); |
|||
|
|||
/* Arbitrary magical numbers. */ |
|||
|
|||
#define MAGICWORD 0xfedabeeb /* Magic word for active chunk */ |
|||
#define MAGICWORDFREE 0xdeadbeef /* Magic word for inactive chunk */ |
|||
#define MAGICBYTE ((char) 0xd7) |
|||
|
|||
/* Each memory allocation is bounded by a header structure and a trailer
|
|||
byte. I.E. |
|||
|
|||
<size><magicword><user's allocation><magicbyte> |
|||
|
|||
The pointer returned to the user points to the first byte in the |
|||
user's allocation area. The magic word can be tested to detect |
|||
buffer underruns and the magic byte can be tested to detect overruns. */ |
|||
|
|||
struct hdr |
|||
{ |
|||
size_t size; /* Exact size requested by user. */ |
|||
unsigned long int magic; /* Magic number to check header integrity. */ |
|||
}; |
|||
|
|||
/* Check the magicword and magicbyte, and if either is corrupted then
|
|||
call the emergency abort function specified for the heap in use. */ |
|||
|
|||
static void |
|||
checkhdr (mdp, hdr) |
|||
struct mdesc *mdp; |
|||
CONST struct hdr *hdr; |
|||
{ |
|||
if (hdr -> magic != MAGICWORD || |
|||
((char *) &hdr[1])[hdr -> size] != MAGICBYTE) |
|||
{ |
|||
(*mdp -> abortfunc)(); |
|||
} |
|||
} |
|||
|
|||
static void |
|||
mfree_check (md, ptr) |
|||
PTR md; |
|||
PTR ptr; |
|||
{ |
|||
struct hdr *hdr = ((struct hdr *) ptr) - 1; |
|||
struct mdesc *mdp; |
|||
|
|||
mdp = MD_TO_MDP (md); |
|||
checkhdr (mdp, hdr); |
|||
hdr -> magic = MAGICWORDFREE; |
|||
mdp -> mfree_hook = NULL; |
|||
mfree (md, hdr); |
|||
mdp -> mfree_hook = mfree_check; |
|||
} |
|||
|
|||
static PTR |
|||
mmalloc_check (md, size) |
|||
PTR md; |
|||
size_t size; |
|||
{ |
|||
struct hdr *hdr; |
|||
struct mdesc *mdp; |
|||
size_t nbytes; |
|||
|
|||
mdp = MD_TO_MDP (md); |
|||
mdp -> mmalloc_hook = NULL; |
|||
nbytes = sizeof (struct hdr) + size + 1; |
|||
hdr = (struct hdr *) mmalloc (md, nbytes); |
|||
mdp -> mmalloc_hook = mmalloc_check; |
|||
if (hdr != NULL) |
|||
{ |
|||
hdr -> size = size; |
|||
hdr -> magic = MAGICWORD; |
|||
hdr++; |
|||
*((char *) hdr + size) = MAGICBYTE; |
|||
} |
|||
return ((PTR) hdr); |
|||
} |
|||
|
|||
static PTR |
|||
mrealloc_check (md, ptr, size) |
|||
PTR md; |
|||
PTR ptr; |
|||
size_t size; |
|||
{ |
|||
struct hdr *hdr = ((struct hdr *) ptr) - 1; |
|||
struct mdesc *mdp; |
|||
size_t nbytes; |
|||
|
|||
mdp = MD_TO_MDP (md); |
|||
checkhdr (mdp, hdr); |
|||
mdp -> mfree_hook = NULL; |
|||
mdp -> mmalloc_hook = NULL; |
|||
mdp -> mrealloc_hook = NULL; |
|||
nbytes = sizeof (struct hdr) + size + 1; |
|||
hdr = (struct hdr *) mrealloc (md, (PTR) hdr, nbytes); |
|||
mdp -> mfree_hook = mfree_check; |
|||
mdp -> mmalloc_hook = mmalloc_check; |
|||
mdp -> mrealloc_hook = mrealloc_check; |
|||
if (hdr != NULL) |
|||
{ |
|||
hdr -> size = size; |
|||
hdr++; |
|||
*((char *) hdr + size) = MAGICBYTE; |
|||
} |
|||
return ((PTR) hdr); |
|||
} |
|||
|
|||
/* Turn on default checking for mmalloc/mrealloc/mfree, for the heap specified
|
|||
by MD. If FUNC is non-NULL, it is a pointer to the function to call |
|||
to abort whenever memory corruption is detected. By default, this is the |
|||
standard library function abort(). |
|||
|
|||
Note that we disallow installation of initial checking hooks if mmalloc |
|||
has been called at any time for this particular heap, since if any region |
|||
that is allocated prior to installation of the hooks is subsequently |
|||
reallocated or freed after installation of the hooks, it is guaranteed |
|||
to trigger a memory corruption error. We do this by checking the state |
|||
of the MMALLOC_INITIALIZED flag. |
|||
|
|||
However, we can call this function at any time after the initial call, |
|||
to update the function pointers to the checking routines and to the |
|||
user defined corruption handler routine, as long as these function pointers |
|||
have been previously extablished by the initial call. Note that we |
|||
do this automatically when remapping an previously used heap, to ensure |
|||
that the hooks get updated to the correct values, although the corruption |
|||
handler pointer gets set back to the default. The application can then |
|||
call mmcheck to use a different corruption handler if desired. |
|||
|
|||
Returns non-zero if checking is successfully enabled, zero otherwise. */ |
|||
|
|||
int |
|||
mmcheck (md, func) |
|||
PTR md; |
|||
void (*func) PARAMS ((void)); |
|||
{ |
|||
struct mdesc *mdp; |
|||
int rtnval; |
|||
|
|||
mdp = MD_TO_MDP (md); |
|||
|
|||
/* We can safely set or update the abort function at any time, regardless
|
|||
of whether or not we successfully do anything else. */ |
|||
|
|||
mdp -> abortfunc = (func != NULL ? func : abort); |
|||
|
|||
/* If we haven't yet called mmalloc the first time for this heap, or if we
|
|||
have hooks that were previously installed, then allow the hooks to be |
|||
initialized or updated. */ |
|||
|
|||
if (1 /* FIXME: Always allow installation for now. */ || |
|||
!(mdp -> flags & MMALLOC_INITIALIZED) || |
|||
(mdp -> mfree_hook != NULL)) |
|||
{ |
|||
mdp -> mfree_hook = mfree_check; |
|||
mdp -> mmalloc_hook = mmalloc_check; |
|||
mdp -> mrealloc_hook = mrealloc_check; |
|||
mdp -> flags |= MMALLOC_MMCHECK_USED; |
|||
rtnval = 1; |
|||
} |
|||
else |
|||
{ |
|||
rtnval = 0; |
|||
} |
|||
|
|||
return (rtnval); |
|||
} |
|||
Loading…
Reference in new issue