elf_object.cc revision 6392:9345de6fca33
1/*
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Steve Reinhardt
29 *          Ali Saidi
30 */
31
32#include <cassert>
33#include <string>
34
35#include "gelf.h"
36
37#include "base/loader/elf_object.hh"
38#include "base/loader/symtab.hh"
39#include "base/misc.hh"
40#include "base/trace.hh"        // for DPRINTF
41#include "sim/byteswap.hh"
42
43using namespace std;
44
45ObjectFile *
46ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
47{
48    Elf *elf;
49    GElf_Ehdr ehdr;
50    Arch arch = UnknownArch;
51    OpSys opSys = UnknownOpSys;
52
53    // check that header matches library version
54    if (elf_version(EV_CURRENT) == EV_NONE)
55        panic("wrong elf version number!");
56
57    // get a pointer to elf structure
58    elf = elf_memory((char*)data,len);
59    // will only fail if fd is invalid
60    assert(elf != NULL);
61
62    // Check that we actually have a elf file
63    if (gelf_getehdr(elf, &ehdr) ==0) {
64        DPRINTFR(Loader, "Not ELF\n");
65        elf_end(elf);
66        return NULL;
67    } else {
68        //Detect the architecture
69        //Since we don't know how to check for alpha right now, we'll
70        //just assume if it wasn't something else and it's 64 bit, that's
71        //what it must be.
72        if (ehdr.e_machine == EM_SPARC64 ||
73                (ehdr.e_machine == EM_SPARC &&
74                 ehdr.e_ident[EI_CLASS] == ELFCLASS64)||
75                ehdr.e_machine == EM_SPARCV9) {
76            arch = ObjectFile::SPARC64;
77        } else if (ehdr.e_machine == EM_SPARC32PLUS ||
78                        (ehdr.e_machine == EM_SPARC &&
79                         ehdr.e_ident[EI_CLASS] == ELFCLASS32)) {
80            arch = ObjectFile::SPARC32;
81        } else if (ehdr.e_machine == EM_MIPS
82                && ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
83            if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) {
84                arch = ObjectFile::Mips;
85            } else {
86                fatal("The binary you're trying to load is compiled for big "
87                        "endian MIPS. M5\nonly supports little endian MIPS. "
88                        "Please recompile your binary.\n");
89            }
90        } else if (ehdr.e_machine == EM_X86_64 &&
91                ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
92            arch = ObjectFile::X86_64;
93        } else if (ehdr.e_machine == EM_386 &&
94                ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
95            arch = ObjectFile::I386;
96        } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
97            arch = ObjectFile::Alpha;
98        } else if (ehdr.e_machine == EM_ARM) {
99            arch = ObjectFile::Arm;
100        } else {
101            warn("Unknown architecture: %d\n", ehdr.e_machine);
102            arch = ObjectFile::UnknownArch;
103        }
104
105        //Detect the operating system
106        switch (ehdr.e_ident[EI_OSABI])
107        {
108
109          case ELFOSABI_LINUX:
110            opSys = ObjectFile::Linux;
111            break;
112          case ELFOSABI_SOLARIS:
113            opSys = ObjectFile::Solaris;
114            break;
115          case ELFOSABI_TRU64:
116            opSys = ObjectFile::Tru64;
117            break;
118          case ELFOSABI_ARM:
119            opSys = ObjectFile::LinuxArmOABI;
120            break;
121          default:
122            opSys = ObjectFile::UnknownOpSys;
123        }
124
125        //take a look at the .note.ABI section
126        //It can let us know what's what.
127        if (opSys == ObjectFile::UnknownOpSys) {
128            Elf_Scn *section;
129            GElf_Shdr shdr;
130            Elf_Data *data;
131            uint32_t osAbi;;
132            int secIdx = 1;
133
134            // Get the first section
135            section = elf_getscn(elf, secIdx);
136
137            // While there are no more sections
138            while (section != NULL && opSys == ObjectFile::UnknownOpSys) {
139                gelf_getshdr(section, &shdr);
140                if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag",
141                            elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) {
142                    // we have found a ABI note section
143                    // Check the 5th 32bit word for OS  0 == linux, 1 == hurd,
144                    // 2 == solaris, 3 == freebsd
145                    data = elf_rawdata(section, NULL);
146                    assert(data->d_buf);
147                    if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
148                        osAbi = htole(((uint32_t*)data->d_buf)[4]);
149                    else
150                        osAbi = htobe(((uint32_t*)data->d_buf)[4]);
151
152                    switch(osAbi) {
153                      case 0:
154                        opSys = ObjectFile::Linux;
155                        break;
156                      case 2:
157                        opSys = ObjectFile::Solaris;
158                        break;
159                    }
160                } // if section found
161                if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)))
162                        opSys = ObjectFile::Solaris;
163                if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)))
164                        opSys = ObjectFile::Solaris;
165
166            section = elf_getscn(elf, ++secIdx);
167            } // while sections
168        }
169
170        ElfObject * result = new ElfObject(fname, fd, len, data, arch, opSys);
171
172        //The number of headers in the file
173        result->_programHeaderCount = ehdr.e_phnum;
174        //Record the size of each entry
175        result->_programHeaderSize = ehdr.e_phentsize;
176        if(result->_programHeaderCount) //If there is a program header table
177        {
178            //Figure out the virtual address of the header table in the
179            //final memory image. We use the program headers themselves
180            //to translate from a file offset to the address in the image.
181            GElf_Phdr phdr;
182            uint64_t e_phoff = ehdr.e_phoff;
183            result->_programHeaderTable = 0;
184            for(int hdrnum = 0; hdrnum < result->_programHeaderCount; hdrnum++)
185            {
186                gelf_getphdr(elf, hdrnum, &phdr);
187                //Check if we've found the segment with the headers in it
188                if(phdr.p_offset <= e_phoff &&
189                        phdr.p_offset + phdr.p_filesz > e_phoff)
190                {
191                    result->_programHeaderTable = phdr.p_paddr + e_phoff;
192                    break;
193                }
194            }
195        }
196        else
197            result->_programHeaderTable = 0;
198
199
200        elf_end(elf);
201        return result;
202    }
203}
204
205
206ElfObject::ElfObject(const string &_filename, int _fd,
207                     size_t _len, uint8_t *_data,
208                     Arch _arch, OpSys _opSys)
209    : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys)
210
211{
212    Elf *elf;
213    GElf_Ehdr ehdr;
214
215    // check that header matches library version
216    if (elf_version(EV_CURRENT) == EV_NONE)
217        panic("wrong elf version number!");
218
219    // get a pointer to elf structure
220    elf = elf_memory((char*)fileData,len);
221    // will only fail if fd is invalid
222    assert(elf != NULL);
223
224    // Check that we actually have a elf file
225    if (gelf_getehdr(elf, &ehdr) ==0) {
226        panic("Not ELF, shouldn't be here");
227    }
228
229    entry = ehdr.e_entry;
230
231    // initialize segment sizes to 0 in case they're not present
232    text.size = data.size = bss.size = 0;
233
234    int secIdx = 1;
235    Elf_Scn *section;
236    GElf_Shdr shdr;
237
238    // The first address of some important sections.
239    Addr textSecStart = 0;
240    Addr dataSecStart = 0;
241    Addr bssSecStart = 0;
242
243    // Get the first section
244    section = elf_getscn(elf, secIdx);
245
246    // Find the beginning of the most interesting sections.
247    while (section != NULL) {
248        gelf_getshdr(section, &shdr);
249        char * secName = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
250
251        if (!strcmp(".text", secName)) {
252            textSecStart = shdr.sh_addr;
253        } else if (!strcmp(".data", secName)) {
254            dataSecStart = shdr.sh_addr;
255        } else if (!strcmp(".bss", secName)) {
256            bssSecStart = shdr.sh_addr;
257        }
258
259        section = elf_getscn(elf, ++secIdx);
260    }
261
262    // Go through all the segments in the program, record them, and scrape
263    // out information about the text, data, and bss areas needed by other
264    // code.
265    for (int i = 0; i < ehdr.e_phnum; ++i) {
266        GElf_Phdr phdr;
267        if (gelf_getphdr(elf, i, &phdr) == 0) {
268            panic("gelf_getphdr failed for segment %d.", i);
269        }
270
271        // for now we don't care about non-loadable segments
272        if (!(phdr.p_type & PT_LOAD))
273            continue;
274
275        // Check to see if this segment contains the bss section.
276        if (phdr.p_paddr <= bssSecStart &&
277                phdr.p_paddr + phdr.p_memsz > bssSecStart &&
278                phdr.p_memsz - phdr.p_filesz > 0) {
279            bss.baseAddr = phdr.p_paddr + phdr.p_filesz;
280            bss.size = phdr.p_memsz - phdr.p_filesz;
281            bss.fileImage = NULL;
282        }
283
284        // Check to see if this is the text or data segment
285        if (phdr.p_vaddr <= textSecStart &&
286                phdr.p_vaddr + phdr.p_filesz > textSecStart) {
287            text.baseAddr = phdr.p_paddr;
288            text.size = phdr.p_filesz;
289            text.fileImage = fileData + phdr.p_offset;
290        } else if (phdr.p_vaddr <= dataSecStart &&
291                phdr.p_vaddr + phdr.p_filesz > dataSecStart) {
292            data.baseAddr = phdr.p_paddr;
293            data.size = phdr.p_filesz;
294            data.fileImage = fileData + phdr.p_offset;
295        } else {
296            // If it's none of the above but is loadable,
297            // load the filesize worth of data
298            Segment extra;
299            extra.baseAddr = phdr.p_paddr;
300            extra.size = phdr.p_filesz;
301            extra.fileImage = fileData + phdr.p_offset;
302            extraSegments.push_back(extra);
303        }
304    }
305
306    // should have found at least one loadable segment
307    assert(text.size != 0);
308
309    DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
310             text.baseAddr, text.size, data.baseAddr, data.size,
311             bss.baseAddr, bss.size);
312
313    elf_end(elf);
314
315    // We will actually read the sections when we need to load them
316}
317
318
319bool
320ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding)
321{
322    Elf *elf;
323    int sec_idx = 1; // there is a 0 but it is nothing, go figure
324    Elf_Scn *section;
325    GElf_Shdr shdr;
326    Elf_Data *data;
327    int count, ii;
328    bool found = false;
329    GElf_Sym sym;
330
331    if (!symtab)
332        return false;
333
334    // check that header matches library version
335    if (elf_version(EV_CURRENT) == EV_NONE)
336        panic("wrong elf version number!");
337
338    // get a pointer to elf structure
339    elf = elf_memory((char*)fileData,len);
340
341    assert(elf != NULL);
342
343    // Get the first section
344    section = elf_getscn(elf, sec_idx);
345
346    // While there are no more sections
347    while (section != NULL) {
348        gelf_getshdr(section, &shdr);
349
350        if (shdr.sh_type == SHT_SYMTAB) {
351            found = true;
352            data = elf_getdata(section, NULL);
353            count = shdr.sh_size / shdr.sh_entsize;
354            DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count);
355
356            // loop through all the symbols, only loading global ones
357            for (ii = 0; ii < count; ++ii) {
358                gelf_getsym(data, ii, &sym);
359                if (GELF_ST_BIND(sym.st_info) == binding) {
360                   symtab->insert(sym.st_value,
361                                  elf_strptr(elf, shdr.sh_link, sym.st_name));
362                }
363            }
364        }
365        ++sec_idx;
366        section = elf_getscn(elf, sec_idx);
367    }
368
369    elf_end(elf);
370
371    return found;
372}
373
374bool
375ElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask)
376{
377    return loadSomeSymbols(symtab, STB_GLOBAL);
378}
379
380bool
381ElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask)
382{
383    return loadSomeSymbols(symtab, STB_LOCAL);
384}
385
386bool
387ElfObject::loadSections(Port *memPort, Addr addrMask)
388{
389    if (!ObjectFile::loadSections(memPort, addrMask))
390        return false;
391
392    vector<Segment>::iterator extraIt;
393    for (extraIt = extraSegments.begin();
394            extraIt != extraSegments.end(); extraIt++) {
395        if (!loadSection(&(*extraIt), memPort, addrMask)) {
396            return false;
397        }
398    }
399    return true;
400}
401
402void
403ElfObject::getSections()
404{
405    Elf *elf;
406    int sec_idx = 1; // there is a 0 but it is nothing, go figure
407    Elf_Scn *section;
408    GElf_Shdr shdr;
409
410    GElf_Ehdr ehdr;
411
412    assert(!sectionNames.size());
413
414    // check that header matches library version
415    if (elf_version(EV_CURRENT) == EV_NONE)
416        panic("wrong elf version number!");
417
418    // get a pointer to elf structure
419    elf = elf_memory((char*)fileData,len);
420    assert(elf != NULL);
421
422    // Check that we actually have a elf file
423    if (gelf_getehdr(elf, &ehdr) ==0) {
424        panic("Not ELF, shouldn't be here");
425    }
426
427    // Get the first section
428    section = elf_getscn(elf, sec_idx);
429
430    // While there are no more sections
431    while (section != NULL) {
432        gelf_getshdr(section, &shdr);
433        sectionNames.insert(elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));
434        section = elf_getscn(elf, ++sec_idx);
435    } // while sections
436}
437
438bool
439ElfObject::sectionExists(string sec)
440{
441    if (!sectionNames.size())
442        getSections();
443    return sectionNames.find(sec) != sectionNames.end();
444}
445
446
447