Files
rocm-systems/projects/rocprofiler-systems/source/lib/rocprof-sys-rt/src/RTheap.c
T
David Galiffi a57fd50865 Update the rocprof-sys-rt library (#786)
Derived from Dyninst_RT 13.0.0
2025-09-03 09:19:43 -04:00

227 lines
6.8 KiB
C

/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* $Id: RTheap.c,v 1.25 2006/05/03 00:31:25 jodom Exp $ */
/* RTheap.c: platform-generic heap management */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#if !defined(os_windows) /* ccw 15 may 2000 : 29 mar 2001 */
/* win does not have these header files. it appears the only
one that is used assert.h anyway.
*/
# include <errno.h>
# include <fcntl.h> /* open() */
# include <sys/stat.h> /* open() */
# include <sys/types.h>
# include <unistd.h>
#else
extern int
getpagesize();
#endif
#include <assert.h>
#include "h/unaligned_memory_access.h"
#include "src/RTcommon.h"
#include "src/RTheap.h"
typedef enum
{
HEAP_TYPE_UNKNOWN = 0x0,
HEAP_TYPE_MMAP = 0x1,
HEAP_TYPE_MALLOC = 0x2
} heapType_t;
typedef struct heap_t
{
void* ret_addr; /* address returned to mutator */
void* addr; /* actual heap address */
size_t len; /* actual heap length */
heapType_t type; /* heap allocation type */
} heap_t;
typedef struct heapList_t
{
heap_t heap;
struct heapList_t* prev;
struct heapList_t* next;
} heapList_t;
/* local variables */
static heapList_t* Heaps = NULL;
static int psize = -1;
static Address
heap_alignUp(Address addr, int align)
{
if(addr % align == 0) return addr;
return ((addr / align) + 1) * align;
}
static Address
trymmap(size_t len, Address beg, Address end, size_t inc, int fd)
{
Address addr;
void* result;
/*We have a possibly large region (beg to end) and a hopefully smaller */
/* allocation size (len). We try to map at every page in the region*/
/* until we get one that succeeds.*/
for(addr = beg; addr + len <= end; addr += inc)
{
result = map_region((void*) addr, len, fd);
if(result)
{
/* Success doesn't necessarily mean it actually mapped at the hinted
* address. Return if it's in range, else unmap and try again. */
if((Address) result >= beg && (Address) result + len <= end)
return (Address) result;
unmap_region(result, len);
}
}
return (Address) NULL;
}
void*
DYNINSTos_malloc(size_t nbytes, void* lo_addr, void* hi_addr)
{
char* heap;
size_t size = nbytes;
heapList_t* node = NULL;
/* initialize page size */
if(psize == -1) psize = getpagesize();
/* buffer size must be aligned */
if(size % DYNINSTheap_align != 0)
{
return ((void*) -1);
}
/* use malloc() if appropriate */
if(DYNINSTheap_useMalloc(lo_addr, hi_addr))
{
char* ret_heap;
int size_heap = size + DYNINSTheap_align + sizeof(heapList_t);
heap = malloc(size_heap);
if(heap == NULL)
{
#ifdef DEBUG
fprintf(stderr, "Failed to MALLOC\n");
#endif
return NULL;
}
ret_heap = (char*) heap_alignUp((Address) heap, DYNINSTheap_align);
/* malloc buffer must meet range constraints */
if(ret_heap < (char*) lo_addr || ret_heap + size - 1 > (char*) hi_addr)
{
free(heap);
#ifdef DEBUG
fprintf(stderr, "MALLOC'd area fails range constraints\n");
#endif
return NULL;
}
/* define new heap */
node = CAST_WITHOUT_ALIGNMENT_WARNING(heapList_t*, (ret_heap + size));
node->heap.ret_addr = (void*) ret_heap;
node->heap.addr = heap;
node->heap.len = size_heap;
node->heap.type = HEAP_TYPE_MALLOC;
}
else
{ /* use mmap() for allocation */
Address lo = heap_alignUp((Address) lo_addr, psize);
Address hi = (Address) hi_addr;
heap = (char*) trymmap(size + sizeof(struct heapList_t), lo, hi, psize, -1);
if(!heap) return NULL;
node = CAST_WITHOUT_ALIGNMENT_WARNING(heapList_t*, (heap + size));
/* define new heap */
node->heap.addr = heap;
node->heap.ret_addr = heap;
node->heap.len = size + sizeof(struct heapList_t);
node->heap.type = HEAP_TYPE_MMAP;
}
/* insert new heap into heap list */
node->prev = NULL;
node->next = Heaps;
if(Heaps) Heaps->prev = node;
Heaps = node;
#ifdef DEBUG
fprintf(stderr, "new heap at %lx, size %lx\n", node->heap.ret_addr, node->heap.len);
#endif
return node->heap.ret_addr;
}
int
DYNINSTos_free(void* buf)
{
int ret = 0;
heapList_t* t;
/*
fprintf(stderr, "*** DYNINSTos_free(0x%08x)\n", buf);
*/
for(t = Heaps; t != NULL; t = t->next)
{
/* lookup heap by (returned) address */
heap_t* heap = &t->heap;
if(heap->ret_addr != buf) continue;
/* remove heap from list */
if(t->next) t->next->prev = t->prev;
if(t->prev) t->prev->next = t->next;
if(Heaps == t) Heaps = t->next;
/* deallocate heap */
switch(heap->type)
{
case HEAP_TYPE_MMAP:
if(!unmap_region(heap->addr, heap->len))
{
perror("DYNINSTos_free(munmap)");
ret = -1;
}
break;
case HEAP_TYPE_MALLOC: free(heap->addr); break;
default:
fprintf(stderr, "DYNINSTos_free(): unknown inferior heap type\n");
ret = -1;
break;
}
break;
}
return ret;
}