/* ************************************************************************************************************************ * * Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. * ***********************************************************************************************************************/ // // Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved. // #include "elf_utils.hpp" #include "memfile.h" #include #include #include #include /* See elf_utils.hpp for descriptions about each functions */ namespace amd { #define ELF_OPEN mem_open #define ELF_READ(f, b, l) mem_read((f), (b), (unsigned int)(l)) #define ELF_WRITE mem_write #define ELF_CLOSE mem_close #define ELF_LSEEK mem_lseek /* Save the error string in _lastErrMsg. If it is built without NDEBUG, the program will terminate immediately with exit(1). */ void OclElfErr::xfail(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vsnprintf(&_lastErrMsg[0], (size_t)MAX_ERROR_MESSAGE_LENGTH, fmt, ap); va_end(ap); #ifndef NDEBUG printf("%s\n", _lastErrMsg); exit(1); #endif } namespace oclelfutils { /* Wrap malloc() with xfail(), so this returns newly-allocated memory or 0. The memory is guaranteed to be initialized to zero. */ void* xmalloc(OclElfErr& err, const size_t len) { void *retval = calloc(1, len); if (retval == NULL) { err.xfail("xmalloc failed: out of memory"); return NULL; } return retval; } /* Return file descriptor on success; return -1 on error and invoke xfail() to record the error. */ int xopen(OclElfErr& err, const char *fname, const int in_flags, const int perms) { const int retval = ELF_OPEN(fname, in_flags, perms); if (retval == -1) { err.xfail("Failed to open '%s': %s", fname, strerror(errno)); return -1; } return retval; } /* Return 0 on success; return -1 on error. */ int xclose(OclElfErr& err, const char *fname, const int fd) { int rc; while ( ((rc = :: ELF_CLOSE(fd)) == -1) && (errno == EINTR) ) { ;/* spin. */ } if (rc == -1) { err.xfail("Failed to close '%s': %s", fname, strerror(errno)); return -1; } return rc; } /* Return the file offset location on success; return -1 on error. */ off_t xlseek( OclElfErr& err, const char* fname, const int fd, const off_t offset, const int whence) { // For really big file _lseeki64/lseek64 are needed. For now, // lseek/_lseek is enough. off_t res = ELF_LSEEK(fd, offset, whence); if (res == -1) { err.xfail("Failed to seek in '%s': %s", fname, strerror(errno)); return -1; } return res; } /* Return the number of bytes that are read on success; return -1 on error. */ ssize_t xread( OclElfErr& err, const char* fname, const int fd, void* buf, const size_t buf_len ) { ssize_t rc; while (((rc = ELF_READ(fd, buf, buf_len)) == -1) && (errno == EINTR)) { ;/* spin */ } if (rc < 0) { err.xfail("Failed to read '%s': %s", fname, strerror(errno)); return -1; } return rc; } #if 0 /* Return the number of bytes that have been written on success; return -1 on error. */ ssize_t xwrite(OclElfErr& err, const char* fname, const int fd, const void* buf, const size_t len) { ssize_t rc; while (((rc = ELF_WRITE(fd, buf, len)) == -1) && (errno == EINTR)) { ;/* spin */ } if ( (rc == -1) || (rc != (ssize_t)len) ) { err.xfail("Failed to write '%s': %s", fname, strerror(errno)); return -1; } return rc; } /* Allocate a copy of (str), invoke xfail() on failure. Returns NULL on error, or address of the allocated copy */ char* xstrdup(OclElfErr& err, const char *str) { char* retval = (char*)xmalloc(err, strlen(str) + 1); if (retval == NULL) { err.xfail("xstrdup failed: cannot allocate new char string"); return NULL; } strcpy(retval, str); return retval; } /* get the length of an open file in bytes. return -1 on error. */ uint64_t xget_file_size(OclElfErr& err, const char *fname, const int fd) { struct stat statbuf; if (fstat(fd, &statbuf) == -1) { err.xfail("Failed to fstat '%s': %s", fname, strerror(errno)); return -1; } return (uint64_t) statbuf.st_size; } /* Copy file 'infd' to file 'outfd'. Return the total number of bytes copied on success; return -1 on error. */ int64_t xcopyfile( OclElfErr& err, const char* in, const int infd, const char* out, const int outfd ) { uint64_t retval = 0; ssize_t rc = 0; off_t res = xlseek(err, in, infd, 0, SEEK_SET); if (res == -1) { err.xfail("xcopyfile failed in xlseek : in %s, out %s", in, out); return -1; } uint8_t* copybuf = err._copyBuffer; if (copybuf == NULL) { copybuf = (uint8_t*)xmalloc(err, IO_BUF_SIZE); err._copyBuffer = copybuf; } while ( (rc = xread(err, in, infd, copybuf, IO_BUF_SIZE)) > 0 ) { retval += (uint64_t) rc; int ret = xwrite(err, out, outfd, copybuf, rc); if (ret == -1) { err.xfail("xcopyfile failed in xwrite: in %s, out %s", in, out); return -1; } } if (rc == -1) { err.xfail("xcopyfile failed in xread: in %s, out %s", in, out); return -1; } return retval; } /* Copy file from 'infd' to current offset in 'outfd', for 'size' bytes. Return 'size' on success; return -1 on error. */ int64_t xcopyfile_range( OclElfErr& err, const char *in, const int infd, const char *out, const int outfd, const uint64_t offset, const uint64_t size ) { uint8_t* copybuf = err._copyBuffer; if (copybuf == NULL) { copybuf = (uint8_t*)xmalloc(err, IO_BUF_SIZE); err._copyBuffer = copybuf; } ssize_t rc = xlseek(err, in, infd, (off_t) offset, SEEK_SET); if (rc == -1) { err.xfail("xcopyfile_range: xlseek() failed: %s", in); return -1; } uint64_t remaining = size; while (remaining >= IO_BUF_SIZE) { rc = xread(err, in, infd, copybuf, IO_BUF_SIZE); if ((rc == -1) || (rc != IO_BUF_SIZE)) { err.xfail("xcopyfile_range: xread() failed %s", in); return -1; } rc = xwrite(err, out, outfd, copybuf, IO_BUF_SIZE); if (rc == -1) { err.xfail("xcopyfile_range: xwrite() failed: %s", out); } remaining -= (uint64_t) IO_BUF_SIZE; } if (remaining > 0) { rc = xread(err, in, infd, copybuf, IO_BUF_SIZE); if ((rc == -1) || (rc != (ssize_t)remaining)) { err.xfail("xcopyfile_range: xread() failed %s", in); return -1; } rc = xwrite(err, out, outfd, copybuf, rc); if (rc == -1) { err.xfail("xcopyfile_range: xwrite() failed: %s", out); } } return size; } uint64_t align_to_page(const uint64_t offset) { // TODO_jugu don't use hardcoded pagesize. return (offset + ((1LL << 12) -1)) & ((uint64_t)(-(1LL << 12))); } #endif } // namespace elfutils } // namespace amd