Retro68/binutils/gprofng/src/Data_window.cc
Wolfgang Thaller f485e125c4 binutils 2.39
2022-10-27 20:45:45 +02:00

242 lines
5.6 KiB
C++

/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
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 3, 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, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h> // for close();
#include "util.h"
#include "Data_window.h"
#include "debug.h"
enum
{
MINBUFSIZE = 1 << 16,
WIN_ALIGN = 8
};
Data_window::Data_window (char *file_name)
{
Dprintf (DEBUG_DATA_WINDOW, NTXT ("Data_window:%d %s\n"), (int) __LINE__, STR (file_name));
page_size = sysconf (_SC_PAGESIZE);
need_swap_endian = false;
opened = false;
fsize = 0;
base = NULL;
woffset = 0;
wsize = 0;
basesize = 0;
fname = dbe_strdup (file_name);
mmap_on_file = false;
use_mmap = false;
#if DEBUG
if (DBE_USE_MMAP)
use_mmap = true;
#endif /* DEBUG */
fd = open64 (fname, O_RDONLY);
if (fd == -1)
return;
fsize = lseek (fd, 0, SEEK_END);
if (fsize == 0)
{
close (fd);
fd = -1;
return;
}
opened = true;
if (use_mmap)
{
if (fsize != -1)
{
base = (void*) mmap (NULL, (size_t) fsize, PROT_READ, MAP_PRIVATE, fd, 0);
close (fd);
fd = -1;
if (base == MAP_FAILED)
{
base = NULL;
use_mmap = false;
return;
}
mmap_on_file = true;
wsize = fsize;
}
}
}
void *
Data_window::bind (int64_t file_offset, int64_t minSize)
{
Span span;
span.length = fsize - file_offset;
span.offset = file_offset;
return bind (&span, minSize);
}
void *
Data_window::bind (Span *span, int64_t minSize)
{
// Do any necessary mapping to access the desired span of data
// and return a pointer to the first byte.
Dprintf (DEBUG_DATA_WINDOW, NTXT ("Data_window:bind:%d offset=%llx:%lld minSize=%lld \n"),
(int) __LINE__, (long long) span->offset, (long long) span->length, (long long) minSize);
if (minSize == 0 || span->length < minSize)
return NULL;
if (span->offset < woffset || span->offset + minSize > woffset + wsize)
{
// Remap the window
if (span->offset + minSize > fsize)
return NULL;
int myfd = fd;
if (myfd == -1)
{
if (fname)
myfd = open64 (fname, O_RDONLY, 0);
if (myfd == -1)
return NULL;
}
bool remap_failed = true;
if (use_mmap)
{
if (base)
{
munmap ((caddr_t) base, (size_t) wsize);
base = NULL;
}
woffset = span->offset & ~(page_size - 1);
wsize = page_size * ((MINBUFSIZE + page_size - 1) / page_size);
if (span->offset + minSize > woffset + wsize)
// Extend a window
wsize += page_size * ((span->offset + minSize -
woffset - wsize + page_size - 1) / page_size);
base = (void *) mmap (0, (size_t) wsize, PROT_READ, MAP_SHARED, fd, woffset);
if (base == MAP_FAILED)
{
base = NULL;
use_mmap = false;
}
remap_failed = (base == NULL);
}
if (remap_failed)
{
remap_failed = false;
woffset = span->offset & ~(WIN_ALIGN - 1);
wsize = minSize + (span->offset % WIN_ALIGN);
if (wsize < MINBUFSIZE)
wsize = MINBUFSIZE;
if (wsize > fsize)
wsize = fsize;
if (basesize < wsize)
{ // Need to realloc 'base'
free (base);
basesize = wsize;
base = (void *) malloc (basesize);
Dprintf (DEBUG_DATA_WINDOW,
NTXT ("Data_window:bind:%d realloc basesize=%llx woffset=%lld \n"),
(int) __LINE__, (long long) basesize, (long long) woffset);
if (base == NULL)
{
basesize = 0;
remap_failed = true;
}
}
if (wsize > fsize - woffset)
wsize = fsize - woffset;
off_t woff = (off_t) woffset;
if (base == NULL || woff != lseek (myfd, woff, SEEK_SET)
|| wsize != read_from_file (myfd, base, wsize))
remap_failed = true;
}
if (fd == -1)
close (myfd);
if (remap_failed)
{
woffset = 0;
wsize = 0;
return NULL;
}
}
return (void *) ((char*) base + span->offset - woffset);
}
void *
Data_window::get_data (int64_t offset, int64_t size, void *datap)
{
if (size <= 0)
return NULL;
void *buf = bind (offset, size);
if (buf == NULL)
return NULL;
if (datap == NULL && !mmap_on_file)
// Can be remmaped or reallocated. Need to make a copy
datap = (void *) malloc (size);
if (datap)
{
memcpy (datap, buf, (size_t) size);
return datap;
}
return buf;
}
Data_window::~Data_window ()
{
free (fname);
if (fd != -1)
close (fd);
if (base)
{
if (use_mmap)
munmap ((caddr_t) base, (size_t) wsize);
else
free (base);
}
}
int64_t
Data_window::get_buf_size ()
{
int64_t sz = MINBUFSIZE;
if (sz < basesize)
sz = basesize;
if (sz > fsize)
sz = fsize;
return sz;
}
int64_t
Data_window::copy_to_file (int f, int64_t offset, int64_t size)
{
long long bsz = get_buf_size ();
for (long long n = 0; n < size;)
{
long long sz = (bsz <= (size - n)) ? bsz : (size - n);
void *b = bind (offset + n, sz);
if (b == NULL)
return n;
long long len = write (f, b, sz);
if (len <= 0)
return n;
n += len;
}
return size;
}