12SN/A/*
21762SN/A * Copyright (c) 2002-2004 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Nathan Binkert
292665Ssaidi@eecs.umich.edu *          Steve Reinhardt
302SN/A */
312SN/A
3211793Sbrandon.potter@amd.com#include "base/loader/object_file.hh"
3311793Sbrandon.potter@amd.com
3411793Sbrandon.potter@amd.com#include <fcntl.h>
358229Snate@binkert.org#include <sys/mman.h>
368229Snate@binkert.org#include <sys/types.h>
378229Snate@binkert.org#include <unistd.h>
3811354SCurtis.Dunham@arm.com#include <zlib.h>
398229Snate@binkert.org
408229Snate@binkert.org#include <cstdio>
412SN/A#include <list>
422SN/A#include <string>
4313982Sgabeblack@google.com#include <vector>
442SN/A
4511793Sbrandon.potter@amd.com#include "base/cprintf.hh"
468229Snate@binkert.org#include "base/loader/aout_object.hh"
479538Satgutier@umich.edu#include "base/loader/dtb_object.hh"
488229Snate@binkert.org#include "base/loader/ecoff_object.hh"
498229Snate@binkert.org#include "base/loader/elf_object.hh"
508229Snate@binkert.org#include "base/loader/raw_object.hh"
518229Snate@binkert.org#include "base/loader/symtab.hh"
528706Sandreas.hansson@arm.com#include "mem/port_proxy.hh"
532420SN/A
542SN/Ausing namespace std;
552SN/A
5610880SCurtis.Dunham@arm.comObjectFile::ObjectFile(const string &_filename,
57360SN/A                       size_t _len, uint8_t *_data,
5811391Sbrandon.potter@amd.com                       Arch _arch, OpSys _op_sys)
5910880SCurtis.Dunham@arm.com    : filename(_filename), fileData(_data), len(_len),
6011391Sbrandon.potter@amd.com      arch(_arch), opSys(_op_sys), entry(0), globalPtr(0),
6110422Sandreas.hansson@arm.com      text{0, nullptr, 0}, data{0, nullptr, 0}, bss{0, nullptr, 0}
6212SN/A{
6312SN/A}
642SN/A
652SN/A
662SN/AObjectFile::~ObjectFile()
672SN/A{
6811391Sbrandon.potter@amd.com    if (fileData) {
6911391Sbrandon.potter@amd.com        ::munmap((char*)fileData, len);
7011391Sbrandon.potter@amd.com        fileData = NULL;
7111391Sbrandon.potter@amd.com    }
7212SN/A}
732SN/A
742SN/A
752420SN/Abool
7614017Sbrandon.potter@amd.comObjectFile::loadSection(Section *sec, const PortProxy& mem_proxy,
7714017Sbrandon.potter@amd.com                        Addr addr_mask, Addr offset)
782420SN/A{
792420SN/A    if (sec->size != 0) {
8011391Sbrandon.potter@amd.com        Addr addr = (sec->baseAddr & addr_mask) + offset;
812420SN/A        if (sec->fileImage) {
8211391Sbrandon.potter@amd.com            mem_proxy.writeBlob(addr, sec->fileImage, sec->size);
832420SN/A        }
842420SN/A        else {
852420SN/A            // no image: must be bss
8611391Sbrandon.potter@amd.com            mem_proxy.memsetBlob(addr, 0, sec->size);
872420SN/A        }
882420SN/A    }
892420SN/A    return true;
902420SN/A}
912420SN/A
922420SN/A
932420SN/Abool
9414017Sbrandon.potter@amd.comObjectFile::loadSections(const PortProxy& mem_proxy, Addr addr_mask,
9514017Sbrandon.potter@amd.com                         Addr offset)
962420SN/A{
9711391Sbrandon.potter@amd.com    return (loadSection(&text, mem_proxy, addr_mask, offset)
9811391Sbrandon.potter@amd.com            && loadSection(&data, mem_proxy, addr_mask, offset)
9911391Sbrandon.potter@amd.com            && loadSection(&bss, mem_proxy, addr_mask, offset));
1002SN/A}
1012SN/A
10213982Sgabeblack@google.comnamespace
10313982Sgabeblack@google.com{
10413982Sgabeblack@google.com
10513982Sgabeblack@google.comtypedef std::vector<ObjectFile::Loader *> LoaderList;
10613982Sgabeblack@google.com
10713982Sgabeblack@google.comLoaderList &
10813982Sgabeblack@google.comobject_file_loaders()
10913982Sgabeblack@google.com{
11013982Sgabeblack@google.com    static LoaderList loaders;
11113982Sgabeblack@google.com    return loaders;
11213982Sgabeblack@google.com}
11313982Sgabeblack@google.com
11413982Sgabeblack@google.com} // anonymous namespace
11513982Sgabeblack@google.com
11613982Sgabeblack@google.comObjectFile::Loader::Loader()
11713982Sgabeblack@google.com{
11813982Sgabeblack@google.com    object_file_loaders().emplace_back(this);
11913982Sgabeblack@google.com}
12013982Sgabeblack@google.com
12113982Sgabeblack@google.comProcess *
12213982Sgabeblack@google.comObjectFile::tryLoaders(ProcessParams *params, ObjectFile *obj_file)
12313982Sgabeblack@google.com{
12413982Sgabeblack@google.com    for (auto &loader: object_file_loaders()) {
12513982Sgabeblack@google.com        Process *p = loader->load(params, obj_file);
12613982Sgabeblack@google.com        if (p)
12713982Sgabeblack@google.com            return p;
12813982Sgabeblack@google.com    }
12913982Sgabeblack@google.com
13013982Sgabeblack@google.com    return nullptr;
13113982Sgabeblack@google.com}
13213982Sgabeblack@google.com
13311354SCurtis.Dunham@arm.comstatic bool
13411354SCurtis.Dunham@arm.comhasGzipMagic(int fd)
13511354SCurtis.Dunham@arm.com{
13611354SCurtis.Dunham@arm.com    uint8_t buf[2] = {0};
13711354SCurtis.Dunham@arm.com    size_t sz = pread(fd, buf, 2, 0);
13811354SCurtis.Dunham@arm.com    panic_if(sz != 2, "Couldn't read magic bytes from object file");
13911354SCurtis.Dunham@arm.com    return ((buf[0] == 0x1f) && (buf[1] == 0x8b));
14011354SCurtis.Dunham@arm.com}
14111354SCurtis.Dunham@arm.com
14211354SCurtis.Dunham@arm.comstatic int
14311354SCurtis.Dunham@arm.comdoGzipLoad(int fd)
14411354SCurtis.Dunham@arm.com{
14511354SCurtis.Dunham@arm.com    const size_t blk_sz = 4096;
14611354SCurtis.Dunham@arm.com
14711354SCurtis.Dunham@arm.com    gzFile fdz = gzdopen(fd, "rb");
14811354SCurtis.Dunham@arm.com    if (!fdz) {
14911354SCurtis.Dunham@arm.com        return -1;
15011354SCurtis.Dunham@arm.com    }
15111354SCurtis.Dunham@arm.com
15211354SCurtis.Dunham@arm.com    size_t tmp_len = strlen(P_tmpdir);
15311354SCurtis.Dunham@arm.com    char *tmpnam = (char*) malloc(tmp_len + 20);
15411354SCurtis.Dunham@arm.com    strcpy(tmpnam, P_tmpdir);
15511354SCurtis.Dunham@arm.com    strcpy(tmpnam+tmp_len, "/gem5-gz-obj-XXXXXX"); // 19 chars
15611354SCurtis.Dunham@arm.com    fd = mkstemp(tmpnam); // repurposing fd variable for output
15711354SCurtis.Dunham@arm.com    if (fd < 0) {
15811354SCurtis.Dunham@arm.com        free(tmpnam);
15911354SCurtis.Dunham@arm.com        gzclose(fdz);
16011354SCurtis.Dunham@arm.com        return fd;
16111354SCurtis.Dunham@arm.com    }
16211354SCurtis.Dunham@arm.com
16311354SCurtis.Dunham@arm.com    if (unlink(tmpnam) != 0)
16411354SCurtis.Dunham@arm.com        warn("couldn't remove temporary file %s\n", tmpnam);
16511354SCurtis.Dunham@arm.com
16611354SCurtis.Dunham@arm.com    free(tmpnam);
16711354SCurtis.Dunham@arm.com
16811354SCurtis.Dunham@arm.com    auto buf = new uint8_t[blk_sz];
16911354SCurtis.Dunham@arm.com    int r; // size of (r)emaining uncopied data in (buf)fer
17011354SCurtis.Dunham@arm.com    while ((r = gzread(fdz, buf, blk_sz)) > 0) {
17111354SCurtis.Dunham@arm.com        auto p = buf; // pointer into buffer
17211354SCurtis.Dunham@arm.com        while (r > 0) {
17311354SCurtis.Dunham@arm.com            auto sz = write(fd, p, r);
17411354SCurtis.Dunham@arm.com            assert(sz <= r);
17511354SCurtis.Dunham@arm.com            r -= sz;
17611354SCurtis.Dunham@arm.com            p += sz;
17711354SCurtis.Dunham@arm.com        }
17811354SCurtis.Dunham@arm.com    }
17911354SCurtis.Dunham@arm.com    delete[] buf;
18011354SCurtis.Dunham@arm.com    gzclose(fdz);
18111354SCurtis.Dunham@arm.com    if (r < 0) { // error
18211354SCurtis.Dunham@arm.com        close(fd);
18311354SCurtis.Dunham@arm.com        return -1;
18411354SCurtis.Dunham@arm.com    }
18511354SCurtis.Dunham@arm.com    assert(r == 0); // finished successfully
18611354SCurtis.Dunham@arm.com    return fd; // return fd to decompressed temporary file for mmap()'ing
18711354SCurtis.Dunham@arm.com}
18812SN/A
18912SN/AObjectFile *
1903584Ssaidi@eecs.umich.educreateObjectFile(const string &fname, bool raw)
1912SN/A{
19212SN/A    // open the file
19312SN/A    int fd = open(fname.c_str(), O_RDONLY);
19412SN/A    if (fd < 0) {
19512SN/A        return NULL;
1962SN/A    }
1972SN/A
19811354SCurtis.Dunham@arm.com    // decompress GZ files
19911354SCurtis.Dunham@arm.com    if (hasGzipMagic(fd)) {
20011354SCurtis.Dunham@arm.com        fd = doGzipLoad(fd);
20111354SCurtis.Dunham@arm.com        if (fd < 0) {
20211354SCurtis.Dunham@arm.com            return NULL;
20311354SCurtis.Dunham@arm.com        }
20411354SCurtis.Dunham@arm.com    }
20511354SCurtis.Dunham@arm.com
20612SN/A    // find the length of the file by seeking to the end
20710422Sandreas.hansson@arm.com    off_t off = lseek(fd, 0, SEEK_END);
20811354SCurtis.Dunham@arm.com    fatal_if(off < 0,
20911354SCurtis.Dunham@arm.com             "Failed to determine size of object file %s\n", fname);
21011354SCurtis.Dunham@arm.com    auto len = static_cast<size_t>(off);
21112SN/A
21212SN/A    // mmap the whole shebang
21311391Sbrandon.potter@amd.com    uint8_t *file_data = (uint8_t *)mmap(NULL, len, PROT_READ, MAP_SHARED,
21411391Sbrandon.potter@amd.com                                         fd, 0);
21510880SCurtis.Dunham@arm.com    close(fd);
21611354SCurtis.Dunham@arm.com
21711391Sbrandon.potter@amd.com    if (file_data == MAP_FAILED) {
21812SN/A        return NULL;
2192SN/A    }
2202SN/A
22111391Sbrandon.potter@amd.com    ObjectFile *file_obj = NULL;
2222SN/A
22312SN/A    // figure out what we have here
22411391Sbrandon.potter@amd.com    if ((file_obj = ElfObject::tryFile(fname, len, file_data)) != NULL) {
22511391Sbrandon.potter@amd.com        return file_obj;
2262SN/A    }
2272SN/A
22811391Sbrandon.potter@amd.com    if ((file_obj = EcoffObject::tryFile(fname, len, file_data)) != NULL) {
22911391Sbrandon.potter@amd.com        return file_obj;
2302SN/A    }
2312SN/A
23211391Sbrandon.potter@amd.com    if ((file_obj = AoutObject::tryFile(fname, len, file_data)) != NULL) {
23311391Sbrandon.potter@amd.com        return file_obj;
2342SN/A    }
2352SN/A
23611391Sbrandon.potter@amd.com    if ((file_obj = DtbObject::tryFile(fname, len, file_data)) != NULL) {
23711391Sbrandon.potter@amd.com        return file_obj;
2389538Satgutier@umich.edu    }
2399538Satgutier@umich.edu
2403584Ssaidi@eecs.umich.edu    if (raw)
24111391Sbrandon.potter@amd.com        return RawObject::tryFile(fname, len, file_data);
2423584Ssaidi@eecs.umich.edu
24312SN/A    // don't know what it is
24411391Sbrandon.potter@amd.com    munmap((char*)file_data, len);
24512SN/A    return NULL;
2462SN/A}
247