kerneltest/e32utils/analyse/symbols.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2000-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 "analyse.h"
#include "symbols.h"

#ifdef __MSVCDOTNET__
#include <fstream>
#else //!__MSVCDOTNET__
#include <fstream.h>
#endif //__MSVCDOTNET__

namespace {
unsigned ParseHex(const char* aText, int aLength)
	{
	unsigned value = 0;
	const char* end = aText + aLength;
	do
		{
		unsigned c = *aText++ - '0';
		if (c > 9)
			c -= 'a' - '0' - 10;
		value = (value << 4) + c;
		} while (aText < end);
	return value;
	}
};


// class SymbolFile

SymbolFile::SymbolFile(const char* aSymbolFile, bool aRofs)
	:iText(0), iTextLower(0)
	{
	ifstream file;
#ifdef __MSVCDOTNET__
	file.open(aSymbolFile, ios::binary);
#else //!__MSVCDOTNET__
	file.open(aSymbolFile, ios::nocreate | ios::binary);
#endif //__MSVCDOTNET__
	if (!file)
		{
		cerr << "Unable to open ROM symbol file '" << aSymbolFile << '\'' << endl;
		Analyse::Abort();
		}
//
	file.seekg(0, ios::end);
	iLength = file.tellg();
//
	iText = new char[iLength+1];
	file.seekg(0, ios::beg);
	file.read(iText, iLength);
	iText[iLength] = '\0';
//
	file.close();

	if (aRofs)
		{
		iTextLower = new char[iLength+1];
		for(char *p = iTextLower, *c = iText, *end = iText + iLength;c < end;c++, p++) 
			*p = tolower(*c);
		}
	}

SymbolFile::~SymbolFile()
	{
	delete [] iText;
	if (iTextLower)
		delete [] iTextLower;
	}

bool SymbolFile::Parse(SymbolFile::Parser& aParser, const char* aModuleName, PC aAddress, PC aModuleLength, int aModuleId) const
	{
	char* text = 0;
	PC first_pc_limit = 0, last_pc_limit = 0;
	TState state = EPreFile;
	PC lastPC = 0;
	bool inSyms = false;
	const char *prevName = 0;
	int lastLen = 0;

	if (aModuleName) // should parse only one module 
		{
		bool not_found = false;
		char * name = strstr(iTextLower, aModuleName);
		if (name)
			{
			for(char * p = name; p != iTextLower && *p != '\n';p--);
			if (*p == '\n' || p == iTextLower) 
				{
				name = ++p;
				text = iText + (name - iTextLower);
				}
			else
				not_found = true;
			}
		else
			not_found = true;

		if (not_found)
			return false;

		state = EFile;
		}
	else
		text = iText;
		
	const char* end = iText + iLength;
	while (text < end && state != EError)
		{
		char* endl = strchr(text, '\r');
		if (endl == 0)
			{
			if (!aModuleName)
				{
				state = EError;
				break;
				}
			else
				{
				char* p = text + strlen(text);
				if (*(p+1) == '\n')
					endl = p;
				else
					{
					state = EError;
					break;
					}
				}
			}
		switch (state)
			{
		case EPreFile:
			if (endl != text)
				state = EError;
			else
				state = EFile;
			break;
		case EFile:
			if (strncmp(text, "From", 4) != 0)
				state = EError;
			else
				{
				*endl = '\0';
				char* name = strrchr(text, '\\');
				if (name == 0)
					name = text + 8;
				else
					++name;
				aParser.File(name);
				state = EPostFile;
				}
			break;
		case EPostFile:
			if (endl != text)
				state = EError;
			else
				state = ESymbol;
			break;
		case ESymbol:
			if (text == endl)
				{
				if (aModuleName)
					goto Quit; 
				else
					state = EFile;
				}
			else
				{
				PC pc = ParseHex(text, 8);
				pc &= ~1; // should be odd address, error in symbol table

				if(aModuleName)
					pc += aAddress;

				*endl = '\0';

				char* codeType = strrchr(text+20, '(');

				if ( codeType == NULL || (strcmp(codeType,"(.data)") != 0 &&
					 strcmp(codeType,"(.bss)") != 0 &&
					 strcmp(codeType,"(.init_array)") != 0 &&
					 strcmp(codeType,"(linker$$defined$$symbols)") != 0 &&
					 strcmp(codeType,"(ExportTable)") != 0) )
					{
					if(inSyms && (pc > (lastPC + lastLen)))
						{
						memcpy((void *)(prevName - 15), "<static> after ", 15);
						aParser.Symbol(prevName - 15, lastPC + lastLen, pc - (lastPC + lastLen));
						}

					int length = ParseHex(text + 12, 4);

					if(pc >= lastPC + lastLen)
						{
						bool is_added = aParser.Symbol(text + 20, pc, length);
						if (is_added && aModuleName && !first_pc_limit) 
							{
							first_pc_limit = pc + length;
							last_pc_limit = pc + aModuleLength;
							}
						}

					prevName = text + 20;
					if(pc + length > lastPC + lastLen)
						{
						lastLen = length;
						lastPC = pc;
						}
					inSyms = true;
					}
				}
			break;
		case EError:
			break;
			}
		text = endl + 2;
		}
	if (state == EError)
		Analyse::Abort("Bad ROM symbol file format");

Quit:
	if(aModuleName && lastPC == first_pc_limit && (lastPC + lastLen) < last_pc_limit)
		{
		memcpy((void *)(prevName - 10), "<anon> in ", 10);
		aParser.Symbol(prevName - 10, lastPC + lastLen, last_pc_limit - (lastPC + lastLen));
		}
	aParser.Done(first_pc_limit, last_pc_limit, aModuleId);

	return true;
	}