/* $Id: elf.c,v 1.1.1.1 2009/02/21 21:25:19 khorben Exp $ */ /* Copyright (c) 2007 khorben of Uberwall */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef __OpenBSD__ # include #else # include #endif #include "plugin.h" /* elf */ /* public */ /* types */ typedef union { Elf32_Ehdr e32; Elf64_Ehdr e64; } elf_ehdr; /* constants */ /* elf.h might not know these (GNU/Linux) */ #ifndef ELFOSABI_HURD # define ELFOSABI_HURD 4 #endif #ifndef ELFOSABI_MONTEREY # define ELFOSABI_MONTEREY 7 #endif #ifndef EM_486 # define EM_486 6 #endif #ifndef EM_MIPS_RS3_LE # define EM_MIPS_RS3_LE 10 #endif /* variables */ /* magic */ static unsigned char elf[] = ELFMAG; PluginMagic elf_magic[] = { { sizeof(Elf32_Ehdr), 0, elf, sizeof(elf)-1 }, { 0, 0, NULL, 0 } }; /* functions */ static int elf_callback(PluginHelper * ph, int signature, FILE * fp); /* plugin */ Plugin plugin = { PT_EXECUTABLE, "ELF", elf_magic, elf_callback }; /* private */ /* functions */ /* plugin_callback */ static int _callback_32(PluginHelper * ph, Elf32_Ehdr * hdr); static int _callback_64(PluginHelper * ph, Elf64_Ehdr * hdr); static int elf_callback(PluginHelper * ph, int signature, FILE * fp) { fpos_t pos; elf_ehdr buf; if(fgetpos(fp, &pos) != 0) return -1; if(fread(&buf, sizeof(buf), 1, fp) == 1) { if(buf.e32.e_ident[EI_CLASS] == ELFCLASS32) return _callback_32(ph, &buf.e32); if(buf.e64.e_ident[EI_CLASS] == ELFCLASS64) return _callback_64(ph, &buf.e64); return -1; } if(fsetpos(fp, &pos) != 0) return -1; if(fread(&buf.e32, sizeof(buf.e32), 1, fp) == 1 && buf.e32.e_ident[EI_CLASS] == ELFCLASS32) return _callback_32(ph, &buf.e32); return -1; } static int _callback_encoding(PluginHelper * ph, unsigned char encoding); static int _callback_version(PluginHelper * ph, unsigned char version); static int _callback_system(PluginHelper * ph, unsigned char system); static void _32_endian(Elf32_Ehdr * hdr); static int _callback_type(PluginHelper * ph, uint16_t type); static int _callback_machine(PluginHelper * ph, uint16_t machine); static int _callback_32(PluginHelper * ph, Elf32_Ehdr * hdr) { int score = 0; ph->printf(ph, "%s", "32-bits"); score+=_callback_encoding(ph, hdr->e_ident[EI_DATA]); score+=_callback_version(ph, hdr->e_ident[EI_VERSION]); score+=_callback_system(ph, hdr->e_ident[EI_OSABI]); _32_endian(hdr); score+=_callback_type(ph, hdr->e_type); score+=_callback_machine(ph, hdr->e_machine); ph->printf(ph, "\n"); return score / 5; } static void _32_endian(Elf32_Ehdr * hdr) { if(hdr->e_ident[EI_DATA] == ELFDATA2LSB) { hdr->e_type = htol16(hdr->e_type); hdr->e_machine = htol16(hdr->e_machine); hdr->e_version = htol32(hdr->e_version); } else if(hdr->e_ident[EI_DATA] == ELFDATA2MSB) { hdr->e_type = htob16(hdr->e_type); hdr->e_machine = htob16(hdr->e_machine); hdr->e_version = htob32(hdr->e_version); } } static void _64_endian(Elf64_Ehdr * hdr); static int _callback_64(PluginHelper * ph, Elf64_Ehdr * hdr) { int score = 0; ph->printf(ph, "%s", "64-bits"); score+=_callback_encoding(ph, hdr->e_ident[EI_DATA]); score+=_callback_version(ph, hdr->e_ident[EI_VERSION]); score+=_callback_system(ph, hdr->e_ident[EI_OSABI]); _64_endian(hdr); score+=_callback_type(ph, hdr->e_type); score+=_callback_machine(ph, hdr->e_machine); ph->printf(ph, "\n"); return score / 5; } static void _64_endian(Elf64_Ehdr * hdr) { if(hdr->e_ident[EI_DATA] == ELFDATA2LSB) { hdr->e_type = htol16(hdr->e_type); hdr->e_machine = htol16(hdr->e_machine); hdr->e_version = htol32(hdr->e_version); } else if(hdr->e_ident[EI_DATA] == ELFDATA2MSB) { hdr->e_type = htob16(hdr->e_type); hdr->e_machine = htob16(hdr->e_machine); hdr->e_version = htob32(hdr->e_version); } } static int _callback_encoding(PluginHelper * ph, unsigned char encoding) { switch(encoding) { case ELFDATANONE: ph->printf(ph, "%s", ", invalid encoding"); return 50; case ELFDATA2LSB: ph->printf(ph, "%s", ", little endian"); return 100; case ELFDATA2MSB: ph->printf(ph, "%s", ", big endian"); return 100; default: ph->printf(ph, "%s", ", unknown encoding"); return 0; } } static int _callback_version(PluginHelper * ph, unsigned char version) { if(version == EV_CURRENT) { ph->printf(ph, "%s", ", current version"); return 100; } ph->printf(ph, "%s", ", invalid version"); return 0; } static int _callback_system(PluginHelper * ph, unsigned char system) { struct { unsigned char system; char * name; int score; } sns[] = { { ELFOSABI_SYSV, "SYSV", 100 }, { ELFOSABI_HPUX, "HP-UX", 100 }, { ELFOSABI_NETBSD, "NetBSD", 100 }, { ELFOSABI_LINUX, "GNU/Linux", 100 }, { ELFOSABI_HURD, "GNU/Hurd", 100 }, { ELFOSABI_SOLARIS, "Solaris", 100 }, { ELFOSABI_MONTEREY, "Monterey", 100 }, { ELFOSABI_IRIX, "IRIX", 100 }, { ELFOSABI_FREEBSD, "FreeBSD", 100 }, { ELFOSABI_TRU64, "TRU64", 100 }, { ELFOSABI_MODESTO, "Modesto", 100 }, { ELFOSABI_OPENBSD, "OpenBSD", 100 }, { ELFOSABI_ARM, "ARM", 100 }, { 0, NULL, 0 } }; size_t i; for(i = 0; sns[i].name != NULL; i++) if(sns[i].system == system) break; if(sns[i].name == NULL) { ph->printf(ph, "%s%d%s", ", unknown ABI (", system, ")"); return 0; } ph->printf(ph, "%s%s%s", ", ", sns[i].name, " ABI"); return sns[i].score; } static int _callback_type(PluginHelper * ph, uint16_t type) { struct { uint16_t type; char * name; int score; } tns[] = { { ET_NONE, "no type", 50 }, { ET_REL, "relocatable", 100 }, { ET_EXEC, "executable", 100 }, { ET_DYN, "shared object", 100 }, { ET_CORE, "core file", 100 }, { 0, NULL, 0 } }; size_t i; for(i = 0; tns[i].name != NULL; i++) if(tns[i].type == type) break; if(tns[i].name == NULL) { ph->printf(ph, "%s", ", unknown type"); return 0; } ph->printf(ph, "%s%s", ", ", tns[i].name); return tns[i].score; } static int _callback_machine(PluginHelper * ph, uint16_t machine) { struct { uint16_t machine; char * name; int score; } mns[] = { { EM_NONE, "no machine", 50 }, { EM_SPARC, "SPARC", 100 }, { EM_386, "i386", 100 }, { EM_68K, "m68k", 100 }, { EM_88K, "m88k", 100 }, { EM_486, "i486", 100 }, { EM_860, "i860", 100 }, { EM_MIPS, "MIPS", 100 }, { EM_MIPS_RS3_LE, "MIPS", 100 }, { EM_ARM, "ARM", 100 }, { 0, NULL, 0 } }; size_t i; for(i = 0; mns[i].name != NULL; i++) if(mns[i].machine == machine) break; if(mns[i].name == NULL) { ph->printf(ph, "%s%d%s", ", unknown target (", machine, ")"); return 0; } ph->printf(ph, "%s%s", ", for ", mns[i].name); return mns[i].score; }