toolsandutils/e32tools/elftools/elftran/elf_file.cpp
changeset 0 83f4b4db085c
child 1 d4b442d23379
equal deleted inserted replaced
-1:000000000000 0:83f4b4db085c
       
     1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 
       
    17 #include <e32def.h>
       
    18 #include <e32def_private.h>
       
    19 #include <e32std.h>
       
    20 #include <e32std_private.h>
       
    21 #include "elftran.h"
       
    22 #include <tools/elfdefs.h>
       
    23 #include "elffile.h"
       
    24 #include "elfdll.h"
       
    25 #include "h_utl.h"
       
    26 #include <string.h>
       
    27 #include <stdlib.h>
       
    28 
       
    29 TBool hadText, hadReloc = EFalse;
       
    30 
       
    31 ELFFile::ELFFile() 
       
    32 	: iFileName(0), iFileHandle(-1) , iElfFile(0),
       
    33 	iHeapCommittedSize(0x1000), iHeapReservedSize(0x100000), iStackCommittedSize(0),
       
    34 	iCodeSegmentHdr(0), iDataSegmentHdr(0), iDynamicSegmentHdr(0),
       
    35 	iCodeSegmentIdx(0), iDataSegmentIdx(0),
       
    36 	iDynamicSegmentIdx(0), iDllData(0), iCpu(ECpuUnknown)
       
    37 	{}
       
    38 
       
    39 
       
    40 
       
    41 
       
    42 ELFFile::~ELFFile()
       
    43 //
       
    44 // Destructor
       
    45 //
       
    46 	{
       
    47 
       
    48 	delete [] iFileName;
       
    49 	delete iElfFile;
       
    50 	delete iDllData;
       
    51 	}
       
    52 
       
    53 
       
    54 TBool ELFFile::Init(const TText * const aFileName)
       
    55 //
       
    56 // Read the ELF file into memory
       
    57 //
       
    58  	{
       
    59 
       
    60  	delete [] iFileName;	
       
    61 	iFileName = new TText[strlen((const char *)aFileName)+1];
       
    62 	strcpy ((char *)iFileName, (const char *)aFileName);
       
    63 
       
    64 	TInt error = HFile::Open(iFileName, &iFileHandle);
       
    65 	if (error!=0)
       
    66 		return EFalse;
       
    67 
       
    68 	TInt flength = HFile::GetLength(iFileHandle);
       
    69 
       
    70 	iElfFile = (Elf32_Ehdr *)HMem::Alloc(0,flength);
       
    71 	if (!iElfFile)
       
    72 		{
       
    73 		Print(EPeError,"Failed to allocate memory to read in file.\n");
       
    74 		Close();
       
    75 		return EFalse;
       
    76 		}
       
    77 
       
    78 	if (!HFile::Read(iFileHandle,iElfFile,flength))
       
    79 		{
       
    80 		Print(EPeError,"Unable to read file %s.\n",iFileName);
       
    81 		Close();
       
    82 		return EFalse;
       
    83 		}
       
    84 
       
    85         Close();
       
    86 
       
    87 	if (!IsValidFileHeader(iElfFile))
       
    88 		{
       
    89 		Print(EPeError,"Invalid file header.\n");
       
    90 		return EFalse;
       
    91 		}
       
    92 	// we only support this....for the moment
       
    93 	iCpu = ECpuArmV4;
       
    94 
       
    95 	if (!InitHeaders()) return EFalse;
       
    96 	
       
    97 	if (!InitDllData()) return EFalse;
       
    98 
       
    99 	iEntryPoint = iElfFile->e_entry;
       
   100 
       
   101 	iCodeSize = GetCodeSize();
       
   102 	iDataSize = GetDataSize();
       
   103 	iBssSize = GetBssSize();
       
   104 
       
   105 	iStackReservedSize = 0x2000;
       
   106 	iStackCommittedSize = 0x2000;
       
   107 
       
   108  	iLinkedBase = iCodeSegmentHdr->p_vaddr;
       
   109 	
       
   110 	iImageIsDll = iDllData->ImageIsDll();
       
   111 
       
   112 	return ETrue;
       
   113 	}
       
   114 
       
   115 char * ELFFile::CreateImportSection(TInt &aSize)
       
   116 //
       
   117 // get ELFDLLData to do it
       
   118 //
       
   119 	{
       
   120 	TInt size;
       
   121 	char * newSection = iDllData->CreateImportSection(size);
       
   122 	aSize = size;
       
   123 	return newSection;
       
   124 	}
       
   125 
       
   126 TUint ELFFile::GetExportTableOffset(void)
       
   127         {
       
   128 	return iDllData->GetExportTableOffset();
       
   129 	}
       
   130 
       
   131 TBool ELFFile::InitHeaders(void)
       
   132         {
       
   133 	TInt nphdrs = iElfFile->e_phnum;
       
   134 	if (nphdrs)
       
   135 	       {
       
   136 	       // Find the dynamic segment
       
   137 	       Elf32_Phdr * aPhdr = ELFADDR(Elf32_Phdr, iElfFile, iElfFile->e_phoff);
       
   138 	       iPhdr = aPhdr;
       
   139 	       for (TInt idx = 0; idx < nphdrs; idx++)
       
   140 					{
       
   141 					Elf32_Word ptype = aPhdr[idx].p_type;
       
   142 					if (ptype == PT_DYNAMIC)
       
   143 							{
       
   144 							iDynamicSegmentHdr = &aPhdr[idx];
       
   145 							iDynamicSegmentIdx = idx;
       
   146 							}
       
   147       				else if (ptype == PT_LOAD && 
       
   148 							 (aPhdr[idx].p_flags & (PF_X + PF_ARM_ENTRY)))
       
   149 							{
       
   150 							iCodeSegmentHdr = &aPhdr[idx];
       
   151 							iCodeSegmentIdx = idx;
       
   152 							}
       
   153       				else if (ptype == PT_LOAD && 
       
   154 							 (aPhdr[idx].p_flags & (PF_W + PF_R)))
       
   155 							{
       
   156 							iDataSegmentHdr = &aPhdr[idx];
       
   157 							iDataSegmentIdx = idx;
       
   158 							}
       
   159 					}
       
   160 	       }
       
   161 	
       
   162 	// cache pointer to symbol table
       
   163 
       
   164 	// Get section header table
       
   165 	Elf32_Shdr * s = ELFADDR(Elf32_Shdr, iElfFile, iElfFile->e_shoff);
       
   166 	// Index of section header for section header string table
       
   167 	TInt stIdx = iElfFile->e_shstrndx;
       
   168 	TInt symIdx = -1;
       
   169 	// Section name string table
       
   170 	char * stringtable = ELFADDR(char, iElfFile, s[stIdx].sh_offset);
       
   171 	// the index at which we find '.symtab' is the index of the symtab section
       
   172 	for (TInt idx = 0; idx < iElfFile->e_shnum; idx++)
       
   173 	    {
       
   174 		if (idx != stIdx)
       
   175 		       {
       
   176 		       if (!strcmp(&stringtable[s[idx].sh_name], ".symtab"))
       
   177 			      {
       
   178 			      symIdx = idx;
       
   179 			      break;
       
   180 			      }
       
   181 		       }
       
   182 		}
       
   183 	if (symIdx == -1) return EFalse;
       
   184 
       
   185 	// save section header table
       
   186 	iSectionHeaderTable = s;
       
   187 	// save the index
       
   188 	iSymIdx = symIdx;	
       
   189 	// here's the symbol table
       
   190 	iSymTab = ELFADDR(Elf32_Sym, iElfFile, s[symIdx].sh_offset);
       
   191 	return ETrue;
       
   192 	}
       
   193 
       
   194 TBool ELFFile::InitDllData(void)
       
   195 	{
       
   196 	if (!iDynamicSegmentHdr)
       
   197 	       {
       
   198 #if defined(_DEBUG)
       
   199 	       Print(EWarning, "Image '%s' has no import/export data.\n", iFileName);
       
   200 #endif
       
   201 	       return ETrue;
       
   202 	       }
       
   203 	iDllData = new ELFDllData(this);
       
   204 	if (!iDllData)
       
   205 	       {
       
   206 	       Print(EPeError, "Out of memory allocating DLL data\n");
       
   207 	       return EFalse;
       
   208 	       }
       
   209 
       
   210 	Elf32_Dyn * dyn = ELFADDR(Elf32_Dyn, iElfFile, iDynamicSegmentHdr->p_offset);
       
   211 	TInt idx = 0;
       
   212 	TInt soNameOffset = 0;
       
   213 	while(dyn[idx].d_tag != DT_NULL) // best to make it explicit
       
   214 	       {
       
   215 	       switch (dyn[idx].d_tag)
       
   216 		      {
       
   217 		      case DT_HASH:
       
   218 			   iDllData->iHashTable = ELFADDR(Elf32_HashTable, dyn, dyn[idx].d_val);
       
   219 			   break;
       
   220 		      case DT_STRTAB:
       
   221 			   iDllData->iDynStrTab = ELFADDR(char, dyn, dyn[idx].d_val);
       
   222 			   break;
       
   223 		      case DT_SYMTAB:
       
   224 			   iDllData->iDynSymTab = ELFADDR(Elf32_Sym, dyn, dyn[idx].d_val);
       
   225 			   break;
       
   226 		      case DT_RELA:
       
   227 			   iDllData->iRela = ELFADDR(Elf32_Rela, dyn, dyn[idx].d_val);
       
   228 			   break;
       
   229 		      case DT_RELASZ:
       
   230 			   iDllData->iRelaSz = dyn[idx].d_val;
       
   231 			   break;
       
   232 		      case DT_RELAENT:
       
   233 			   iDllData->iRelaSz = dyn[idx].d_val;
       
   234 			   break;
       
   235 		      case DT_STRSZ:
       
   236 			   iDllData->iDynStrTabSize = dyn[idx].d_val;
       
   237 			   break;
       
   238 		      case DT_ARM_SYMTABSZ_21: //For RVCT2.1
       
   239 			   //iDllData->iDynSymTabSize = dyn[idx].d_val;
       
   240 		      case DT_ARM_SYMTABSZ:
       
   241 			  /* This is same as DT_ARM_SYMTABSZ_21, but for RVCT 2.2
       
   242 			   * The tag value has been changed for RVC2.2 from RVCT2.1.
       
   243 			   * We just ignore this. i.e., we get the symbol table size
       
   244 			   * from the nchain field of the hash table as noted in section
       
   245 			   * 3.2.2.2 of the BPABI.
       
   246 			   */
       
   247 			   break;
       
   248 		      case DT_SYMENT:
       
   249 			   iDllData->iSymSize = dyn[idx].d_val;
       
   250 			   break;
       
   251 		      case DT_SONAME:
       
   252 			   soNameOffset = dyn[idx].d_val;
       
   253 			   break;
       
   254 		      case DT_REL:
       
   255 			   iDllData->iRel = ELFADDR(Elf32_Rel, dyn, dyn[idx].d_val);
       
   256 			   break;
       
   257 		      case DT_RELSZ:
       
   258 			   iDllData->iRelSz = dyn[idx].d_val;
       
   259 			   break;
       
   260 		      case DT_RELENT:
       
   261 			   iDllData->iRelEnt = dyn[idx].d_val;
       
   262 			   break;
       
   263 		      case DT_NEEDED:
       
   264 			   iDllData->AddToDependency(dyn[idx].d_val);
       
   265 			   break;
       
   266 		      case DT_PLTRELSZ:
       
   267 		      case DT_PLTGOT:
       
   268 		      case DT_INIT:
       
   269 		      case DT_FINI:
       
   270 		      case DT_RPATH:
       
   271 		      case DT_SYMBOLIC:
       
   272 		      case DT_PLTREL:
       
   273 		      case DT_DEBUG:
       
   274 		      case DT_TEXTREL:
       
   275 		      case DT_JMPREL:
       
   276 		      case DT_BIND_NOW:
       
   277 			   break;
       
   278 		      default:
       
   279 		           Print(EPeError,"Unrecognized Dyn Array tag in image '%s'.\n", iFileName);
       
   280 			   return EFalse;
       
   281 		      }
       
   282 		      idx++;
       
   283 	       }
       
   284 	return iDllData->Init();
       
   285 	}
       
   286 
       
   287 
       
   288 void ELFFile::Close()
       
   289 //
       
   290 // close the ELF file
       
   291 //
       
   292 	{
       
   293 	HFile::Close(iFileHandle);
       
   294 	}
       
   295 
       
   296 
       
   297 
       
   298 TInt ELFFile::NumberOfImports() const
       
   299 //
       
   300 // Count the total number of imports for this image
       
   301 //
       
   302 	{
       
   303 	return iDllData->NumberOfImports();
       
   304 	}
       
   305 
       
   306 TInt ELFFile::NumberOfImportDlls() const
       
   307 //
       
   308 // Count the number of referenced Dlls
       
   309 //
       
   310 	{
       
   311 	return iDllData->NumberOfImportDlls();
       
   312 	}
       
   313 
       
   314 TInt ELFFile::NumberOfExports() const
       
   315 //
       
   316 // Count the number of exported symbols
       
   317 //
       
   318 	{
       
   319 	return iDllData->NumberOfExports();
       
   320 	}
       
   321 
       
   322 TInt ELFFile::NumberOfCodeRelocs() 
       
   323 	{ 
       
   324 	return iDllData->NumberOfCodeRelocs(); 
       
   325 	}
       
   326 
       
   327 TInt ELFFile::NumberOfDataRelocs() 
       
   328 	{ 
       
   329 	return iDllData->NumberOfDataRelocs(); 
       
   330 	}
       
   331 
       
   332 Elf32_Phdr * ELFFile::GetSegmentFromAddr(Elf32_Addr addr)
       
   333 	{
       
   334 	TInt nphdrs = iElfFile->e_phnum;
       
   335 	for (TInt idx = 0; idx < nphdrs; idx++)
       
   336 	        {
       
   337 		// take advantage of unsignedness 
       
   338 		if ((addr - iPhdr[idx].p_vaddr) < iPhdr[idx].p_memsz) return &iPhdr[idx];
       
   339 		}
       
   340 	return NULL;
       
   341 	}
       
   342 
       
   343 
       
   344 TInt ELFFile::NumberOfRelocs()
       
   345 	{
       
   346 	return iDllData->NumberOfRelocs();
       
   347 	}
       
   348 
       
   349 TUint16 ELFFile::GetRelocType(Elf32_Rel *aReloc)
       
   350     {
       
   351 	// We work out the type by figuring out the segment of the reloc
       
   352 	TInt segmentIdx = ELF32_R_SYM(aReloc->r_info);
       
   353 	
       
   354 	// check to see if its a reserved or special index.
       
   355 	if ((!segmentIdx) || ((segmentIdx >= SHN_LORESERVE) && (segmentIdx <= SHN_HIRESERVE)))
       
   356 		// up until now these have been treated as KInferredRelocType, so lets continue...
       
   357 		return KInferredRelocType;
       
   358 			
       
   359 	// need to see if this section is executable or writable
       
   360 	if (iPhdr[segmentIdx-1].p_flags & PF_X) 
       
   361 		return KTextRelocType;
       
   362 	if (iPhdr[segmentIdx-1].p_flags & PF_W) 
       
   363 		return KDataRelocType;
       
   364 	// perhaps we should error here.
       
   365 	return KInferredRelocType;
       
   366 	}
       
   367 
       
   368 TBool ELFFile::GetRelocs(Elf32_Rel **aCodeRelocs, Elf32_Rel **aDataRelocs)
       
   369         {
       
   370 	return iDllData->GetRelocs(aCodeRelocs, aDataRelocs);
       
   371 	}
       
   372 
       
   373 TUint ELFFile::GetCodeSize()
       
   374     {
       
   375 	return iCodeSegmentHdr->p_filesz;
       
   376 	}
       
   377 
       
   378 TBool ELFFile::HasInitialisedData()
       
   379 	{
       
   380 	return iDataSegmentHdr != NULL && iDataSegmentHdr->p_filesz != 0;
       
   381 	}
       
   382 
       
   383 TUint ELFFile::GetDataSize()
       
   384     {
       
   385 	return iDataSegmentHdr != NULL ? iDataSegmentHdr->p_filesz : 0;
       
   386 	}
       
   387 
       
   388 TBool ELFFile::HasBssData()
       
   389 	{
       
   390 	return iDataSegmentHdr != NULL && (iDataSegmentHdr->p_memsz - iDataSegmentHdr->p_filesz) != 0;
       
   391 	}
       
   392 
       
   393 TUint ELFFile::GetBssSize()
       
   394     {
       
   395 	return iDataSegmentHdr != NULL ? iDataSegmentHdr->p_memsz - iDataSegmentHdr->p_filesz: 0;
       
   396 	}
       
   397 
       
   398 
       
   399 
       
   400 
       
   401 
       
   402 
       
   403 TBool ELFFile::IsValidFileHeader(Elf32_Ehdr * iElfFile)
       
   404  	{
       
   405         if (!(iElfFile->e_ident[EI_MAG0] == ELFMAG0 &&
       
   406 	      iElfFile->e_ident[EI_MAG1] == ELFMAG1 &&
       
   407 	      iElfFile->e_ident[EI_MAG2] == ELFMAG2 &&
       
   408 	      iElfFile->e_ident[EI_MAG3] == ELFMAG3))
       
   409 		{
       
   410                 Print(EPeError,"Invalid ELF magic.\n");
       
   411 		return EFalse;
       
   412 		}
       
   413 
       
   414         if (iElfFile->e_ident[EI_CLASS] != ELFCLASS32)
       
   415 		{
       
   416                 Print(EPeError,"File is not a 32 bit object file.\n");
       
   417 		return EFalse;
       
   418 		}
       
   419         if (iElfFile->e_ident[EI_DATA] != ELFDATA2LSB)
       
   420 		{
       
   421                 Print(EPeError,"File data encoding is not Little Endian.\n");
       
   422 		return EFalse;
       
   423 		}
       
   424 
       
   425   	if (iElfFile->e_machine != EM_ARM)
       
   426 		{
       
   427 		Print(EPeError,"File does not target ARM/THUMB processors.\n");
       
   428 		return EFalse;
       
   429 		}
       
   430 
       
   431   	if (!(iElfFile->e_type == ET_EXEC || iElfFile->e_type == ET_DYN))
       
   432 		{
       
   433 		Print(EPeError,"File is neither an executable nor a shared object\n");
       
   434 		return EFalse;
       
   435 		}
       
   436 
       
   437 	return ETrue;
       
   438 	}
       
   439 
       
   440 
       
   441 // Get details of the next import to fix-up in the current file. Fill in the name of the dll 
       
   442 //it is imported from, the ordinal number and the address to write back to.
       
   443 #define ORDINAL_DONE 0x40000000
       
   444 
       
   445 
       
   446 // The following static functions are passed an array of PE files to operate on
       
   447 
       
   448 Elf32_Sym * ELFFile::FindSymbol(const TText *aName)
       
   449     {
       
   450 	Elf32_Shdr * s = ELFADDR(Elf32_Shdr, iElfFile, iElfFile->e_shoff);	
       
   451 	TInt symIdx = iSymIdx;
       
   452 	Elf32_Sym * sym = iSymTab;
       
   453 	TInt nSyms = s[symIdx].sh_size / s[symIdx].sh_entsize;
       
   454 	char * symStringtable = ELFADDR(char, iElfFile, s[s[symIdx].sh_link].sh_offset);
       
   455 	for (TInt jdx = 0; jdx < nSyms; jdx++)
       
   456 	    {
       
   457 		if (!strcmp(&symStringtable[sym[jdx].st_name], (char *)aName)) 
       
   458 			return &sym[jdx];
       
   459 		}
       
   460 	return (Elf32_Sym *)0;
       
   461     }
       
   462 
       
   463 TBool ELFFile::SymbolPresent(TText *aName)
       
   464     {
       
   465 	return (FindSymbol(aName) != 0);
       
   466     }
       
   467 
       
   468 TBool ELFFile::GetExceptionIndexInfo(TUint32 &aOffset)
       
   469     {
       
   470     const TText * aBase = (TText *)".ARM.exidx$$Base";
       
   471     const TText * aLimit = (TText *)".ARM.exidx$$Limit";
       
   472 	Elf32_Sym * exidxBase = FindSymbol(aBase);
       
   473 	Elf32_Sym * exidxLimit = FindSymbol(aLimit);
       
   474 	if (exidxBase && exidxLimit && (exidxLimit->st_value - exidxBase->st_value)) 
       
   475 	    {
       
   476 		const TText * aExceptionDescriptor = (TText *)"Symbian$$CPP$$Exception$$Descriptor";
       
   477 		Elf32_Sym * aED = FindSymbol(aExceptionDescriptor);
       
   478 		if (aED) 
       
   479 			{
       
   480 			// Set bottom bit so 0 in header slot means an old binary.
       
   481 			// The decriptor is always aligned on a 4 byte boundary.
       
   482 			aOffset = (aED->st_value - iLinkedBase) | 0x00000001;
       
   483 			return ETrue;
       
   484 			}
       
   485 		else
       
   486 			{
       
   487 			Print(EPeError,"Executable has exception table but no exception descriptor\n");
       
   488 			exit(666);
       
   489 			}
       
   490 		}
       
   491 	return EFalse;
       
   492     }
       
   493 
       
   494 TBool ELFFile::SetUpLookupTable()
       
   495 {
       
   496 	if(!iDllData->CreateSymLookupTable() ) {
       
   497 		Print(EPeError,"Failed to create named symbol lookup information\n");
       
   498 		return FALSE;
       
   499 	}
       
   500 	if(!iDllData->CreateDependency()){
       
   501 		Print(EPeError,"Failed to create dependency ordering for named symbol lookup\n");
       
   502 		return FALSE;
       
   503 	}
       
   504 
       
   505 	iDllData->SetExportSymInfo();
       
   506 	return TRUE;
       
   507 }
       
   508 
       
   509 void ELFFile::GetExportSymInfoHeader(E32EpocExpSymInfoHdr& aSymInfoHdr)
       
   510 {
       
   511 	iDllData->GetExportSymInfoHeader(aSymInfoHdr);
       
   512 }
       
   513 
       
   514 void ELFFile::SetLookupTblBase(TInt aBaseOffset)
       
   515 {
       
   516 	iDllData->SetLookupTblBase(aBaseOffset);
       
   517 }
       
   518 
       
   519 TInt ELFFile::GetLookupTblSize()
       
   520 {
       
   521 	return iDllData->GetLookupTblSize();
       
   522 }
       
   523 
       
   524 TUint ELFFile::GetSymLookupSection(char* aBuff)
       
   525 {
       
   526 	return iDllData->GetSymLookupSection(aBuff);
       
   527 }
       
   528