/* 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 #include #include #include // 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; }