bintools/elftools/getexports/geninf.cpp
changeset 0 044383f39525
child 590 360bd6b35136
--- /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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+#include <elfdefs.h>
+#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 "#<SYMEDIT>#"
+#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;
+}
+  
+
+  
+
+  
+