1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
/* elfread.c: Functions for reading specific ELF headers.
* Copyright (C) 1999,2011 by Brian Raiter <breadbox@muppetlabs.com>
* License GPLv2+: GNU GPL version 2 or later.
* This is free software; you are free to change and redistribute it.
* There is NO WARRANTY, to the extent permitted by law.
*/
#include <string.h>
#include <elf.h>
#include "gen.h"
#include "names.h"
#include "pieces.h"
#include "phdrtab.h"
#include "shdrtab.h"
#include "readelf.h"
/* Some platforms (e.g. FreeBSD) may not provide these standard
* defines in elf.h, so default definitions are supplied as a
* fallback.
*/
#ifndef ELFCLASSNUM
#define ELFCLASSNUM 3
#endif
#ifndef ELFDATANUM
#define ELFDATANUM 2
#endif
#ifndef EV_NUM
#define EV_NUM 2
#endif
static long filesize; /* size of the input ELF file */
static unsigned char const *image; /* pointer to the ELF file image */
static Elf64_Ehdr const *ehdr; /* pointer to a scrubbed ELF header */
/* Returns true if the input file is a 64-bit ELF file.
*/
int iself64(void)
{
return ehdr->e_ident[EI_CLASS] == ELFCLASS64;
}
/* Returns true if the input file is an ELF core file.
*/
int iscorefile(void)
{
return ehdr->e_type == ET_CORE;
}
/* Returns a pointer to a location in the input file, given an offset.
*/
void const *getptrto(long offset, long *size)
{
if (offset >= filesize || offset < 0 || *size < 0) {
*size = 0;
return NULL;
}
if (offset + *size > filesize)
*size = filesize - offset;
return image + offset;
}
/* Examines the ELF file's ident header and runs some sanity checks on
* the contents. Warnings are printed if anything in the ident looks
* dodgy or unexpected. False is returned if there are insurmountable
* obstacles to parsing the ELF file.
*/
static int verifyident(void)
{
unsigned char const *ident = image;
if (filesize < EI_NIDENT)
return err("file is not an ELF file.");
if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1
|| ident[EI_MAG2] != ELFMAG2
|| ident[EI_MAG3] != ELFMAG3)
warn("file does not contain an ELF signature.");
if (ident[EI_CLASS] == ELFCLASSNONE || ident[EI_CLASS] >= ELFCLASSNUM)
warn("unrecognized ELF class value: %d.", ident[EI_CLASS]);
if (ident[EI_DATA] == ELFDATANONE || ident[EI_DATA] >= ELFDATANUM) {
warn("unrecognized ELF data value: %d.", ident[EI_DATA]);
} else {
int be = 1;
*(char*)&be = 0;
if (ident[EI_DATA] != (be ? ELFDATA2MSB : ELFDATA2LSB))
return err("not a %s-endian ELF file.", (be ? "big" : "little"));
}
if (ident[EI_VERSION] == EV_NONE || ident[EI_VERSION] >= EV_NUM)
warn("unrecognized ELF header version: %d.", ident[EI_VERSION]);
return TRUE;
}
/* Makes a copy of the input file's ELF header and stores it in ehdr.
* Warnings are printed if the examined fields don't match their
* expected values. If the ELF header is a 32-bit structure, or if it
* is somehow malformed, its values are extracted manually.
*/
static void copyehdr(void)
{
Elf64_Ehdr *eh64;
eh64 = allocate(sizeof *eh64);
if (image[EI_CLASS] == ELFCLASS64) {
if (filesize >= (int)(sizeof *eh64)) {
memcpy(eh64, image, sizeof *eh64);
recordpiece(0, sizeof(Elf64_Ehdr), P_EHDR, "ehdr", 0);
} else {
memcpy(eh64, image, filesize);
memset((char*)eh64 + filesize, 0, sizeof *eh64 - filesize);
warn("file does not have a complete ELF header.");
recordpiece(0, filesize, P_SECTION, "~ehdr", 0);
}
if (eh64->e_version == EV_NONE || eh64->e_version >= EV_NUM)
warn("unrecognized ELF version: %d.", eh64->e_version);
if (eh64->e_ehsize != sizeof(Elf64_Ehdr))
warn("unexpected ELF header size: %u instead of %u.",
eh64->e_ehsize, sizeof(Elf64_Ehdr));
if (eh64->e_phoff && eh64->e_phentsize != sizeof(Elf64_Phdr))
warn("unexpected program header entry size: %u instead of %u.",
eh64->e_phentsize, sizeof(Elf64_Phdr));
if (eh64->e_shoff && eh64->e_shentsize != sizeof(Elf64_Shdr))
warn("unexpected section header entry size: %u instead of %u.",
eh64->e_shentsize, sizeof(Elf64_Shdr));
} else {
Elf32_Ehdr eh32;
if (filesize >= (int)(sizeof eh32)) {
memcpy(&eh32, image, sizeof eh32);
recordpiece(0, sizeof(Elf32_Ehdr), P_EHDR, "ehdr", 0);
} else {
memcpy(&eh32, image, filesize);
memset((char*)&eh32 + filesize, 0, sizeof eh32 - filesize);
warn("file does not have a complete ELF header.");
recordpiece(0, filesize, P_SECTION, "~ehdr", 0);
}
if (eh32.e_version == EV_NONE || eh32.e_version >= EV_NUM)
warn("unrecognized ELF version: %d.", eh32.e_version);
if (eh32.e_ehsize != sizeof(Elf32_Ehdr))
warn("unexpected ELF header size: %u instead of %u.",
eh32.e_ehsize, sizeof(Elf32_Ehdr));
if (eh32.e_phoff && eh32.e_phentsize != sizeof(Elf32_Phdr))
warn("unexpected program header entry size: %u instead of %u.",
eh32.e_phentsize, sizeof(Elf32_Phdr));
if (eh32.e_shoff && eh32.e_shentsize != sizeof(Elf32_Shdr))
warn("unexpected section header entry size: %u instead of %u.",
eh32.e_shentsize, sizeof(Elf32_Shdr));
memcpy(eh64->e_ident, eh32.e_ident, sizeof eh64->e_ident);
eh64->e_type = eh32.e_type;
eh64->e_machine = eh32.e_machine;
eh64->e_version = eh32.e_version;
eh64->e_entry = eh32.e_entry;
eh64->e_phoff = eh32.e_phoff;
eh64->e_shoff = eh32.e_shoff;
eh64->e_flags = eh32.e_flags;
eh64->e_ehsize = eh32.e_ehsize;
eh64->e_phentsize = eh32.e_phentsize;
eh64->e_phnum = eh32.e_phnum;
eh64->e_shentsize = eh32.e_shentsize;
eh64->e_shnum = eh32.e_shnum;
eh64->e_shstrndx = eh32.e_shstrndx;
}
ehdr = eh64;
}
/* Initialize the ELF file's size and location, and examine the basic
* headers: the ELF header, the program segment header table, and the
* section header table. False is returned if the file is not
* analyzable.
*/
int readelf(void const *ptr, size_t size)
{
image = ptr;
filesize = size;
if (!verifyident())
return FALSE;
recordpiece(0, filesize, P_UNCLAIMED, "~pad", 0);
copyehdr();
setmachinespecific(ehdr->e_machine);
dividesegments(ehdr->e_phoff, ehdr->e_phnum, ehdr->e_phentsize);
dividesections(ehdr->e_shoff, ehdr->e_shnum, ehdr->e_shentsize,
ehdr->e_shstrndx);
return TRUE;
}
|