diff options
-rw-r--r-- | src/arch/arm/freebsd/system.cc | 24 | ||||
-rw-r--r-- | src/arch/arm/linux/system.cc | 22 | ||||
-rw-r--r-- | src/base/SConscript | 4 | ||||
-rw-r--r-- | src/base/loader/aout_object.cc | 63 | ||||
-rw-r--r-- | src/base/loader/aout_object.hh | 22 | ||||
-rw-r--r-- | src/base/loader/dtb_file.cc (renamed from src/base/loader/dtb_object.cc) | 83 | ||||
-rw-r--r-- | src/base/loader/dtb_file.hh (renamed from src/base/loader/dtb_object.hh) | 37 | ||||
-rw-r--r-- | src/base/loader/ecoff_object.cc | 75 | ||||
-rw-r--r-- | src/base/loader/ecoff_object.hh | 26 | ||||
-rw-r--r-- | src/base/loader/elf_object.cc | 416 | ||||
-rw-r--r-- | src/base/loader/elf_object.hh | 45 | ||||
-rw-r--r-- | src/base/loader/image_file.hh | 52 | ||||
-rw-r--r-- | src/base/loader/image_file_data.cc | 130 | ||||
-rw-r--r-- | src/base/loader/image_file_data.hh (renamed from src/base/loader/raw_object.cc) | 62 | ||||
-rw-r--r-- | src/base/loader/memory_image.hh | 59 | ||||
-rw-r--r-- | src/base/loader/object_file.cc | 152 | ||||
-rw-r--r-- | src/base/loader/object_file.hh | 91 | ||||
-rw-r--r-- | src/base/loader/raw_image.hh (renamed from src/base/loader/raw_object.hh) | 32 |
18 files changed, 680 insertions, 715 deletions
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<DtbObject*>(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<DtbObject*>(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 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 <sys/mman.h> #include <unistd.h> @@ -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<uint8_t *>(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 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<uint8_t *>(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<uint8_t *>(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<ElfObject *>(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<ElfObject*>(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<Addr>::max()), - ldMax(std::numeric_limits<Addr>::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<uint8_t *>( + 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<uint8_t *>(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 <set> #include <vector> #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<std::string> 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 <cstdint> +#include <string> + +#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 <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <zlib.h> + +#include <cstdio> +#include <vector> + +#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<size_t>(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 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 <cstdint> +#include <memory> +#include <string> -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<ImageFileData> 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 <algorithm> #include <functional> #include <initializer_list> #include <memory> #include <string> #include <vector> +#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<Segment> new_segs) + MemoryImage(const Segment &seg) { - for (auto &seg: new_segs) - addSegment(seg); + addSegment(seg); + } + + MemoryImage(std::initializer_list<Segment> 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<Segment> 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 <fcntl.h> -#include <sys/mman.h> -#include <sys/types.h> -#include <unistd.h> -#include <zlib.h> - -#include <cstdio> -#include <list> #include <string> #include <vector> -#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<ObjectFileFormat *> 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<size_t>(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 <limits> -#include <memory> #include <string> -#include <vector> +#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 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__ |