From d856e5ce7154202f050dafdb7a638e1146081507 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 3 Oct 2019 23:42:18 -0700 Subject: [PATCH] arch,base: Restructure the object file loaders. This change creates a distinction between object files which hold executable code, and flat files which don't. The first type of files have entry points, symbols, etc., while the others are just blobs which can be shoved into memory. Rather than have those aspects but stub them out, this change creates a new base class which simply doesn't have them. This change also restructures the ELF loader since it's main function was quite long and doing multiple jobs. It stops passing the architecture and operating system to the ObjectFile constructor, since those might not be known at the very top of the constructor. Instead, those default to Uknown*, and then are filled in in the constructor body if appropriate. This removes a lot of plumbing that was hard to actually use in practice. It also introduces a mechanism to collect generic object file formats so that they can be tried one by one by the general createObjectFile function, rather than listing them all there one by one. It's unlikely that new types of object files will need to be added in a modular way without being able to modify the core loader code, but it's cleaner to have that abstraction and modularization like is already there for process loaders. Finally, to make it possible to share the code which handles zipped files for both true object files and also files which will be loaded into memory but are just blobs, that mechanism is pulled out into a new class called ImageFileData. It holds a collection of segments which are set up by the object file and may refer to regions of the original file, buffers maintained elsewhere, or even nothing to support bss-es. shared_ptr is used to make it easier to keep track of that information without having to do so explicitly or worry about deleting a buffer before everyone was done using it. Change-Id: I92890266f2ba0a703803cccad675a3ab41f2c4af Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21467 Tested-by: kokoro Reviewed-by: Brandon Potter Maintainer: Gabe Black --- src/arch/arm/freebsd/system.cc | 24 +- src/arch/arm/linux/system.cc | 22 +- src/base/SConscript | 4 +- src/base/loader/aout_object.cc | 63 +-- src/base/loader/aout_object.hh | 22 +- .../loader/{dtb_object.cc => dtb_file.cc} | 83 ++-- .../loader/{dtb_object.hh => dtb_file.hh} | 37 +- src/base/loader/ecoff_object.cc | 75 ++-- src/base/loader/ecoff_object.hh | 26 +- src/base/loader/elf_object.cc | 416 ++++++++---------- src/base/loader/elf_object.hh | 45 +- src/base/loader/image_file.hh | 52 +++ src/base/loader/image_file_data.cc | 130 ++++++ .../{raw_object.cc => image_file_data.hh} | 62 +-- src/base/loader/memory_image.hh | 59 ++- src/base/loader/object_file.cc | 152 +------ src/base/loader/object_file.hh | 91 ++-- .../loader/{raw_object.hh => raw_image.hh} | 32 +- 18 files changed, 680 insertions(+), 715 deletions(-) rename src/base/loader/{dtb_object.cc => dtb_file.cc} (71%) rename src/base/loader/{dtb_object.hh => dtb_file.hh} (67%) create mode 100644 src/base/loader/image_file.hh create mode 100644 src/base/loader/image_file_data.cc rename src/base/loader/{raw_object.cc => image_file_data.hh} (58%) rename src/base/loader/{raw_object.hh => raw_image.hh} (66%) diff --git a/src/arch/arm/freebsd/system.cc b/src/arch/arm/freebsd/system.cc index 106c8e432..3f38f2e0d 100644 --- a/src/arch/arm/freebsd/system.cc +++ b/src/arch/arm/freebsd/system.cc @@ -35,7 +35,7 @@ #include "arch/arm/isa_traits.hh" #include "arch/arm/utility.hh" #include "arch/generic/freebsd/threadinfo.hh" -#include "base/loader/dtb_object.hh" +#include "base/loader/dtb_file.hh" #include "base/loader/object_file.hh" #include "base/loader/symtab.hh" #include "cpu/base.hh" @@ -110,25 +110,15 @@ FreebsdArmSystem::initState() inform("Loading DTB file: %s at address %#x\n", params()->dtb_filename, params()->atags_addr + loadAddrOffset); - ObjectFile *dtb_file = createObjectFile(params()->dtb_filename, true); - if (!dtb_file) { - fatal("couldn't load DTB file: %s\n", params()->dtb_filename); - } - - DtbObject *_dtb_file = dynamic_cast(dtb_file); + DtbFile *dtb_file = new DtbFile(params()->dtb_filename); - if (_dtb_file) { - if (!_dtb_file->addBootCmdLine(params()->boot_osflags.c_str(), - params()->boot_osflags.size())) { - warn("couldn't append bootargs to DTB file: %s\n", - params()->dtb_filename); - } - } else { - warn("dtb_file cast failed; couldn't append bootargs " - "to DTB file: %s\n", params()->dtb_filename); + if (!dtb_file->addBootCmdLine(params()->boot_osflags.c_str(), + params()->boot_osflags.size())) { + warn("couldn't append bootargs to DTB file: %s\n", + params()->dtb_filename); } - Addr ra = _dtb_file->findReleaseAddr(); + Addr ra = dtb_file->findReleaseAddr(); if (ra) bootReleaseAddr = ra & ~ULL(0x7F); diff --git a/src/arch/arm/linux/system.cc b/src/arch/arm/linux/system.cc index 740d2e0e6..acca58af3 100644 --- a/src/arch/arm/linux/system.cc +++ b/src/arch/arm/linux/system.cc @@ -46,7 +46,7 @@ #include "arch/arm/linux/atag.hh" #include "arch/arm/utility.hh" #include "arch/generic/linux/threadinfo.hh" -#include "base/loader/dtb_object.hh" +#include "base/loader/dtb_file.hh" #include "base/loader/object_file.hh" #include "base/loader/symtab.hh" #include "cpu/base.hh" @@ -133,22 +133,12 @@ LinuxArmSystem::initState() inform("Loading DTB file: %s at address %#x\n", params()->dtb_filename, params()->atags_addr + loadAddrOffset); - ObjectFile *dtb_file = createObjectFile(params()->dtb_filename, true); - if (!dtb_file) { - fatal("couldn't load DTB file: %s\n", params()->dtb_filename); - } - - DtbObject *_dtb_file = dynamic_cast(dtb_file); + DtbFile *dtb_file = new DtbFile(params()->dtb_filename); - if (_dtb_file) { - if (!_dtb_file->addBootCmdLine(params()->boot_osflags.c_str(), - params()->boot_osflags.size())) { - warn("couldn't append bootargs to DTB file: %s\n", - params()->dtb_filename); - } - } else { - warn("dtb_file cast failed; couldn't append bootargs " - "to DTB file: %s\n", params()->dtb_filename); + if (!dtb_file->addBootCmdLine(params()->boot_osflags.c_str(), + params()->boot_osflags.size())) { + warn("couldn't append bootargs to DTB file: %s\n", + params()->dtb_filename); } dtb_file->buildImage(). diff --git a/src/base/SConscript b/src/base/SConscript index 8d170793b..b4b381bf1 100644 --- a/src/base/SConscript +++ b/src/base/SConscript @@ -74,12 +74,12 @@ GTest('trie.test', 'trie.test.cc') Source('types.cc') Source('loader/aout_object.cc') -Source('loader/dtb_object.cc') +Source('loader/dtb_file.cc') Source('loader/ecoff_object.cc') Source('loader/elf_object.cc') +Source('loader/image_file_data.cc') Source('loader/memory_image.cc') Source('loader/object_file.cc') -Source('loader/raw_object.cc') Source('loader/symtab.cc') Source('stats/group.cc') diff --git a/src/base/loader/aout_object.cc b/src/base/loader/aout_object.cc index eb633c1ce..47f3021b7 100644 --- a/src/base/loader/aout_object.cc +++ b/src/base/loader/aout_object.cc @@ -40,63 +40,44 @@ using namespace std; ObjectFile * -AoutObject::tryFile(const string &fname, size_t len, uint8_t *data) +AoutObjectFileFormat::load(ImageFileDataPtr ifd) { - if (!N_BADMAG(*(aout_exechdr *)data)) { - // right now this is only used for Alpha PAL code - return new AoutObject(fname, len, data, - ObjectFile::Alpha, ObjectFile::UnknownOpSys); - } else { + if (!N_BADMAG(*(const aout_exechdr *)ifd->data())) + return new AoutObject(ifd); + else return nullptr; - } } +namespace +{ + +AoutObjectFileFormat aoutObjectFileFormat; + +} // anonymous namespace + -AoutObject::AoutObject(const string &_filename, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys) - : ObjectFile(_filename, _len, _data, _arch, _opSys) +AoutObject::AoutObject(ImageFileDataPtr ifd) : ObjectFile(ifd) { - execHdr = (aout_exechdr *)fileData; + execHdr = (const aout_exechdr *)imageData->data(); entry = execHdr->entry; + + // Right now this is only used for Alpha PAL code. + arch = Alpha; } MemoryImage AoutObject::buildImage() const { MemoryImage image({ - { "text", N_TXTADDR(*execHdr), - fileData + N_TXTOFF(*execHdr), execHdr->tsize }, - { "data", N_DATADDR(*execHdr), - fileData + N_DATOFF(*execHdr), execHdr->dsize }, - { "bss", N_BSSADDR(*execHdr), nullptr, execHdr->bsize} + MemoryImage::Segment{ "text", N_TXTADDR(*execHdr), imageData, + N_TXTOFF(*execHdr), execHdr->tsize }, + MemoryImage::Segment{ "data", N_DATADDR(*execHdr), imageData, + N_DATOFF(*execHdr), execHdr->dsize }, + MemoryImage::Segment{ "bss", N_BSSADDR(*execHdr), execHdr->bsize} }); for (auto &seg: image.segments()) DPRINTFR(Loader, "%s\n", seg); - return image; -} - -bool -AoutObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset, - Addr addr_mask) -{ - return false; -} - -bool -AoutObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset, - Addr addr_mask) -{ - // a.out symbols not supported yet - return false; -} - -bool -AoutObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset, - Addr addr_mask) -{ - // a.out symbols not supported yet - return false; + return image; } diff --git a/src/base/loader/aout_object.hh b/src/base/loader/aout_object.hh index 4f8c86fcd..480a30c92 100644 --- a/src/base/loader/aout_object.hh +++ b/src/base/loader/aout_object.hh @@ -39,26 +39,18 @@ struct aout_exechdr; class AoutObject : public ObjectFile { protected: - aout_exechdr *execHdr; - - AoutObject(const std::string &_filename, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); + const aout_exechdr *execHdr; public: - virtual ~AoutObject() {} + AoutObject(ImageFileDataPtr ifd); MemoryImage buildImage() const override; +}; - bool loadAllSymbols(SymbolTable *symtab, Addr base=0, - Addr offset=0, Addr addr_mask = MaxAddr) override; - bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0, - Addr offset=0, Addr addr_mask=MaxAddr) override; - bool loadLocalSymbols(SymbolTable *symtab, Addr base=0, - Addr offset=0, Addr addr_mask=MaxAddr) override; - - static ObjectFile *tryFile(const std::string &fname, - size_t len, uint8_t *data); +class AoutObjectFileFormat : public ObjectFileFormat +{ + public: + ObjectFile *load(ImageFileDataPtr data) override; }; #endif // __AOUT_OBJECT_HH__ diff --git a/src/base/loader/dtb_object.cc b/src/base/loader/dtb_file.cc similarity index 71% rename from src/base/loader/dtb_object.cc rename to src/base/loader/dtb_file.cc index f5b206a74..aaae0a254 100644 --- a/src/base/loader/dtb_object.cc +++ b/src/base/loader/dtb_file.cc @@ -28,7 +28,7 @@ * Authors: Anthony Gutierrez */ -#include "base/loader/dtb_object.hh" +#include "base/loader/dtb_file.hh" #include #include @@ -39,48 +39,34 @@ #include "libfdt.h" #include "sim/byteswap.hh" -ObjectFile * -DtbObject::tryFile(const std::string &fname, size_t len, uint8_t *data) -{ - // Check if this is a FDT file by looking for magic number - if (fdt_magic((void*)data) == FDT_MAGIC) { - return new DtbObject(fname, len, data, - ObjectFile::UnknownArch, ObjectFile::UnknownOpSys); - } else { - return NULL; - } -} - -DtbObject::DtbObject(const std::string &_filename, size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys) - : ObjectFile(_filename, _len, _data, _arch, _opSys) +DtbFile::DtbFile(const std::string &filename) : + ImageFile(ImageFileDataPtr(new ImageFileData(filename))) { + panic_if(fdt_magic((const void *)imageData->data()) != FDT_MAGIC, + "File %s doesn't seem to be a DTB.\n", filename); fileDataMmapped = true; + fileData = const_cast(imageData->data()); + length = imageData->len(); } -DtbObject::~DtbObject() +DtbFile::~DtbFile() { // Make sure to clean up memory properly depending // on how buffer was allocated. - if (fileData && !fileDataMmapped) { + if (!fileDataMmapped) delete [] fileData; - fileData = NULL; - } else if (fileData) { - munmap(fileData, len); - fileData = NULL; - } } bool -DtbObject::addBootCmdLine(const char* _args, size_t len) +DtbFile::addBootCmdLine(const char *_args, size_t len) { - const char* root_path = "/"; - const char* node_name = "chosen"; - const char* full_path_node_name = "/chosen"; - const char* property_name = "bootargs"; + const char *root_path = "/"; + const char *node_name = "chosen"; + const char *full_path_node_name = "/chosen"; + const char *property_name = "bootargs"; // Make a new buffer that has extra space to add nodes/properties - int newLen = 2 * this->len; + int newLen = 2 * length; uint8_t *fdt_buf_w_space = new uint8_t[newLen]; // Copy and unpack flattened device tree into new buffer int ret = fdt_open_into((void *)fileData, (void *)fdt_buf_w_space, newLen); @@ -130,23 +116,24 @@ DtbObject::addBootCmdLine(const char* _args, size_t len) } // clean up old buffer and set to new fdt blob - munmap(fileData, this->len); + if (!fileDataMmapped) + delete [] fileData; fileData = fdt_buf_w_space; fileDataMmapped = false; - this->len = newLen; + length = newLen; return true; } Addr -DtbObject::findReleaseAddr() +DtbFile::findReleaseAddr() { void *fd = (void *)fileData; int offset = fdt_path_offset(fd, "/cpus/cpu@0"); int len; - const void* temp = fdt_getprop(fd, offset, "cpu-release-addr", &len); + const void *temp = fdt_getprop(fd, offset, "cpu-release-addr", &len); Addr rel_addr = 0; if (len > 3) @@ -160,30 +147,10 @@ DtbObject::findReleaseAddr() } MemoryImage -DtbObject::buildImage() const -{ - return {{"data", 0, fileData, len}}; -} - -bool -DtbObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset, - Addr addr_mask) -{ - return false; -} - -bool -DtbObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset, - Addr addr_mask) -{ - // nothing to do here - return false; -} - -bool -DtbObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset, - Addr addr_mask) +DtbFile::buildImage() const { - // nothing to do here - return false; + if (fileDataMmapped) + return {{ "data", imageData }}; + else + return {{ "data", 0, fileData, length }}; } diff --git a/src/base/loader/dtb_object.hh b/src/base/loader/dtb_file.hh similarity index 67% rename from src/base/loader/dtb_object.hh rename to src/base/loader/dtb_file.hh index 1284025ff..53bc13e29 100644 --- a/src/base/loader/dtb_object.hh +++ b/src/base/loader/dtb_file.hh @@ -28,29 +28,29 @@ * Authors: Anthony Gutierrez */ -#ifndef __DTB_OBJECT_HH__ -#define __DTB_OBJECT_HH__ +#ifndef __BASE_LOADER_DTB_FILE_HH__ +#define __BASE_LOADER_DTB_FILE_HH__ -#include "base/loader/object_file.hh" +#include "base/loader/image_file.hh" /** @file - * This implements an object file format to support loading + * This implements an image file format to support loading * and modifying flattened device tree blobs for use with * current and future ARM Linux kernels. */ -class DtbObject : public ObjectFile +class DtbFile : public ImageFile { protected: - DtbObject(const std::string &_filename, size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); - /** Bool marking if this dtb file has replaced the original * read in DTB file with a new modified buffer */ bool fileDataMmapped; + uint8_t *fileData = nullptr; + size_t length = 0; public: - virtual ~DtbObject(); + DtbFile(const std::string &name); + ~DtbFile(); /** Adds the passed in Command Line options for the kernel * to the proper location in the device tree. @@ -67,23 +67,6 @@ class DtbObject : public ObjectFile Addr findReleaseAddr(); MemoryImage buildImage() const override; - - bool loadAllSymbols(SymbolTable *symtab, Addr base=0, - Addr offset=0, Addr addrMask=MaxAddr) override; - bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0, - Addr offset=0, Addr addrMask=MaxAddr) override; - bool loadLocalSymbols(SymbolTable *symtab, Addr base=0, - Addr offset=0, Addr addrMask=MaxAddr) override; - - /** Static function that tries to load file as a - * flattened device tree blob. - * @param fname path to file - * @param len length of file - * @param data mmap'ed data buffer containing file contents - * @return ObjectFile representing closest match of file type - */ - static ObjectFile *tryFile(const std::string &fname, - size_t len, uint8_t *data); }; -#endif //__DTB_OBJECT_HH__ +#endif //__BASE_LOADER_DTB_FILE_HH__ diff --git a/src/base/loader/ecoff_object.cc b/src/base/loader/ecoff_object.cc index cecc68dc1..2f534311a 100644 --- a/src/base/loader/ecoff_object.cc +++ b/src/base/loader/ecoff_object.cc @@ -50,39 +50,43 @@ using namespace std; ObjectFile * -EcoffObject::tryFile(const string &fname, size_t len, uint8_t *data) +EcoffObjectFormat::load(ImageFileDataPtr ifd) { - if (((ecoff_filehdr *)data)->f_magic == ECOFF_MAGIC_ALPHA) { - // it's Alpha ECOFF - return new EcoffObject(fname, len, data, - ObjectFile::Alpha, ObjectFile::Tru64); - } - else { - return NULL; - } + if (((const ecoff_filehdr *)ifd->data())->f_magic == ECOFF_MAGIC_ALPHA) + return new EcoffObject(ifd); + else + return nullptr; } +namespace +{ + +EcoffObjectFormat ecoffObjectFormat; + +} // anonymous namespace + -EcoffObject::EcoffObject(const string &_filename, size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys) - : ObjectFile(_filename, _len, _data, _arch, _opSys) +EcoffObject::EcoffObject(ImageFileDataPtr ifd) : ObjectFile(ifd) { - execHdr = (ecoff_exechdr *)fileData; + execHdr = (const ecoff_exechdr *)imageData->data(); fileHdr = &(execHdr->f); aoutHdr = &(execHdr->a); entry = aoutHdr->entry; + // it's Alpha ECOFF + arch = Alpha; + opSys = Tru64; } MemoryImage EcoffObject::buildImage() const { MemoryImage image({ - { "text", aoutHdr->text_start, - fileData + ECOFF_TXTOFF(execHdr), aoutHdr->tsize }, - { "data", aoutHdr->data_start, - fileData + ECOFF_DATOFF(execHdr), aoutHdr->dsize }, - { "bss", aoutHdr->bss_start, nullptr, aoutHdr->bsize } + { "text", aoutHdr->text_start, imageData, + ECOFF_TXTOFF(execHdr), aoutHdr->tsize }, + { "data", aoutHdr->data_start, imageData, + ECOFF_DATOFF(execHdr), aoutHdr->dsize }, + { "bss", aoutHdr->bss_start, aoutHdr->bsize } }); for (auto &seg: image.segments()) @@ -108,21 +112,24 @@ EcoffObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset, return false; if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) { - warn("loadGlobalSymbols: wrong magic on %s\n", filename); + warn("loadGlobalSymbols: wrong magic on %s\n", imageData->filename()); return false; } - ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr); + auto *syms = (const ecoff_symhdr *)(imageData->data() + fileHdr->f_symptr); if (syms->magic != magicSym2) { - warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename); + warn("loadGlobalSymbols: bad symbol header magic on %s\n", + imageData->filename()); return false; } - ecoff_extsym *ext_syms = (ecoff_extsym *)(fileData + syms->cbExtOffset); + auto *ext_syms = (const ecoff_extsym *)( + imageData->data() + syms->cbExtOffset); - char *ext_strings = (char *)(fileData + syms->cbSsExtOffset); + auto *ext_strings = + (const char *)(imageData->data() + syms->cbSsExtOffset); for (int i = 0; i < syms->iextMax; i++) { - ecoff_sym *entry = &(ext_syms[i].asym); + const ecoff_sym *entry = &(ext_syms[i].asym); if (entry->iss != -1) symtab->insert(entry->value, ext_strings + entry->iss); } @@ -138,23 +145,25 @@ EcoffObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset, return false; if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) { - warn("loadGlobalSymbols: wrong magic on %s\n", filename); + warn("loadGlobalSymbols: wrong magic on %s\n", imageData->filename()); return false; } - ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr); + auto *syms = (const ecoff_symhdr *)(imageData->data() + fileHdr->f_symptr); if (syms->magic != magicSym2) { - warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename); + warn("loadGlobalSymbols: bad symbol header magic on %s\n", + imageData->filename()); return false; } - ecoff_sym *local_syms = (ecoff_sym *)(fileData + syms->cbSymOffset); - char *local_strings = (char *)(fileData + syms->cbSsOffset); - ecoff_fdr *fdesc = (ecoff_fdr *)(fileData + syms->cbFdOffset); + auto *local_syms = + (const ecoff_sym *)(imageData->data() + syms->cbSymOffset); + auto *local_strings = (const char *)(imageData->data() + syms->cbSsOffset); + auto *fdesc = (const ecoff_fdr *)(imageData->data() + syms->cbFdOffset); for (int i = 0; i < syms->ifdMax; i++) { - ecoff_sym *entry = (ecoff_sym *)(local_syms + fdesc[i].isymBase); - char *strings = (char *)(local_strings + fdesc[i].issBase); + auto *entry = (const ecoff_sym *)(local_syms + fdesc[i].isymBase); + auto *strings = (const char *)(local_strings + fdesc[i].issBase); for (int j = 0; j < fdesc[i].csym; j++) { if (entry[j].st == stGlobal || entry[j].st == stProc) if (entry[j].iss != -1) @@ -163,7 +172,7 @@ EcoffObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset, } for (int i = 0; i < syms->isymMax; i++) { - ecoff_sym *entry = &(local_syms[i]); + const ecoff_sym *entry = &(local_syms[i]); if (entry->st == stProc) symtab->insert(entry->value, local_strings + entry->iss); } diff --git a/src/base/loader/ecoff_object.hh b/src/base/loader/ecoff_object.hh index 94811158e..9e6c53373 100644 --- a/src/base/loader/ecoff_object.hh +++ b/src/base/loader/ecoff_object.hh @@ -28,8 +28,8 @@ * Authors: Steve Reinhardt */ -#ifndef __ECOFF_OBJECT_HH__ -#define __ECOFF_OBJECT_HH__ +#ifndef __BASE_LOADER_ECOFF_OBJECT_HH__ +#define __BASE_LOADER_ECOFF_OBJECT_HH__ #include "base/loader/object_file.hh" @@ -38,18 +38,21 @@ struct ecoff_exechdr; struct ecoff_filehdr; struct ecoff_aouthdr; +class EcoffObjectFormat : public ObjectFileFormat +{ + public: + ObjectFile *load(ImageFileDataPtr data) override; +}; + class EcoffObject : public ObjectFile { protected: - ecoff_exechdr *execHdr; - ecoff_filehdr *fileHdr; - ecoff_aouthdr *aoutHdr; - - EcoffObject(const std::string &_filename, size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); + const ecoff_exechdr *execHdr; + const ecoff_filehdr *fileHdr; + const ecoff_aouthdr *aoutHdr; public: - virtual ~EcoffObject() {} + EcoffObject(ImageFileDataPtr ifd); MemoryImage buildImage() const override; @@ -59,9 +62,6 @@ class EcoffObject : public ObjectFile Addr offset=0, Addr addr_mask=MaxAddr) override; bool loadLocalSymbols(SymbolTable *symtab, Addr base=0, Addr offset=0, Addr addr_mask=MaxAddr) override; - - static ObjectFile *tryFile(const std::string &fname, - size_t len, uint8_t *data); }; -#endif // __ECOFF_OBJECT_HH__ +#endif // __BASE_LOADER_ECOFF_OBJECT_HH__ diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc index 7a83c0bd2..e35c28bd0 100644 --- a/src/base/loader/elf_object.cc +++ b/src/base/loader/elf_object.cc @@ -61,310 +61,254 @@ #include "sim/byteswap.hh" ObjectFile * -ElfObject::tryFile(const std::string &fname, size_t len, uint8_t *data, - bool skip_interp_check) +ElfObjectFormat::load(ImageFileDataPtr ifd) { // check that header matches library version if (elf_version(EV_CURRENT) == EV_NONE) panic("wrong elf version number!"); + ObjectFile *object = nullptr; + // get a pointer to elf structure // Check that we actually have a elf file - Elf *elf = elf_memory((char*)data, len); + Elf *elf = + elf_memory((char *)const_cast(ifd->data()), ifd->len()); assert(elf); GElf_Ehdr ehdr; - if (gelf_getehdr(elf, &ehdr) == 0) { + if (gelf_getehdr(elf, &ehdr) == 0) DPRINTFR(Loader, "Not ELF\n"); - elf_end(elf); - return NULL; + else + object = new ElfObject(ifd); + + elf_end(elf); + + return object; +} + +namespace +{ + +ElfObjectFormat elfObjectFormat; + +} // anonymous namespace + +ElfObject::ElfObject(ImageFileDataPtr ifd) : ObjectFile(ifd) +{ + // get a pointer to elf structure + elf = elf_memory((char *)const_cast(imageData->data()), + imageData->len()); + assert(elf); + gelf_getehdr(elf, &ehdr); + + determineArch(); + determineOpSys(); + + entry = ehdr.e_entry; + _programHeaderCount = ehdr.e_phnum; + _programHeaderSize = ehdr.e_phentsize; + + // Go through all the segments in the program and record them. + for (int i = 0; i < ehdr.e_phnum; ++i) { + GElf_Phdr phdr; + if (gelf_getphdr(elf, i, &phdr) == 0) { + panic("gelf_getphdr failed for segment %d.", i); + } + + if (phdr.p_type == PT_LOAD) + handleLoadableSegment(phdr); + if (phdr.p_type == PT_INTERP) { + // Make sure the interpreter is an valid ELF file. + char *interp_path = (char *)imageData->data() + phdr.p_offset; + ObjectFile *obj = createObjectFile(interp_path); + interpreter = dynamic_cast(obj); + assert(interpreter != nullptr); + } } + // should have found at least one loadable segment + warn_if(image.segments().empty(), + "No loadable segments in '%s'. ELF file corrupted?\n", + imageData->filename()); + + for (auto &seg: image.segments()) + DPRINTFR(Loader, "%s\n", seg); + + // We will actually read the sections when we need to load them +} + +void +ElfObject::determineArch() +{ + auto &emach = ehdr.e_machine; + auto &eclass = ehdr.e_ident[EI_CLASS]; + auto &edata = ehdr.e_ident[EI_DATA]; + // Detect the architecture - Arch arch = UnknownArch; - if (ehdr.e_machine == EM_SPARC64 || - (ehdr.e_machine == EM_SPARC && - ehdr.e_ident[EI_CLASS] == ELFCLASS64) || - ehdr.e_machine == EM_SPARCV9) { + if (emach == EM_SPARC64 || (emach == EM_SPARC && eclass == ELFCLASS64) || + emach == EM_SPARCV9) { arch = SPARC64; - } else if (ehdr.e_machine == EM_SPARC32PLUS || - (ehdr.e_machine == EM_SPARC && - ehdr.e_ident[EI_CLASS] == ELFCLASS32)) { + } else if (emach == EM_SPARC32PLUS || + (emach == EM_SPARC && eclass == ELFCLASS32)) { arch = SPARC32; - } else if (ehdr.e_machine == EM_MIPS && - ehdr.e_ident[EI_CLASS] == ELFCLASS32) { + } else if (emach == EM_MIPS && eclass == ELFCLASS32) { arch = Mips; - if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) { + if (edata != ELFDATA2LSB) { fatal("The binary you're trying to load is compiled for big " "endian MIPS. gem5\nonly supports little endian MIPS. " "Please recompile your binary.\n"); } - } else if (ehdr.e_machine == EM_X86_64 && - ehdr.e_ident[EI_CLASS] == ELFCLASS64) { + } else if (emach == EM_X86_64 && eclass == ELFCLASS64) { arch = X86_64; - } else if (ehdr.e_machine == EM_386 && - ehdr.e_ident[EI_CLASS] == ELFCLASS32) { + } else if (emach == EM_386 && eclass == ELFCLASS32) { arch = I386; - } else if (ehdr.e_machine == EM_ARM && - ehdr.e_ident[EI_CLASS] == ELFCLASS32) { + } else if (emach == EM_ARM && eclass == ELFCLASS32) { arch = bits(ehdr.e_entry, 0) ? Thumb : Arm; - } else if (ehdr.e_machine == EM_AARCH64 && - ehdr.e_ident[EI_CLASS] == ELFCLASS64) { + } else if (emach == EM_AARCH64 && eclass == ELFCLASS64) { arch = Arm64; - } else if (ehdr.e_machine == EM_RISCV) { - arch = (ehdr.e_ident[EI_CLASS] == ELFCLASS64) ? Riscv64 : Riscv32; - } else if (ehdr.e_machine == EM_PPC && - ehdr.e_ident[EI_CLASS] == ELFCLASS32) { + } else if (emach == EM_RISCV) { + arch = (eclass == ELFCLASS64) ? Riscv64 : Riscv32; + } else if (emach == EM_PPC && eclass == ELFCLASS32) { arch = Power; - if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { + if (edata != ELFDATA2MSB) { fatal("The binary you're trying to load is compiled for " "little endian Power.\ngem5 only supports big " "endian Power. Please recompile your binary.\n"); } - } else if (ehdr.e_machine == EM_PPC64) { + } else if (emach == EM_PPC64) { fatal("The binary you're trying to load is compiled for 64-bit " "Power. M5\n only supports 32-bit Power. Please " "recompile your binary.\n"); - } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { + } else if (eclass == ELFCLASS64) { // Since we don't know how to check for alpha right now, we'll // just assume if it wasn't something else and it's 64 bit, that's // what it must be. arch = Alpha; } else { - warn("Unknown architecture: %d\n", ehdr.e_machine); - arch = UnknownArch; + warn("Unknown architecture: %d\n", emach); } +} +void +ElfObject::determineOpSys() +{ // Detect the operating system - OpSys op_sys; switch (ehdr.e_ident[EI_OSABI]) { case ELFOSABI_LINUX: - op_sys = Linux; - break; + opSys = Linux; + return; case ELFOSABI_SOLARIS: - op_sys = Solaris; - break; + opSys = Solaris; + return; case ELFOSABI_TRU64: - op_sys = Tru64; - break; + opSys = Tru64; + return; case ELFOSABI_ARM: - op_sys = LinuxArmOABI; - break; + opSys = LinuxArmOABI; + return; case ELFOSABI_FREEBSD: - op_sys = FreeBSD; - break; + opSys = FreeBSD; + return; default: - op_sys = UnknownOpSys; + opSys = UnknownOpSys; } - // Take a look at the .note.ABI section. - // It can let us know what's what. - if (op_sys == UnknownOpSys) { - int sec_idx = 1; - - // Get the first section - Elf_Scn *section = elf_getscn(elf, sec_idx); - - // While there are no more sections - while (section && op_sys == UnknownOpSys) { - GElf_Shdr shdr; - gelf_getshdr(section, &shdr); - - char *e_str = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); - if (shdr.sh_type == SHT_NOTE && - !strcmp(".note.ABI-tag", e_str)) { - // we have found a ABI note section - // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, - // 2 == solaris, 3 == freebsd - Elf_Data *raw_data = elf_rawdata(section, NULL); - assert(raw_data && raw_data->d_buf); - - uint32_t raw_abi = ((uint32_t*)raw_data->d_buf)[4]; - bool is_le = ehdr.e_ident[EI_DATA] == ELFDATA2LSB; - uint32_t os_abi = is_le ? htole(raw_abi) : htobe(raw_abi); - - switch (os_abi) { - case 0: - op_sys = Linux; - break; - case 1: - fatal("gem5 does not support the HURD ABI.\n"); - case 2: - op_sys = Solaris; - break; - case 3: - op_sys = FreeBSD; - break; - } - } // if section found - - if (!strcmp(".SUNW_version", e_str) || - !strcmp(".stab.index", e_str)) - op_sys = Solaris; - - section = elf_getscn(elf, ++sec_idx); - } // while sections - } + Elf_Scn *section = elf_getscn(elf, 1); + for (int sec_idx = 1; section; section = elf_getscn(elf, ++sec_idx)) { + GElf_Shdr shdr; + gelf_getshdr(section, &shdr); - ElfObject * result = new ElfObject(fname, len, data, arch, op_sys); - - // The number of headers in the file - result->_programHeaderCount = ehdr.e_phnum; - // Record the size of each entry - result->_programHeaderSize = ehdr.e_phentsize; - result->_programHeaderTable = 0; - if (result->_programHeaderCount) { // If there is a program header table - // Figure out the virtual address of the header table in the - // final memory image. We use the program headers themselves - // to translate from a file offset to the address in the image. - GElf_Phdr phdr; - uint64_t e_phoff = ehdr.e_phoff; - - for (int i = 0; i < result->_programHeaderCount; i++) { - gelf_getphdr(elf, i, &phdr); - // Check if we've found the segment with the headers in it - if (phdr.p_offset <= e_phoff && - phdr.p_offset + phdr.p_filesz > e_phoff) { - result->_programHeaderTable = - phdr.p_paddr + (e_phoff - phdr.p_offset); - break; + char *e_str = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); + if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", e_str)) { + // we have found a ABI note section + // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, + // 2 == solaris, 3 == freebsd + Elf_Data *raw_data = elf_rawdata(section, nullptr); + assert(raw_data && raw_data->d_buf); + + uint32_t raw_abi = ((uint32_t *)raw_data->d_buf)[4]; + bool is_le = ehdr.e_ident[EI_DATA] == ELFDATA2LSB; + uint32_t os_abi = is_le ? htole(raw_abi) : htobe(raw_abi); + + switch (os_abi) { + case 0: + opSys = Linux; + return; + case 1: + fatal("gem5 does not support the HURD ABI.\n"); + case 2: + opSys = Solaris; + return; + case 3: + opSys = FreeBSD; + return; } } - } - if (!skip_interp_check) { - for (int i = 0; i < ehdr.e_phnum; i++) { - GElf_Phdr phdr; - M5_VAR_USED void *check_p = gelf_getphdr(elf, i, &phdr); - assert(check_p != nullptr); - - if (phdr.p_type != PT_INTERP) - continue; - - char *interp_path = (char*)data + phdr.p_offset; - int fd = open(interp_path, O_RDONLY); - if (fd == -1) - fatal("Unable to open dynamic executable's interpreter.\n"); - - struct stat sb; - M5_VAR_USED int check_i = fstat(fd, &sb); - assert(check_i == 0); - - void *mm = mmap(nullptr, sb.st_size, PROT_READ, - MAP_PRIVATE, fd, 0); - assert(mm != MAP_FAILED); - close(fd); - - uint8_t *interp_image = (uint8_t*)mm; - ObjectFile *obj = tryFile(interp_path, sb.st_size, - interp_image, true); - assert(obj != nullptr); - result->interpreter = dynamic_cast(obj); - assert(result->interpreter != nullptr); - break; + if (!strcmp(".SUNW_version", e_str) || !strcmp(".stab.index", e_str)) { + opSys = Solaris; + return; } } - - elf_end(elf); - return result; } -ElfObject::ElfObject(const std::string &_filename, size_t _len, - uint8_t *_data, Arch _arch, OpSys _op_sys) - : ObjectFile(_filename, _len, _data, _arch, _op_sys), - _programHeaderTable(0), _programHeaderSize(0), _programHeaderCount(0), - interpreter(nullptr), ldBias(0), relocate(true), - ldMin(std::numeric_limits::max()), - ldMax(std::numeric_limits::min()) +void +ElfObject::handleLoadableSegment(GElf_Phdr phdr) { - // check that header matches library version - if (elf_version(EV_CURRENT) == EV_NONE) - panic("wrong elf version number!"); + Addr mem_start = phdr.p_vaddr; + Addr mem_end = mem_start + phdr.p_memsz; + Addr file_start = phdr.p_offset; + Addr file_end = file_start + phdr.p_filesz; - // get a pointer to elf structure - Elf *elf = elf_memory((char*)fileData,len); - assert(elf); + std::string name; - // Check that we actually have a elf file - GElf_Ehdr ehdr; - if (gelf_getehdr(elf, &ehdr) ==0) { - panic("Not ELF, shouldn't be here"); - } - - entry = ehdr.e_entry; - - int sec_idx = 1; - - // Go through all the segments in the program, record them, and scrape - // out information about the text, data, and bss areas needed by other - // code. - for (int i = 0; i < ehdr.e_phnum; ++i) { - GElf_Phdr phdr; - if (gelf_getphdr(elf, i, &phdr) == 0) { - panic("gelf_getphdr failed for segment %d.", i); - } - - // for now we don't care about non-loadable segments - if (phdr.p_type != PT_LOAD) - continue; - - ldMin = std::min(ldMin, phdr.p_vaddr); - ldMax = std::max(ldMax, phdr.p_vaddr + phdr.p_memsz); - - std::string name; - - // Get the first section - Elf_Scn *section = elf_getscn(elf, sec_idx); - - // Name segments after the sections they contain. - while (section) { - GElf_Shdr shdr; - gelf_getshdr(section, &shdr); - char *sec_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); - - if (!sec_name) { - Elf_Error errorNum = (Elf_Error)elf_errno(); - if (errorNum != ELF_E_NONE) { - const char *errorMessage = elf_errmsg(errorNum); - fatal("Error from libelf: %s.\n", errorMessage); - } - } + // Name segments after the sections they contain. + Elf_Scn *section = elf_getscn(elf, 1); + for (int sec_idx = 1; section; section = elf_getscn(elf, ++sec_idx)) { + GElf_Shdr shdr; + gelf_getshdr(section, &shdr); + char *sec_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); - if (shdr.sh_addr >= ldMin && shdr.sh_addr < ldMax) { - if (name != "") - name += ","; - name += sec_name; + if (!sec_name) { + Elf_Error errorNum = (Elf_Error)elf_errno(); + if (errorNum != ELF_E_NONE) { + const char *errorMessage = elf_errmsg(errorNum); + fatal("Error from libelf: %s.\n", errorMessage); } - - section = elf_getscn(elf, ++sec_idx); } - image.addSegment(name, phdr.p_paddr, fileData + phdr.p_offset, - phdr.p_filesz); - Addr uninitialized = phdr.p_memsz - phdr.p_filesz; - if (uninitialized) { - // There may be parts of a segment which aren't included in the - // file. In those cases, we need to create a new segment with no - // data to take up the extra space. This should be zeroed when - // loaded into memory. - image.addSegment(name + "(uninitialized)", - phdr.p_paddr + phdr.p_filesz, nullptr, uninitialized); + if (shdr.sh_addr >= mem_start && shdr.sh_addr < mem_end) { + if (name != "") + name += ","; + name += sec_name; } } - // should have found at least one loadable segment - warn_if(image.segments().empty(), - "No loadable segments in '%s'. ELF file corrupted?\n", filename); + image.addSegment({ name, phdr.p_paddr, imageData, + phdr.p_offset, phdr.p_filesz }); + Addr uninitialized = phdr.p_memsz - phdr.p_filesz; + if (uninitialized) { + // There may be parts of a segment which aren't included in the + // file. In those cases, we need to create a new segment with no + // data to take up the extra space. This should be zeroed when + // loaded into memory. + image.addSegment({ name + "(uninitialized)", + phdr.p_paddr + phdr.p_filesz, uninitialized }); + } - for (auto &seg: image.segments()) - DPRINTFR(Loader, "%s\n", seg); + // If there is a program header table, figure out the virtual + // address of the header table in the final memory image. We use + // the program headers themselves to translate from a file offset + // to the address in the image. + if (file_start <= ehdr.e_phoff && file_end > ehdr.e_phoff) + _programHeaderTable = mem_start + (ehdr.e_phoff - file_start); +} +ElfObject::~ElfObject() +{ elf_end(elf); - - // We will actually read the sections when we need to load them } - bool ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask, Addr base, Addr offset) @@ -377,7 +321,8 @@ ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask, panic("wrong elf version number!"); // get a pointer to elf structure - Elf *elf = elf_memory((char*)fileData,len); + Elf *elf = elf_memory((char *)const_cast( + imageData->data()), imageData->len()); assert(elf != NULL); // Get the first section @@ -401,7 +346,8 @@ ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask, GElf_Sym sym; gelf_getsym(data, i, &sym); if (GELF_ST_BIND(sym.st_info) == binding) { - char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name); + char *sym_name = + elf_strptr(elf, shdr.sh_link, sym.st_name); if (sym_name && sym_name[0] != '$') { Addr value = sym.st_value - base + offset; if (symtab->insert(value & mask, sym_name)) { @@ -473,7 +419,9 @@ ElfObject::getSections() panic("wrong elf version number!"); // get a pointer to elf structure - Elf *elf = elf_memory((char*)fileData,len); + Elf *elf = + elf_memory((char *)const_cast(imageData->data()), + imageData->len()); assert(elf != NULL); // Check that we actually have a elf file diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh index 0b8c79b47..42edc7438 100644 --- a/src/base/loader/elf_object.hh +++ b/src/base/loader/elf_object.hh @@ -40,56 +40,68 @@ * Authors: Steve Reinhardt */ -#ifndef __ELF_OBJECT_HH__ -#define __ELF_OBJECT_HH__ +#ifndef __BASE_LOADER_ELF_OBJECT_HH__ +#define __BASE_LOADER_ELF_OBJECT_HH__ #include #include #include "base/loader/object_file.hh" +#include "gelf.h" + +class ElfObjectFormat : public ObjectFileFormat +{ + public: + ObjectFile *load(ImageFileDataPtr data) override; +}; class ElfObject : public ObjectFile { protected: + Elf *elf; + GElf_Ehdr ehdr; + + void determineArch(); + void determineOpSys(); + void handleLoadableSegment(GElf_Phdr phdr); + // These values are provided to a linux process by the kernel, so we // need to keep them around. - Addr _programHeaderTable; - uint16_t _programHeaderSize; - uint16_t _programHeaderCount; + Addr _programHeaderTable = 0; + uint16_t _programHeaderSize = 0; + uint16_t _programHeaderCount = 0; std::set sectionNames; - ElfObject *interpreter; + ElfObject *interpreter = nullptr; // An interpreter load bias is the location in the process address space // where the interpreter is chosen to reside. Typically, this is carved // out of the top of the mmap reserve section. - Addr ldBias; + Addr ldBias = 0; // The interpreter is typically a relocatable shared library and will // have a default value of zero which means that it does not care where // it is placed. However, the loader can be compiled and linked so that // it does care and needs a specific entry point. - bool relocate; + bool relocate = true; // The ldMin and ldMax fields are required to know how large of an // area is required to map the interpreter. - Addr ldMin; - Addr ldMax; + Addr ldMin = MaxAddr; + Addr ldMax = MaxAddr; /// Helper functions for loadGlobalSymbols() and loadLocalSymbols(). bool loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask, Addr base, Addr offset); - ElfObject(const std::string &_filename, size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); - void getSections(); bool sectionExists(std::string sec); MemoryImage image; public: - virtual ~ElfObject() {} + ElfObject(ImageFileDataPtr ifd); + ~ElfObject(); MemoryImage buildImage() const override { return image; } @@ -111,12 +123,9 @@ class ElfObject : public ObjectFile bool hasTLS() override { return sectionExists(".tbss"); } - static ObjectFile *tryFile(const std::string &fname, - size_t len, uint8_t *data, - bool skip_interp_check = false); Addr programHeaderTable() {return _programHeaderTable;} uint16_t programHeaderSize() {return _programHeaderSize;} uint16_t programHeaderCount() {return _programHeaderCount;} }; -#endif // __ELF_OBJECT_HH__ +#endif // __BASE_LOADER_ELF_OBJECT_HH__ diff --git a/src/base/loader/image_file.hh b/src/base/loader/image_file.hh new file mode 100644 index 000000000..79d31a433 --- /dev/null +++ b/src/base/loader/image_file.hh @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2002-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + * Steve Reinhardt + */ + +#ifndef __BASE_LOADER_IMAGE_FILE_HH__ +#define __BASE_LOADER_IMAGE_FILE_HH__ + +#include +#include + +#include "base/loader/image_file_data.hh" +#include "base/loader/memory_image.hh" + +class ImageFile +{ + protected: + ImageFileDataPtr imageData; + ImageFile(ImageFileDataPtr data) : imageData(data) {} + virtual ~ImageFile() {} + + public: + virtual MemoryImage buildImage() const = 0; +}; + +#endif // __BASE_LOADER_IMAGE_FILE_HH__ diff --git a/src/base/loader/image_file_data.cc b/src/base/loader/image_file_data.cc new file mode 100644 index 000000000..12cba77e0 --- /dev/null +++ b/src/base/loader/image_file_data.cc @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2002-2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + * Steve Reinhardt + */ + +#include "base/loader/image_file_data.hh" + +#include +#include +#include +#include +#include + +#include +#include + +#include "base/logging.hh" + +static bool +hasGzipMagic(int fd) +{ + uint8_t buf[2] = {0}; + size_t sz = pread(fd, buf, 2, 0); + panic_if(sz != 2, "Couldn't read magic bytes from object file"); + return ((buf[0] == 0x1f) && (buf[1] == 0x8b)); +} + +static int +doGzipLoad(int fd) +{ + const size_t blk_sz = 4096; + + gzFile fdz = gzdopen(fd, "rb"); + if (!fdz) { + return -1; + } + + size_t tmp_len = strlen(P_tmpdir); + char *tmpnam = (char*) malloc(tmp_len + 20); + strcpy(tmpnam, P_tmpdir); + strcpy(tmpnam+tmp_len, "/gem5-gz-obj-XXXXXX"); // 19 chars + fd = mkstemp(tmpnam); // repurposing fd variable for output + if (fd < 0) { + free(tmpnam); + gzclose(fdz); + return fd; + } + + if (unlink(tmpnam) != 0) + warn("couldn't remove temporary file %s\n", tmpnam); + + free(tmpnam); + + auto buf = new uint8_t[blk_sz]; + int r; // size of (r)emaining uncopied data in (buf)fer + while ((r = gzread(fdz, buf, blk_sz)) > 0) { + auto p = buf; // pointer into buffer + while (r > 0) { + auto sz = write(fd, p, r); + assert(sz <= r); + r -= sz; + p += sz; + } + } + delete[] buf; + gzclose(fdz); + if (r < 0) { // error + close(fd); + return -1; + } + assert(r == 0); // finished successfully + return fd; // return fd to decompressed temporary file for mmap()'ing +} + +ImageFileData::ImageFileData(const std::string &fname) +{ + _filename = fname; + + // Open the file. + int fd = open(fname.c_str(), O_RDONLY); + panic_if(fd < 0, "Failed to open file %s.\n", fname); + + // Decompress GZ files. + if (hasGzipMagic(fd)) { + fd = doGzipLoad(fd); + panic_if(fd < 0, "Failed to unzip file %s.\n", fname); + } + + // Find the length of the file by seeking to the end. + off_t off = lseek(fd, 0, SEEK_END); + fatal_if(off < 0, "Failed to determine size of file %s.\n", fname); + _len = static_cast(off); + + // Mmap the whole shebang. + _data = (uint8_t *)mmap(NULL, _len, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + + panic_if(_data == MAP_FAILED, "Failed to mmap file %s.\n", fname); +} + +ImageFileData::~ImageFileData() +{ + munmap((void *)_data, _len); +} diff --git a/src/base/loader/raw_object.cc b/src/base/loader/image_file_data.hh similarity index 58% rename from src/base/loader/raw_object.cc rename to src/base/loader/image_file_data.hh index 35ed485c4..8810ae473 100644 --- a/src/base/loader/raw_object.cc +++ b/src/base/loader/image_file_data.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2002-2004 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,51 +25,33 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Steve Reinhardt + * Authors: Nathan Binkert + * Steve Reinhardt */ -#include "base/loader/raw_object.hh" +#ifndef __BASE_LOADER_IMAGE_FILE_DATA_HH__ +#define __BASE_LOADER_IMAGE_FILE_DATA_HH__ -#include "base/loader/symtab.hh" -#include "base/trace.hh" -#include "debug/Loader.hh" +#include +#include +#include -ObjectFile * -RawObject::tryFile(const std::string &fname, size_t len, uint8_t *data) +class ImageFileData { - return new RawObject(fname, len, data, ObjectFile::UnknownArch, - ObjectFile::UnknownOpSys); -} + private: + std::string _filename; + uint8_t *_data; + size_t _len; -RawObject::RawObject(const std::string &_filename, size_t _len, - uint8_t *_data, Arch _arch, OpSys _opSys) - : ObjectFile(_filename, _len, _data, _arch, _opSys) -{ -} - -MemoryImage -RawObject::buildImage() const -{ - return {{ "data", 0, fileData, len }}; -} + public: + const std::string &filename() const { return _filename; } + uint8_t const *data() const { return _data; } + size_t len() const { return _len; } -bool -RawObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset, - Addr addr_mask) -{ - return true; -} + ImageFileData(const std::string &f_name); + virtual ~ImageFileData(); +}; -bool -RawObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset, - Addr addr_mask) -{ - return true; -} +typedef std::shared_ptr ImageFileDataPtr; -bool -RawObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset, - Addr addr_mask) -{ - return true; -} +#endif // __BASE_LOADER_IMAGE_FILE_DATA_HH__ diff --git a/src/base/loader/memory_image.hh b/src/base/loader/memory_image.hh index 866e9560c..a10daba6c 100644 --- a/src/base/loader/memory_image.hh +++ b/src/base/loader/memory_image.hh @@ -32,37 +32,63 @@ #ifndef __BASE_LOADER_MEMORY_IMAGE_HH__ #define __BASE_LOADER_MEMORY_IMAGE_HH__ +#include #include #include #include #include #include +#include "base/loader/image_file_data.hh" #include "base/logging.hh" #include "base/types.hh" class PortProxy; -class Process; -class ProcessParams; -class SymbolTable; class MemoryImage { public: struct Segment { + Segment(const std::string &_name, Addr _base, + const uint8_t *_data, size_t _size) : + name(_name), base(_base), data(_data), size(_size) + {} + + Segment(const std::string &_name, Addr _base, size_t _size) : + name(_name), base(_base), size(_size) + {} + + Segment(const std::string &_name, Addr _base, + const ImageFileDataPtr &_ifd, Addr offset, size_t _size) : + ifd(_ifd), name(_name), base(_base), size(_size) + { + panic_if(offset + size > ifd->len(), + "Segment outside the bounds of the image data"); + data = ifd->data() + offset; + } + + Segment(const std::string &_name, const ImageFileDataPtr &_ifd) : + Segment(_name, 0, _ifd, 0, _ifd->len()) + {} + + ImageFileDataPtr ifd; std::string name; - Addr base; - uint8_t *data; - size_t size; + Addr base = 0; + const uint8_t *data = nullptr; + size_t size = 0; }; MemoryImage() {} - MemoryImage(std::initializer_list new_segs) + MemoryImage(const Segment &seg) { - for (auto &seg: new_segs) - addSegment(seg); + addSegment(seg); + } + + MemoryImage(std::initializer_list segs) + { + addSegments(segs); } private: @@ -83,9 +109,10 @@ class MemoryImage } void - addSegment(std::string name, Addr base, uint8_t *data, size_t size) + addSegments(std::initializer_list segs) { - _segments.push_back(Segment({name, base, data, size})); + for (auto &seg: segs) + addSegment(seg); } bool write(const PortProxy &proxy) const; @@ -104,11 +131,8 @@ class MemoryImage maxAddr() const { Addr max = 0; - for (auto &seg: _segments) { - Addr end = seg.base + seg.size; - if (end > max) - max = end; - } + for (auto &seg: _segments) + max = std::max(max, seg.base + seg.size); return max; } @@ -117,8 +141,7 @@ class MemoryImage { Addr min = MaxAddr; for (auto &seg: _segments) - if (seg.base < min) - min = seg.base; + min = std::min(min, seg.base); return min; } diff --git a/src/base/loader/object_file.cc b/src/base/loader/object_file.cc index afecd21e3..b7e05428c 100644 --- a/src/base/loader/object_file.cc +++ b/src/base/loader/object_file.cc @@ -31,44 +31,16 @@ #include "base/loader/object_file.hh" -#include -#include -#include -#include -#include - -#include -#include #include #include -#include "base/cprintf.hh" -#include "base/loader/aout_object.hh" -#include "base/loader/dtb_object.hh" -#include "base/loader/ecoff_object.hh" -#include "base/loader/elf_object.hh" -#include "base/loader/raw_object.hh" +#include "base/loader/raw_image.hh" #include "base/loader/symtab.hh" #include "mem/port_proxy.hh" using namespace std; -ObjectFile::ObjectFile(const string &_filename, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _op_sys) - : filename(_filename), fileData(_data), len(_len), - arch(_arch), opSys(_op_sys), entry(0) -{} - - -ObjectFile::~ObjectFile() -{ - if (fileData) { - ::munmap((char*)fileData, len); - fileData = NULL; - } -} - +ObjectFile::ObjectFile(ImageFileDataPtr ifd) : ImageFile(ifd) {} namespace { @@ -101,117 +73,37 @@ ObjectFile::tryLoaders(ProcessParams *params, ObjectFile *obj_file) return nullptr; } -static bool -hasGzipMagic(int fd) -{ - uint8_t buf[2] = {0}; - size_t sz = pread(fd, buf, 2, 0); - panic_if(sz != 2, "Couldn't read magic bytes from object file"); - return ((buf[0] == 0x1f) && (buf[1] == 0x8b)); -} +namespace { -static int -doGzipLoad(int fd) -{ - const size_t blk_sz = 4096; +typedef std::vector ObjectFileFormatList; - gzFile fdz = gzdopen(fd, "rb"); - if (!fdz) { - return -1; - } +ObjectFileFormatList & +object_file_formats() +{ + static ObjectFileFormatList formats; + return formats; +} - size_t tmp_len = strlen(P_tmpdir); - char *tmpnam = (char*) malloc(tmp_len + 20); - strcpy(tmpnam, P_tmpdir); - strcpy(tmpnam+tmp_len, "/gem5-gz-obj-XXXXXX"); // 19 chars - fd = mkstemp(tmpnam); // repurposing fd variable for output - if (fd < 0) { - free(tmpnam); - gzclose(fdz); - return fd; - } +} // anonymous namespace - if (unlink(tmpnam) != 0) - warn("couldn't remove temporary file %s\n", tmpnam); - - free(tmpnam); - - auto buf = new uint8_t[blk_sz]; - int r; // size of (r)emaining uncopied data in (buf)fer - while ((r = gzread(fdz, buf, blk_sz)) > 0) { - auto p = buf; // pointer into buffer - while (r > 0) { - auto sz = write(fd, p, r); - assert(sz <= r); - r -= sz; - p += sz; - } - } - delete[] buf; - gzclose(fdz); - if (r < 0) { // error - close(fd); - return -1; - } - assert(r == 0); // finished successfully - return fd; // return fd to decompressed temporary file for mmap()'ing +ObjectFileFormat::ObjectFileFormat() +{ + object_file_formats().emplace_back(this); } ObjectFile * -createObjectFile(const string &fname, bool raw) +createObjectFile(const std::string &fname, bool raw) { - // open the file - int fd = open(fname.c_str(), O_RDONLY); - if (fd < 0) { - return NULL; - } - - // decompress GZ files - if (hasGzipMagic(fd)) { - fd = doGzipLoad(fd); - if (fd < 0) { - return NULL; - } - } - - // find the length of the file by seeking to the end - off_t off = lseek(fd, 0, SEEK_END); - fatal_if(off < 0, - "Failed to determine size of object file %s\n", fname); - auto len = static_cast(off); - - // mmap the whole shebang - uint8_t *file_data = (uint8_t *)mmap(NULL, len, PROT_READ, MAP_SHARED, - fd, 0); - close(fd); - - if (file_data == MAP_FAILED) { - return NULL; - } + ImageFileDataPtr ifd(new ImageFileData(fname)); - ObjectFile *file_obj = NULL; - - // figure out what we have here - if ((file_obj = ElfObject::tryFile(fname, len, file_data)) != NULL) { - return file_obj; - } - - if ((file_obj = EcoffObject::tryFile(fname, len, file_data)) != NULL) { - return file_obj; - } - - if ((file_obj = AoutObject::tryFile(fname, len, file_data)) != NULL) { - return file_obj; - } - - if ((file_obj = DtbObject::tryFile(fname, len, file_data)) != NULL) { - return file_obj; + for (auto &format: object_file_formats()) { + ObjectFile *file_obj = format->load(ifd); + if (file_obj) + return file_obj; } if (raw) - return RawObject::tryFile(fname, len, file_data); + return new RawImage(ifd); - // don't know what it is - munmap((char*)file_data, len); - return NULL; + return nullptr; } diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh index 669afeb11..da35db148 100644 --- a/src/base/loader/object_file.hh +++ b/src/base/loader/object_file.hh @@ -29,24 +29,22 @@ * Steve Reinhardt */ -#ifndef __OBJECT_FILE_HH__ -#define __OBJECT_FILE_HH__ +#ifndef __BASE_LOADER_OBJECT_FILE_HH__ +#define __BASE_LOADER_OBJECT_FILE_HH__ -#include -#include #include -#include +#include "base/loader/image_file.hh" +#include "base/loader/image_file_data.hh" #include "base/loader/memory_image.hh" #include "base/logging.hh" #include "base/types.hh" -class PortProxy; class Process; class ProcessParams; class SymbolTable; -class ObjectFile +class ObjectFile : public ImageFile { public: @@ -76,37 +74,51 @@ class ObjectFile }; protected: - const std::string filename; - uint8_t *fileData; - size_t len; + Arch arch = UnknownArch; + OpSys opSys = UnknownOpSys; - Arch arch; - OpSys opSys; - - ObjectFile(const std::string &_filename, size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); + ObjectFile(ImageFileDataPtr ifd); public: - virtual ~ObjectFile(); - - virtual MemoryImage buildImage() const = 0; + virtual ~ObjectFile() {}; - virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0, - Addr offset=0, Addr mask=MaxAddr) = 0; - virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0, - Addr offset=0, Addr mask=MaxAddr) = 0; - virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base=0, - Addr offset=0, Addr mask=MaxAddr) = 0; - virtual bool loadWeakSymbols(SymbolTable *symtab, Addr base=0, - Addr offset=0, Addr mask=MaxAddr) - { return false; } + virtual bool + loadAllSymbols(SymbolTable *symtab, Addr base=0, + Addr offset=0, Addr mask=MaxAddr) + { + return true; + }; + virtual bool + loadGlobalSymbols(SymbolTable *symtab, Addr base=0, + Addr offset=0, Addr mask=MaxAddr) + { + return true; + } + virtual bool + loadLocalSymbols(SymbolTable *symtab, Addr base=0, + Addr offset=0, Addr mask=MaxAddr) + { + return true; + } + virtual bool + loadWeakSymbols(SymbolTable *symtab, Addr base=0, + Addr offset=0, Addr mask=MaxAddr) + { + return true; + } virtual ObjectFile *getInterpreter() const { return nullptr; } virtual bool relocatable() const { return false; } - virtual Addr mapSize() const - { panic("mapSize() should only be called on relocatable objects\n"); } - virtual void updateBias(Addr bias_addr) - { panic("updateBias() should only be called on relocatable objects\n"); } + virtual Addr + mapSize() const + { + panic("mapSize() should only be called on relocatable objects\n"); + } + virtual void + updateBias(Addr bias_addr) + { + panic("updateBias() should only be called on relocatable objects\n"); + } virtual Addr bias() const { return 0; } virtual bool hasTLS() { return false; } @@ -115,7 +127,7 @@ class ObjectFile OpSys getOpSys() const { return opSys; } protected: - Addr entry; + Addr entry = 0; public: Addr entryPoint() const { return entry; } @@ -153,7 +165,18 @@ class ObjectFile static Process *tryLoaders(ProcessParams *params, ObjectFile *obj_file); }; -ObjectFile *createObjectFile(const std::string &fname, bool raw = false); +class ObjectFileFormat +{ + protected: + ObjectFileFormat(); + + public: + ObjectFileFormat(const ObjectFileFormat &) = delete; + void operator=(const ObjectFileFormat &) = delete; + + virtual ObjectFile *load(ImageFileDataPtr data) = 0; +}; +ObjectFile *createObjectFile(const std::string &fname, bool raw=false); -#endif // __OBJECT_FILE_HH__ +#endif // __BASE_LOADER_OBJECT_FILE_HH__ diff --git a/src/base/loader/raw_object.hh b/src/base/loader/raw_image.hh similarity index 66% rename from src/base/loader/raw_object.hh rename to src/base/loader/raw_image.hh index 6dc54c7aa..aae82a36f 100644 --- a/src/base/loader/raw_object.hh +++ b/src/base/loader/raw_image.hh @@ -28,33 +28,27 @@ * Authors: Ali Saidi */ -#ifndef __BASE_LOADER_RAW_OBJECT_HH__ -#define __BASE_LOADER_RAW_OBJECT_HH__ +#ifndef __BASE_LOADER_RAW_IMAGE_HH__ +#define __BASE_LOADER_RAW_IMAGE_HH__ #include "base/loader/object_file.hh" -class RawObject: public ObjectFile +class RawImage: public ObjectFile { - protected: - RawObject(const std::string &_filename, size_t _len, - uint8_t *_data, Arch _arch, OpSys _opSys); - public: - virtual ~RawObject() {} - - MemoryImage buildImage() const override; + RawImage(ImageFileDataPtr ifd) : ObjectFile(ifd) {} - bool loadAllSymbols(SymbolTable *symtab, Addr base=0, - Addr offset=0, Addr addr_mask=MaxAddr) override; - bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0, - Addr offset=0, Addr addr_mask=MaxAddr) override; - bool loadLocalSymbols(SymbolTable *symtab, Addr base=0, - Addr offset=0, Addr addr_mask=MaxAddr) override; + RawImage(const std::string &filename) : + RawImage(ImageFileDataPtr(new ImageFileData(filename))) + {} - static ObjectFile *tryFile(const std::string &fname, size_t len, - uint8_t *data); + MemoryImage + buildImage() const override + { + return {{ "data", imageData }}; + } }; -#endif // __BASE_LOADER_RAW_OBJECT_HH__ +#endif // __BASE_LOADER_RAW_IMAGE_HH__ -- 2.30.2