/* Copyright (C) 2021-2026 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 *) xmalloc (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 *) xmalloc (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_tData_window::get_buf_size (){ int64_t sz = MINBUFSIZE; if (sz < basesize) sz = basesize; if (sz > fsize) sz = fsize; return sz;} int64_tData_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;}
/* Copyright (C) 2021-2026 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 *) xmalloc (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 *) xmalloc (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;
}