#include <stdio.h>
#include <sys/mman.h>
#include <sys/param.h>
#include "mmap.h"
#include "out.h"
#include "os.h"
#define PROCMAXLEN 2048
char *Mmap_mapfile = OS_MAPFILE;
#ifdef __FreeBSD__
static const char *sscanf_os = "%p %p";
#else
static const char *sscanf_os = "%p-%p";
#endif
char *
util_map_hint_unused(void *minaddr, size_t len, size_t align)
{
LOG(3, "minaddr %p len %zu align %zu", minaddr, len, align);
ASSERT(align > 0);
FILE *fp;
if ((fp = os_fopen(Mmap_mapfile, "r")) == NULL) {
ERR("!%s", Mmap_mapfile);
return MAP_FAILED;
}
char line[PROCMAXLEN];
char *lo = NULL;
char *hi = NULL;
char *raddr = minaddr;
if (raddr == NULL)
raddr += Pagesize;
raddr = (char *)roundup((uintptr_t)raddr, align);
while (fgets(line, PROCMAXLEN, fp) != NULL) {
if (sscanf(line, sscanf_os, &lo, &hi) == 2) {
LOG(4, "%p-%p", lo, hi);
if (lo > raddr) {
if ((uintptr_t)(lo - raddr) >= len) {
LOG(4, "unused region of size %zu "
"found at %p",
lo - raddr, raddr);
break;
} else {
LOG(4, "region is too small: %zu < %zu",
lo - raddr, len);
}
}
if (hi > raddr) {
raddr = (char *)roundup((uintptr_t)hi, align);
LOG(4, "nearest aligned addr %p", raddr);
}
if (raddr == NULL) {
LOG(4, "end of address space reached");
break;
}
}
}
if ((raddr != NULL) && (UINTPTR_MAX - (uintptr_t)raddr < len)) {
LOG(4, "end of address space reached");
raddr = MAP_FAILED;
}
fclose(fp);
LOG(3, "returning %p", raddr);
return raddr;
}
char *
util_map_hint(size_t len, size_t req_align)
{
LOG(3, "len %zu req_align %zu", len, req_align);
char *hint_addr = MAP_FAILED;
size_t align = util_map_hint_align(len, req_align);
if (Mmap_no_random) {
LOG(4, "user-defined hint %p", (void *)Mmap_hint);
hint_addr = util_map_hint_unused((void *)Mmap_hint, len, align);
} else {
char *addr = mmap(NULL, len + align, PROT_READ,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (addr != MAP_FAILED) {
LOG(4, "system choice %p", addr);
hint_addr = (char *)roundup((uintptr_t)addr, align);
munmap(addr, len + align);
}
}
LOG(4, "hint %p", hint_addr);
return hint_addr;
}