diff -r 000000000000 -r 044383f39525 bintools/elftools/getexports/geninf.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bintools/elftools/getexports/geninf.cpp Tue Oct 27 16:36:35 2009 +0000 @@ -0,0 +1,433 @@ +/* +* Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include +#include +#include + + +#include +#define DEFAULT_VERSION 2 + +#define ELFADDR(rtype, p, o) (rtype *)(((char *)p) + o) + +FILE *OUTFILE; + +void croak(char * s) +{ + printf("GENINF ERROR: %s\n", s); + exit(EXIT_FAILURE); +} + +void croak2(char * s1, char * s2) +{ + printf("GENINF ERROR: %s %s\n", s1, s2); + exit(EXIT_FAILURE); +} + +int GetFileSize(FILE * f, char * file) +{ + int r = fseek(f, 0, SEEK_END); + if (r) croak2("can't seek to end of file:", file); + r = ftell(f); + rewind(f); + return r; +} + +void EnsureElf(Elf32_Ehdr* eh) +{ + if (!(eh->e_ident[EI_MAG0] == ELFMAG0 && + eh->e_ident[EI_MAG1] == ELFMAG1 && + eh->e_ident[EI_MAG2] == ELFMAG2 && + eh->e_ident[EI_MAG3] == ELFMAG3)) + croak("Invalid ELF magic.\n"); + if (eh->e_ident[EI_CLASS] != ELFCLASS32) + croak("File is not a 32 bit ELF object file.\n"); + if (eh->e_ident[EI_DATA] != ELFDATA2LSB) + croak("File data encoding is not Little Endian.\n"); + if (eh->e_machine != EM_ARM) + croak("File does not target ARM/THUMB processors.\n"); + +} + + +Elf32_Ehdr* OpenElfFile (char* file) +{ + Elf32_Ehdr* eh; + FILE* f = fopen(file, "rb"); + if (!f) + croak2("can't open file:", file); + + int fsize = GetFileSize(f, file); + + eh = (Elf32_Ehdr*)malloc(fsize); + if (!eh) + croak("Out of memory"); + + if (fread(eh, fsize, 1, f) != 1) + croak2("Can't read file", file); + + EnsureElf(eh); + + return eh; +} + +typedef struct NameList +{ + NameList * nl_next; + char * nl_name; + unsigned int nl_size; +} NameList; + + +static NameList * ExportedData = 0; +static NameList * ExportedCode = 0; +//Workaround for compiler defect(To avoid export of static symbols) +static NameList * LocalSymbols = 0; + + +NameList* IsPresentInList(char * name, NameList * list) +{ + NameList * e = list; + while (e) { + if (!strcmp(name, e->nl_name)) + return e; + else + e = e->nl_next; + } + return 0; +} + +NameList* IsExportedData(char * name) +{ + return IsPresentInList(name,ExportedData); +} + +NameList* IsExportedCode(char * name) +{ + return IsPresentInList(name,ExportedCode); +} + +//Workaround for compiler defect(To avoid export of local symbols) +NameList* IsLocalSymbol(char * name) +{ + return IsPresentInList(name,LocalSymbols); +} + +void AddToList(char * name, NameList *& list, unsigned int aSymSz) +{ + NameList * ed = new NameList; + ed->nl_name = name; + ed->nl_size = aSymSz; + ed->nl_next = list; + list = ed; +} + +void AddExportedData(char * name, unsigned int aSymSz) +{ + AddToList(name, ExportedData, aSymSz); +} + +void AddExportedCode(char * name, unsigned int aSymSz) +{ + AddToList(name, ExportedCode, aSymSz); +} + +//Workaround for compiler defect(To avoid export of local symbols) +void AddLocalSymbols(char * name) +{ + AddToList(name, LocalSymbols, 0); +} + +void InitSymbolsLists(Elf32_Ehdr * eh,Elf32_Shdr * shdr,int shnum) +{ + Elf32_Sym * symtab = 0; + int nSyms = 0; + char * strtab = 0; + int i=0; + + for (i = 0; (i < shnum); i++) { + if (shdr[i].sh_type == SHT_SYMTAB) { + symtab = ELFADDR(Elf32_Sym, eh, shdr[i].sh_offset); + nSyms = shdr[i].sh_size / shdr[i].sh_entsize; + strtab = ELFADDR(char, eh, shdr[shdr[i].sh_link].sh_offset); + break; + } + } + for (i = 0; i < nSyms; i++) { + if (symtab[i].st_info == ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT)) { + char * name = ELFADDR(char, strtab, symtab[i].st_name); + AddExportedData(name, symtab[i].st_size); + } else if (symtab[i].st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)) { + char * name = ELFADDR(char, strtab, symtab[i].st_name); + AddExportedCode(name, symtab[i].st_size); + } + else if (symtab[i].st_info == ELF32_ST_INFO(STB_LOCAL, STT_FUNC) || + symtab[i].st_info == ELF32_ST_INFO(STB_LOCAL, STT_OBJECT)) { + // Workaround for compiler defect to avoid export of local symbols + char * name = ELFADDR(char, strtab, symtab[i].st_name); + AddLocalSymbols(name); + } + } +} + +#define DIRECTIVE_TAG "##" +#define DIRECTIVE_TAG_SIZE (sizeof(DIRECTIVE_TAG) - 1) +#define EXPORT_DIRECTIVE "EXPORT " +#define EXPORT_DIRECTIVE_SIZE (sizeof(EXPORT_DIRECTIVE) - 1) + +void PrintExportsFromSection(char * section, int size) +{ + if (strncmp(DIRECTIVE_TAG, section, DIRECTIVE_TAG_SIZE) != 0) + croak("Unrecognized .directive tag"); + section += (DIRECTIVE_TAG_SIZE + 1); + size -= (DIRECTIVE_TAG_SIZE + 1); + // The separator for the following entries is 0x0A (i.e. \n). + // We're only interested in lines starting with EXPORT + char eolchar = '\n'; + NameList* aDataSymbol; + while (size > 0) { + + char * eolp = (char *)memchr(section, eolchar, size); + int linelength = (eolp - section) + 1; + if (!strncmp(EXPORT_DIRECTIVE, section, EXPORT_DIRECTIVE_SIZE)) { + char * symbol = section + EXPORT_DIRECTIVE_SIZE; + int symbolsize = linelength - EXPORT_DIRECTIVE_SIZE - 1; + // null-terminate the string - doesn't matter that we side effect the + // section since we won't see it again and saves making a copy. + symbol[symbolsize] = 0; + if (IsExportedCode(symbol)) { + fprintf(OUTFILE, " %s\n", symbol); + + } else if ( (aDataSymbol = IsExportedData(symbol)) != 0) { + fprintf(OUTFILE, " %s DATA %d\n", symbol, aDataSymbol->nl_size); + } + else { + //All those symbols included from static libs that are + //treated as exported because of the dll_runtime compiler + //option.Such symbols donot figure out in the symbol table. + //Hence are handled separately here. + + //Workaround for compiler defect - To avoid export of local symbols + if(!IsLocalSymbol(symbol)) + { + fprintf(OUTFILE, " %s\n", symbol); + } + + } + } + size -= linelength; + section += linelength; + } +} + +void PrintABIv1ExportSymbols (Elf32_Ehdr * eh) +{ + int shoff = eh->e_shoff; // offset of section header table + if (shoff) { + Elf32_Shdr * shdr = ELFADDR(Elf32_Shdr, eh, shoff); + + int shnum = eh->e_shnum; // number of section headers + + // e_shnum will be 0 if the number of sections is >= SHN_LORESERVE (0xff00) + // If this is the case, sh_size contains the actual number of section headers. + // If sh_size is 0, there really aren't any section headers. + if (!shnum) + shnum = shdr->sh_size; + + int shstrndx = eh->e_shstrndx; + + // If the section name string table index is >= SHN_LORESERVE (0xff00), shstrndx + // contains SHN_XINDEX (0xffff). + // If this is the case, sh_link contains the actual index of the section name string + // table, otherwise sh_link is 0. + + if (shstrndx >= 65535) + shstrndx = shdr->sh_link; + + // Initialize list of global data symbols + InitSymbolsLists(eh,shdr,shnum); + + int snameoffset = shdr[shstrndx].sh_offset; // offset in file of sections' names + char * sname = ELFADDR(char, eh, snameoffset); + for (int i = 0; i < shnum; i++) { + if (i != shstrndx) { + if (!strcmp(".directive", &sname[shdr[i].sh_name])) { + // we're in business. print the section to stdout + char * data = ELFADDR(char, eh, shdr[i].sh_offset); + int size = shdr[i].sh_size; + PrintExportsFromSection(data, size); + } + } + } + } +} + +void PrintABIv2ExportSymbols(Elf32_Ehdr *eh) +{ + int shoff = eh->e_shoff; // offset of section header table + if (shoff) { + Elf32_Shdr * shdr = ELFADDR(Elf32_Shdr, eh, shoff); + int i=0; + + int shnum = eh->e_shnum; // number of section headers + + // e_shnum will be 0 if the number of sections is >= SHN_LORESERVE (0xff00) + // If this is the case, sh_size contains the actual number of section headers. + // If sh_size is 0, there really aren't any section headers. + if (!shnum) + shnum = shdr->sh_size; + + int shstrndx = eh->e_shstrndx; + + // If the section name string table index is >= SHN_LORESERVE (0xff00), shstrndx + // contains SHN_XINDEX (0xffff). + // If this is the case, sh_link contains the actual index of the section name string + // table, otherwise sh_link is 0. + + if (shstrndx >= 65535) + shstrndx = shdr->sh_link; + + //Get the symbol table + Elf32_Sym * symtab = 0; + int nSyms = 0; + char * strtab = 0; + + for (i = 0; (i < shnum); i++) { + if (shdr[i].sh_type == SHT_DYNSYM) { + symtab = ELFADDR(Elf32_Sym, eh, shdr[i].sh_offset); + nSyms = shdr[i].sh_size / shdr[i].sh_entsize; + strtab = ELFADDR(char, eh, shdr[shdr[i].sh_link].sh_offset); + break; + } + } + for (i = 0; i < nSyms; i++) { + if (symtab[i].st_info == ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT)) { + char * name = ELFADDR(char, strtab, symtab[i].st_name); + char * CodeSection = ELFADDR(char, eh, shdr[symtab[i].st_shndx].sh_offset); + Elf32_Word *aLocation = ELFADDR(Elf32_Word, CodeSection, symtab[i].st_value); + int ordinal = *aLocation; + fprintf(OUTFILE, "%s %d DATA %d %d\n",name, ordinal, symtab[i].st_size); + } else if (symtab[i].st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)) { + char * name = ELFADDR(char, strtab, symtab[i].st_name); + char * CodeSection = ELFADDR(char, eh, shdr[symtab[i].st_shndx].sh_offset); + Elf32_Word *aLocation = ELFADDR(Elf32_Word, CodeSection, symtab[i].st_value); + int ordinal = *aLocation; + fprintf(OUTFILE, "%s %d \n",name, ordinal); + } + } + } +} + +void PrintSONAME(Elf32_Ehdr *eh) +{ + int shoff = eh->e_shoff; // offset of section header table + if (shoff) { + Elf32_Shdr * shdr = ELFADDR(Elf32_Shdr, eh, shoff); + + int shnum = eh->e_shnum; // number of section headers + + // e_shnum will be 0 if the number of sections is >= SHN_LORESERVE (0xff00) + // If this is the case, sh_size contains the actual number of section headers. + // If sh_size is 0, there really aren't any section headers. + if (!shnum) + shnum = shdr->sh_size; + + int shstrndx = eh->e_shstrndx; + char *aSHdrStrTab = ELFADDR(char, eh, shdr[shstrndx].sh_offset); + int i=0; + Elf32_Verdef *aVerDef = 0; + char *aStringTab = 0; + for(i = 0; i < shnum; i++) { + if(strcmp(aSHdrStrTab + shdr[i].sh_name, ".version_d") == 0) { + aVerDef = ELFADDR(Elf32_Verdef,eh , shdr[i].sh_offset ); + aStringTab = ELFADDR(char, eh, shdr[shdr[i].sh_link].sh_offset); + break; + } + } + if(!aVerDef) + return; + char *aLinkAsName; + while(aVerDef) { + if(aVerDef->vd_ndx == DEFAULT_VERSION){ + Elf32_Verdaux *aVerAux = ELFADDR(Elf32_Verdaux, aVerDef, aVerDef->vd_aux); + aLinkAsName = ELFADDR(char, aStringTab, aVerAux->vda_name); + fprintf(OUTFILE, "%s \n", aLinkAsName); + break; + } + aVerDef = ELFADDR(Elf32_Verdef, aVerDef, aVerDef->vd_next); + } + } +} + +int main(int argc, char** argv) +{ + if( argc < 2 ) + { + return EXIT_FAILURE; + } + + char* file = argv[argc - 1];//The last arg is the file name + int idx = 0; + bool outFileOpt = false; + bool proxyDso = false; + bool soname = false; + while(idx < argc ) + { + if((stricmp(argv[idx], "-o") == 0) && ((idx + 1) < argc) ) + { + idx++; + char *outfilename = argv[idx]; + OUTFILE = fopen(outfilename, "wb"); + outFileOpt = true; + } + else if(stricmp(argv[idx], "-d") == 0) + { + proxyDso = true; + } + else if(stricmp(argv[idx], "-s") == 0) + { + soname = true; + } + idx++; + } + + if(!outFileOpt) + { + OUTFILE = stdout; + } + + Elf32_Ehdr * eh = OpenElfFile(file); + + if( soname ) { + PrintSONAME(eh); + } + else if( !proxyDso ) { + PrintABIv1ExportSymbols(eh); + } + else { + PrintABIv2ExportSymbols(eh); + } + return EXIT_SUCCESS; +} + + + + + +