/*++

Copyright (c) 1998-2001 Klaus P. Gerlicher

Module ModuleName:

    symbols.c

Abstract:

Environment:

    Kernel mode only

Author:

    Klaus P. Gerlicher
	Reactos Port by Eugene Ingerman

Revision History:

    19-Aug-1998:	created
    15-Nov-2000:    general cleanup of source files

Copyright notice:

  This file may be distributed under the terms of the GNU Public License.

--*/

////////////////////////////////////////////////////
// INCLUDES
////
#include "remods.h"
#include "precomp.h"
#include "stab_gnu.h"

#include <ntdll/ldr.h>
#include <ntdll/rtl.h>
#include <internal/ps.h>
#include <internal/ob.h>
#include <internal/module.h>

#define NDEBUG
#include <debug.h>


PVOID pExports=0;
ULONG ulExportLen=0;

LOCAL_VARIABLE local_vars[512];

PICE_SYMBOLFILE_HEADER* apSymbols[32]={NULL,};
ULONG ulNumSymbolsLoaded=0;

ULONG kernel_end=0;

char tempSym[1024]; // temp buffer for output


PULONG LocalRegs[]=
{
    &CurrentEAX,
    &CurrentECX,
    &CurrentEDX,
    &CurrentEBX,
    &CurrentESP,
    &CurrentEBP,
    &CurrentESI,
    &CurrentEDI,
    &CurrentEIP,
    &CurrentEFL
};

typedef struct _VRET
{
	ULONG value;
	ULONG type;
	ULONG father_type;
	ULONG error;
	ULONG file;
    ULONG size;
    ULONG address;
    char name[256];
    char type_name[256];
    BOOLEAN bPtrType;
    BOOLEAN bStructType;
    BOOLEAN bArrayType;
	PICE_SYMBOLFILE_HEADER* pSymbols;
}VRET,*PVRET;

ULONG ulIndex;
LPSTR pExpression;
VRET vr;
VRET vrStructMembers[1024];
ULONG ulNumStructMembers;

BOOLEAN Expression(PVRET pvr);

LIST_ENTRY *pModuleListHead = NULL;
extern PDIRECTORY_OBJECT *pNameSpaceRoot;
extern PDEBUG_MODULE pdebug_module_tail;
extern PDEBUG_MODULE pdebug_module_head;


PVOID HEADER_TO_BODY(POBJECT_HEADER obj)
{
   return(((void *)obj)+sizeof(OBJECT_HEADER)-sizeof(COMMON_BODY_HEADER));
}

POBJECT_HEADER BODY_TO_HEADER(PVOID body)
{
   PCOMMON_BODY_HEADER chdr = (PCOMMON_BODY_HEADER)body;
   return(CONTAINING_RECORD((&(chdr->Type)),OBJECT_HEADER,Type));
}

/*-----------------12/26/2001 7:59PM----------------
 * FreeModuleList - free list allocated with InitModuleList. Must
 * be called at passive irql.
 * --------------------------------------------------*/
VOID FreeModuleList( PDEBUG_MODULE pm )
{
	PDEBUG_MODULE pNext = pm;

	ENTER_FUNC();

	while( pNext ){
		pNext = pm->next;
		ExFreePool( pm );
	}
	LEAVE_FUNC();
}

/*-----------------12/26/2001 7:58PM----------------
 * InitModuleList - creates linked list of length len for debugger. Can't be
 * called at elevated IRQL
 * --------------------------------------------------*/
BOOLEAN InitModuleList( PDEBUG_MODULE *ppmodule, ULONG len )
{
	ULONG i;
	PDEBUG_MODULE pNext = NULL, pm = *ppmodule;

	ENTER_FUNC();

	ASSERT(pm==NULL);

	for(i=1;i<=len;i++){
		pm = (PDEBUG_MODULE)ExAllocatePool( NonPagedPool, sizeof( DEBUG_MODULE ) );
		if( !pm ){
			FreeModuleList(pNext);
			return FALSE;
		}
		pm->next = pNext;
		pm->size = 0;
		pm->BaseAddress = NULL;
		//DbgPrint("len1: %d\n", pm->name.Length);
		pNext = pm;
	}
	*ppmodule = pm;

	LEAVE_FUNC();

	return TRUE;
}

BOOLEAN ListUserModules( PPEB peb )
{
	PLIST_ENTRY UserModuleListHead;
	PLIST_ENTRY Entry;
	PLDR_DATA_TABLE_ENTRY Module;
	PPEB_LDR_DATA Ldr;

	ENTER_FUNC();

	Ldr = peb->Ldr;
	if( Ldr && IsAddressValid((ULONG)Ldr)){
		UserModuleListHead = &Ldr->InLoadOrderModuleList;
		ASSERT(IsAddressValid((ULONG)UserModuleListHead));
		Entry = UserModuleListHead->Flink;
		while (Entry != UserModuleListHead)
		{
			Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
			//DbgPrint("Module: %x, BaseAddress: %x\n", Module, Module->BaseAddress);

			DPRINT((0,"FullName: %S, BaseName: %S, Length: %ld, EntryPoint: %x, BaseAddress: %x\n", Module->FullDllName.Buffer,
					Module->BaseDllName.Buffer, Module->SizeOfImage, Module->EntryPoint, Module->BaseAddress ));

			pdebug_module_tail->size = Module->SizeOfImage;
			pdebug_module_tail->BaseAddress = Module->BaseAddress;
			pdebug_module_tail->EntryPoint = (PVOID)(Module->EntryPoint);
			ASSERT(Module->BaseDllName.Length<DEBUG_MODULE_NAME_LEN); //name length is limited
			PICE_wcscpy( pdebug_module_tail->name, Module->BaseDllName.Buffer );
			pdebug_module_tail = pdebug_module_tail->next;

			Entry = Entry->Flink;
		}
	}
	LEAVE_FUNC();
	return TRUE;
}

POBJECT FindDriverObjectDirectory( void )
{
    PLIST_ENTRY current;
    POBJECT_HEADER current_obj;
	PDIRECTORY_OBJECT pd;

	ENTER_FUNC();

	if( pNameSpaceRoot && *pNameSpaceRoot ){
		current = (*pNameSpaceRoot)->head.Flink;
		while (current!=(&((*pNameSpaceRoot)->head)))
		{
			current_obj = CONTAINING_RECORD(current,OBJECT_HEADER,Entry);
	   	 	DPRINT((0,"Scanning %S\n",current_obj->Name.Buffer));
			if (_wcsicmp(current_obj->Name.Buffer, L"Modules")==0)
			{
				pd=HEADER_TO_BODY(current_obj);
				DPRINT((0,"Found it %x\n",pd));
				return pd;
			}
		  	current = current->Flink;
		}
	}
	LEAVE_FUNC();
	return NULL;
}

BOOLEAN ListDriverModules( void )
{
    PLIST_ENTRY current_entry;
	PMODULE_OBJECT current;
    POBJECT_HEADER current_obj;

	ENTER_FUNC();

	ASSERT( pModuleListHead );

	current_entry = pModuleListHead->Flink;

  	while (current_entry != (pModuleListHead)){

		current = CONTAINING_RECORD(current_entry,MODULE_OBJECT,ListEntry);

		DPRINT((0,"FullName: %S, BaseName: %S, Length: %ld, EntryPoint: %x\n", current->FullName.Buffer,
				current->BaseName.Buffer, current->Length, current->EntryPoint ));

		pdebug_module_tail->BaseAddress = current->Base;
		pdebug_module_tail->size = current->Length;
		PICE_wcscpy( pdebug_module_tail->name, current->BaseName.Buffer);
		pdebug_module_tail->EntryPoint = current->EntryPoint;

		pdebug_module_tail = pdebug_module_tail->next;

		if (current && _wcsicmp(current->BaseName.Buffer, L"ntoskrnl")==0)
		{
		   kernel_end = (ULONG)current->Base + current->Length;
		}
		current_entry = current_entry->Flink;
	}

	LEAVE_FUNC();
	return TRUE;
}

BOOLEAN BuildModuleList( void )
{
 	PPEB peb;
	PEPROCESS tsk;
	ENTER_FUNC();

	pdebug_module_tail = pdebug_module_head;
	tsk = IoGetCurrentProcess();
	ASSERT(IsAddressValid((ULONG)tsk));
	if( tsk  ){
		peb = tsk->Peb;
		if( peb ){
			if( !ListUserModules( peb ) ){
				LEAVE_FUNC();
				return FALSE;
			}
		}
	}
	if( !ListDriverModules() ){
		LEAVE_FUNC();
		return FALSE;
	}
	LEAVE_FUNC();
	return TRUE;
}

//*************************************************************************
// IsModuleLoaded()
//
//*************************************************************************
PDEBUG_MODULE IsModuleLoaded(LPSTR p)
{
    PDEBUG_MODULE pd;

	ENTER_FUNC();
	DPRINT((0,"IsModuleLoaded(%s)\n",p));

    if(BuildModuleList())
    {
        pd = pdebug_module_head;
        do
        {
			char temp[DEBUG_MODULE_NAME_LEN];
            DPRINT((0,"module (%x) %S\n",pd->size,pd->name));
			CopyWideToAnsi(temp,pd->name);
            if(pd->size && PICE_strcmpi(p,temp) == 0)
            {
                DPRINT((0,"module %S is loaded!\n",pd->name));
				LEAVE_FUNC();
				return pd;
            }
        }while((pd = pd->next)!=pdebug_module_tail);
    }
	LEAVE_FUNC();
    return NULL;
}

//*************************************************************************
// ScanExports()
//
//*************************************************************************
BOOLEAN ScanExports(const char *pFind,PULONG pValue)
{
	char temp[256];
	LPSTR pStr=NULL;
	LPSTR pExp = pExports;
	BOOLEAN bResult = FALSE;

	ENTER_FUNC();
	DPRINT((0,"ScanExports pValue: %x\n", pValue));
nomatch:
	if(pExports)
		pStr = strstr(pExp,pFind);

	if(pStr)
	{
		LPSTR p;
		ULONG state;
		LPSTR pOldStr = pStr;

		for(;(*pStr!=0x0a && *pStr!=0x0d) && (ULONG)pStr>=(ULONG)pExports;pStr--);
		pStr++;
		p = temp;
		for(;(*pStr!=0x0a && *pStr!=0x0d);)*p++=*pStr++;
		*p=0;
		p = (LPSTR) PICE_strtok(temp," ");
		state=0;
		while(p)
		{
			switch(state)
			{
				case 0:
					ConvertTokenToHex(p,pValue);
					break;
				case 1:
					break;
				case 2:
					if(strcmp(p,pFind)!=0)
					{
						DPRINT((0,"Not: %s\n", p));
						pExp = pOldStr+1;
						goto nomatch;
					}
					state = -1;
					bResult = TRUE;
		            DPRINT((0,"%s @ %x\n",pFind,*pValue));
					goto exit;
					break;
			}
			state++;
			p = (char*) PICE_strtok(NULL," ");
		}
	}
exit:
	DPRINT((0,"%s %x @ %x\n",pFind,pValue,*pValue));

	LEAVE_FUNC();

	return bResult;
}

//*************************************************************************
// ReadHex()
//
//*************************************************************************
BOOLEAN ReadHex(LPSTR p,PULONG pValue)
{
    ULONG result=0,i;

	for(i=0;i<8 && p[i]!=0 && p[i]!=' ';i++)
	{
		if(p[i]>='0' && p[i]<='9')
		{
			result<<=4;
			result|=(ULONG)(UCHAR)(p[i]-'0');
		}
		else if(p[i]>='A' && p[i]<='F')
		{
			result<<=4;
			result|=(ULONG)(UCHAR)(p[i]-'A'+10);
		}
		else if(p[i]>='a' && p[i]<='f')
		{
			result<<=4;
			result|=(ULONG)(UCHAR)(p[i]-'a'+10);
		}
		else
			return FALSE;
	}

    *pValue = result;
    return TRUE;
}

//*************************************************************************
// ScanExportLine()
//
//*************************************************************************
BOOLEAN ScanExportLine(LPSTR p,PULONG ulValue,LPSTR* ppPtrToSymbol)
{
    BOOLEAN bResult = FALSE;

    if(ReadHex(p,ulValue))
    {
        p += 11;
        *ppPtrToSymbol += 11;
        bResult = TRUE;
    }

    return bResult;
}

//*************************************************************************
// ValidityCheckSymbols()
//
//*************************************************************************
BOOLEAN ValidityCheckSymbols(PICE_SYMBOLFILE_HEADER* pSymbols)
{
	BOOLEAN bRet;

    DPRINT((0,"ValidityCheckSymbols()\n"));

	bRet = (IsRangeValid((ULONG)pSymbols + pSymbols->ulOffsetToHeaders,pSymbols->ulSizeOfHeader) &&
		    IsRangeValid((ULONG)pSymbols + pSymbols->ulOffsetToGlobals,pSymbols->ulSizeOfGlobals) &&
		    IsRangeValid((ULONG)pSymbols + pSymbols->ulOffsetToGlobalsStrings,pSymbols->ulSizeOfGlobalsStrings) &&
		    IsRangeValid((ULONG)pSymbols + pSymbols->ulOffsetToStabs,pSymbols->ulSizeOfStabs) &&
		    IsRangeValid((ULONG)pSymbols + pSymbols->ulOffsetToStabsStrings,pSymbols->ulSizeOfStabsStrings));

    DPRINT((0,"ValidityCheckSymbols(): symbols are %s\n",bRet?"VALID":"NOT VALID"));

	return bRet;
}

//*************************************************************************
// FindModuleSymbols()
//
//*************************************************************************
PICE_SYMBOLFILE_HEADER* FindModuleSymbols(ULONG addr)
{
    ULONG start,end,i;
	PDEBUG_MODULE pd = pdebug_module_head;

    DPRINT((0,"FindModuleSymbols(%x)\n",addr));
    if(BuildModuleList())
    {
        i=0;
        pd = pdebug_module_head;
        do
        {
			DPRINT((0,"pd: %x\n", pd));
            if(pd->size)
			{
                start = (ULONG)pd->BaseAddress;
                end = start + pd->size;
                DPRINT((0,"FindModuleSymbols(): %S %x-%x\n",pd->name,start,end));
                if(addr>=start && addr<end)
                {
                    DPRINT((0,"FindModuleSymbols(): address matches %S %x-%x\n",pd->name,start,end));
                    for(i=0;i<ulNumSymbolsLoaded;i++)
                    {
						DPRINT((0,"%S -", apSymbols[i]->name ));
                        if(PICE_wcsicmp(pd->name,apSymbols[i]->name) == 0)
						{
							if(ValidityCheckSymbols(apSymbols[i]))
	                            return apSymbols[i];
							else
								return NULL;
						}
                    }
                }
            }
        }while((pd = pd->next) != pdebug_module_tail);
    }

    return NULL;
}

//*************************************************************************
// FindModuleFromAddress()
//
//*************************************************************************
PDEBUG_MODULE FindModuleFromAddress(ULONG addr)
{
    PDEBUG_MODULE pd;
    ULONG start,end;

    DPRINT((0,"FindModuleFromAddress()\n"));
    if(BuildModuleList())
    {
        pd = pdebug_module_head;
        do
        {
			if(pd->size)
			{
                start = (ULONG)pd->BaseAddress;
                end = start + pd->size;
                DPRINT((0,"FindModuleFromAddress(): %S %x-%x\n",pd->name,start,end));
                if(addr>=start && addr<end)
                {
                    DPRINT((0,"FindModuleFromAddress(): found %S\n",pd->name));
                    return pd;
                }
            }
        }while((pd = pd->next)!=pdebug_module_tail);
    }

    return NULL;
}

//*************************************************************************
// FindModuleByName()
//
//*************************************************************************
PDEBUG_MODULE FindModuleByName(LPSTR modname)
{
    PDEBUG_MODULE pd;
	WCHAR tempstr[DEBUG_MODULE_NAME_LEN];

    DPRINT((0,"FindModuleFromAddress()\n"));
	if( !PICE_MultiByteToWideChar(CP_ACP, NULL, modname, -1, tempstr, DEBUG_MODULE_NAME_LEN ) )
	{
		DPRINT((0,"Can't convert module name.\n"));
		return NULL;
	}

    if(BuildModuleList())
    {
        pd = pdebug_module_head;
        do
        {
			if(pd->size)
			{
				if(PICE_wcsicmp(tempstr,pd->name) == 0)
                {
                    DPRINT((0,"FindModuleByName(): found %S\n",pd->name));
                    return pd;
                }
            }
        }while((pd = pd->next) != pdebug_module_tail);
    }

    return NULL;
}

//*************************************************************************
// FindModuleSymbolsByModuleName()
//
//*************************************************************************
PICE_SYMBOLFILE_HEADER* FindModuleSymbolsByModuleName(LPSTR modname)
{
    ULONG i;
	WCHAR tempstr[DEBUG_MODULE_NAME_LEN];

    DPRINT((0,"FindModuleSymbols()\n"));
	if( !PICE_MultiByteToWideChar(CP_ACP, NULL, modname, -1, tempstr, DEBUG_MODULE_NAME_LEN ) )
	{
		DPRINT((0,"Can't convert module name in FindModuleSymbols.\n"));
		return NULL;
	}

    for(i=0;i<ulNumSymbolsLoaded;i++)
    {
        if(PICE_wcsicmp(tempstr,apSymbols[i]->name) == 0)
            return apSymbols[i];
    }

    return NULL;
}

//*************************************************************************
// ScanExportsByAddress()
//
//*************************************************************************
BOOLEAN ScanExportsByAddress(LPSTR *pFind,ULONG ulValue)
{
	char temp[256];
    static char temp3[256];
    LPSTR p,pStartOfLine,pSymbolName=NULL;
    ULONG ulCurrentValue=0;
    BOOLEAN bResult = FALSE;
	PDEBUG_MODULE pd;
    ULONG ulMinValue = -1;
	PIMAGE_SYMBOL pSym,pSymEnd;			  		//running pointer to symbols and end of sym talbe
	PIMAGE_SYMBOL pFoundSym = NULL;    	  		//current best symbol match
	ULONG ulAddr = 0x0;		  					//address of the best match
	LPSTR pStr;
	PIMAGE_SECTION_HEADER pShdr;
    PICE_SYMBOLFILE_HEADER* pSymbols;
	ULONG   ulSectionSize;
	LPSTR pName;

	ENTER_FUNC();
	DPRINT((0,"In ScanExportsByAddress:\n"));

    pSymbols = FindModuleSymbols(ulValue);
	DPRINT((0,"pSymbols: %x\n", pSymbols));

	if(BuildModuleList()){
		if(pSymbols && pdebug_module_head)
		{
	        PDEBUG_MODULE pdTemp;

			DPRINT((0,"looking up symbols\n"));
	        pd = pdebug_module_head;
	        do
	        {
				if(pd->size){
					pdTemp = pd;

					if(ulValue>=((ULONG)pdTemp->BaseAddress) && ulValue<((ULONG)pdTemp+pdTemp->size))
					{
						if(PICE_wcsicmp(pdTemp->name,pSymbols->name) == 0)
						{
							DPRINT((0,"ScanExportsByAddress(): found symbols for module %S @ %x \n",pdTemp->name,(ULONG)pSymbols));

							pSym = (PIMAGE_SYMBOL)((ULONG)pSymbols+pSymbols->ulOffsetToGlobals);
							pSymEnd = (PIMAGE_SYMBOL)((ULONG)pSym+pSymbols->ulSizeOfGlobals);
							pStr = (LPSTR)((ULONG)pSymbols+pSymbols->ulOffsetToGlobalsStrings);
							pShdr = (PIMAGE_SECTION_HEADER)((ULONG)pSymbols+pSymbols->ulOffsetToHeaders);

							if(!IsRangeValid((ULONG)pSym,sizeof(IMAGE_SYMBOL) ) ) //should we actually check all the symbols here?
							{
								DPRINT((0,"ScanExportsByAddress(): pSym = %x is not a valid pointer\n",(ULONG)pSym));
								return FALSE;
							}

							DPRINT((0,"ScanExportsByAddress(): pSym = %x\n",pSym));
							DPRINT((0,"ScanExportsByAddress(): pStr = %x\n",pStr));
							DPRINT((0,"ScanExportsByAddress(): pShdr = %x\n",pShdr));

							DPRINT((0,"ScanExportsByAddress(): %S has %u symbols\n",pSymbols->name,pSymbols->ulSizeOfGlobals/sizeof(IMAGE_SYMBOL)));

							/* go through all the global symbols and find the one with
							   the largest address which is less than ulValue */
							while(pSym < pSymEnd)
							{   //it seems only 0x0 and 0x20 are used for type and External or Static storage classes
								if(((pSym->Type == 0x0) || (pSym->Type == 0x20) )  &&
								   ((pSym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) || (pSym->StorageClass==IMAGE_SYM_CLASS_STATIC)) &&
								   (pSym->SectionNumber > 0 ))
								{
									ULONG ulCurrAddr;
									PIMAGE_SECTION_HEADER pShdrThis = (PIMAGE_SECTION_HEADER)pShdr + (pSym->SectionNumber-1);


									DPRINT((0,"ScanExportsByAddress(): pShdr[%x] = %x\n",pSym->SectionNumber,(ULONG)pShdrThis));

									if(!IsRangeValid((ULONG)pShdrThis,sizeof(IMAGE_SECTION_HEADER)) )
									{
										DPRINT((0,"ScanExportsByAddress(): pElfShdr[%x] = %x is not a valid pointer\n",pSym->SectionNumber,(ULONG)pShdrThis));
										return FALSE;
									}
									//to get address in the memory we base address of the module and
									//add offset of the section and then add offset of the symbol from
									//the begining of the section
									ulCurrAddr = ((ULONG)pdTemp->BaseAddress+pShdrThis->VirtualAddress+pSym->Value);
									DPRINT((0,"ScanExportsByAddress(): CurrAddr [1] = %x\n",ulCurrAddr));

									if(ulCurrAddr<=ulValue && ulCurrAddr>ulAddr)
									{
										ulAddr = ulCurrAddr;
										pFoundSym = pSym;
									}
								}
								//skip the auxiliary symbols and get the next symbol
								pSym += pSym->NumberOfAuxSymbols + 1;
							}
							*pFind = temp3;
							if( pFoundSym->N.Name.Short ){
								pName = pFoundSym->N.ShortName;  //name is in the header
								PICE_sprintf(temp3,"%S!%.8s",pdTemp->name,pName); //if name is in the header it may be nonzero terminated
							}
							else{
								ASSERT(pFoundSym->N.Name.Long<=pSymbols->ulSizeOfGlobalsStrings); //sanity check
								pName = pStr+pFoundSym->N.Name.Long;
								if(!IsAddressValid((ULONG)pName))
								{
									DPRINT((0,"ScanExportsByAddress(): pName = %x is not a valid pointer\n",pName));
									return FALSE;
								}
								PICE_sprintf(temp3,"%S!%s",pdTemp->name,pName);
							}
							DPRINT((0,"ScanExportsByAddress(): pName = %x\n",(ULONG)pName));
							return TRUE;
						}
					}
				}
	        }while((pd = pd->next));
		}
	}
	// if haven't found in the symbols try ntoskrnl exports. (note: check that this is needed since we
	// already checked ntoskrnl coff symbol table)
    if(pExports && ulValue >= KERNEL_START && ulValue < kernel_end)
    {
        p = pExports;
        // while we bound in System.map
        while(p<((LPSTR)pExports+ulExportLen))
        {
            // make a temp ptr to the line we can change
            pStartOfLine = p;
            // will read the hex value and return a pointer to the symbol name
            if(ScanExportLine(p,&ulCurrentValue,&pStartOfLine))
            {
                if(ulValue>=ulCurrentValue && (ulValue-ulCurrentValue)<ulMinValue)
                {
                    // save away our info for later
                    ulMinValue = ulValue-ulCurrentValue;
                    pSymbolName = pStartOfLine;
                    bResult = TRUE;
                    *pFind = temp3;
					if(ulMinValue==0)
						break;
                }
            }
            // increment pointer to next line
            p = pStartOfLine;
            while(*p!=0 && *p!=0x0a && *p!=0x0d)p++;
                p++;
        }
        if(bResult)
        {
			int i;
            // copy symbol name to temp string
            for(i=0;pSymbolName[i]!=0 && pSymbolName[i]!=0x0a && pSymbolName[i]!=0x0d;i++)
                temp[i] = pSymbolName[i];
            temp[i] = 0;
            // decide if we need to append an offset
            if(ulMinValue)
                PICE_sprintf(temp3,"ntoskrnl!%s+%.8X",temp,ulMinValue);
            else
                PICE_sprintf(temp3,"ntoskrnl!%s",temp);
        }
    }

	LEAVE_FUNC();
	return bResult;
}

//*************************************************************************
// FindFunctionByAddress()
//
//*************************************************************************
LPSTR FindFunctionByAddress(ULONG ulValue,PULONG pulstart,PULONG pulend)
{
	PIMAGE_SYMBOL pSym, pSymEnd, pFoundSym;
	LPSTR pStr;
	PIMAGE_SECTION_HEADER pShdr;
	PDEBUG_MODULE pd;
	PDEBUG_MODULE pdTemp;
    PICE_SYMBOLFILE_HEADER* pSymbols;
    ULONG start,end;
	static char temp4[256];
	LPSTR pName;

    pSymbols = FindModuleSymbols(ulValue);
    DPRINT((0,"FindFunctionByAddress(): symbols for %S @ %x \n",pSymbols->name,(ULONG)pSymbols));
	if(pSymbols && pdebug_module_head)
	{
		DPRINT((0,"looking up symbol\n"));
        pd = pdebug_module_head;
        do
        {
			ASSERT(pd->size);
            pdTemp = pd;

			//initial values for start and end.
            start = (ULONG)pdTemp->BaseAddress;
            end = start+pdTemp->size;

            DPRINT((0,"FindFunctionByAddress(): ulValue %x\n",ulValue));

			if(ulValue>=start && ulValue<end)
			{
                DPRINT((0,"FindFunctionByAddress(): address matches %S\n",(ULONG)pdTemp->name));
				if(PICE_wcsicmp(pdTemp->name,pSymbols->name) == 0)
				{
					DPRINT((0,"found symbols for module %S\n",pdTemp->name));
					pSym = (PIMAGE_SYMBOL)((ULONG)pSymbols+pSymbols->ulOffsetToGlobals);
					pSymEnd = (PIMAGE_SYMBOL)((ULONG)pSym+pSymbols->ulSizeOfGlobals);
					pStr = (LPSTR)((ULONG)pSymbols+pSymbols->ulOffsetToGlobalsStrings);
					pShdr = (PIMAGE_SECTION_HEADER)((ULONG)pSymbols+pSymbols->ulOffsetToHeaders);

					if(!IsRangeValid((ULONG)pSym,sizeof(IMAGE_SYMBOL) ) ) //should we actually check all the symbols here?
					{
						DPRINT((0,"FindFunctionByAddress(): pSym = %x is not a valid pointer\n",(ULONG)pSym));
						return FALSE;
					}
					DPRINT((0,"pSym = %x\n",pSym));
					DPRINT((0,"pStr = %x\n",pStr));
					DPRINT((0,"pShdr = %x\n",pShdr));

					while( pSym < pSymEnd )
					{
						//symbol is a function is it's type is 0x20, and section>0
						if(( (pSym->Type == 0x20) &&
						   (pSym->SectionNumber > 0 )))
						{
							ULONG ulCurrAddr;
							PIMAGE_SECTION_HEADER pShdrThis = (PIMAGE_SECTION_HEADER)pShdr + (pSym->SectionNumber-1);

							DPRINT((0,"FindFunctionByAddress(): pShdr[%x] = %x\n",pSym->SectionNumber,(ULONG)pShdrThis));

							if(!IsRangeValid((ULONG)pShdrThis,sizeof(IMAGE_SECTION_HEADER)) )
							{
								DPRINT((0,"ScanExportsByAddress(): pElfShdr[%x] = %x is not a valid pointer\n",pSym->SectionNumber,(ULONG)pShdrThis));
								return FALSE;
							}
							//to get address in the memory we base address of the module and
							//add offset of the section and then add offset of the symbol from
							//the begining of the section
							ulCurrAddr = ((ULONG)pdTemp->BaseAddress+pShdrThis->VirtualAddress+pSym->Value);
							DPRINT((0,"FindFunctionByAddress(): CurrAddr [1] = %x\n",ulCurrAddr));
							DPRINT((0,"%x  ", ulCurrAddr));

							if(ulCurrAddr<=ulValue && ulCurrAddr>start)
							{
								start = ulCurrAddr;
								pFoundSym = pSym;
								//DPRINT((0,"FindFunctionByAddress(): CANDIDATE for start %x\n",start));
							}
							else if(ulCurrAddr>=ulValue && ulCurrAddr<end)
								 {
								   end = ulCurrAddr;
								   //DPRINT((0,"FindFunctionByAddress(): CANDIDATE for end %x\n",end));
								 }
							}
							//skip the auxiliary symbols and get the next symbol
							pSym += pSym->NumberOfAuxSymbols + 1;
						}
						//we went through all the symbols for this module
						//now start should point to the start of the function and
						//end to the start of the next (or end of section)
						if(pulstart)
                            *pulstart = start;

                        if(pulend){
							//just in case there is more than  one code section
							PIMAGE_SECTION_HEADER pShdrThis = (PIMAGE_SECTION_HEADER)pShdr + (pFoundSym->SectionNumber-1);
							if( end > (ULONG)pdTemp->BaseAddress+pShdrThis->SizeOfRawData ){
								DPRINT((0,"Hmm: end=%d, end of section: %d\n", end, (ULONG)pdTemp->BaseAddress+pShdrThis->SizeOfRawData));
								end = (ULONG)pdTemp->BaseAddress+pShdrThis->SizeOfRawData;
							}
							*pulend = end;
						}

						if(pFoundSym->N.Name.Short){
							//name is in the header. it's not zero terminated. have to copy.
							PICE_sprintf(temp4,"%.8s", pFoundSym->N.ShortName);
							pName = temp4;
							DPRINT((0,"Function name: %S!%.8s",pdTemp->name,pName));
						}
						else{
							ASSERT(pFoundSym->N.Name.Long<=pSymbols->ulSizeOfGlobalsStrings); //sanity check
							pName = pStr+pFoundSym->N.Name.Long;
							if(!IsAddressValid((ULONG)pName))
							{
								DPRINT((0,"FindFunctionByAddress(): pName = %x is not a valid pointer\n",pName));
								return NULL;
							}
							DPRINT((0,"Function name: %S!%s",pdTemp->name,pName));
						}
						return pName;
					}
				}
        }while((pd = pd->next) != pdebug_module_tail);
	}
	return NULL;
}

//*************************************************************************
// FindDataSectionOffset()
//
//*************************************************************************
/* ei: never used
ULONG FindDataSectionOffset(Elf32_Shdr* pSHdr)
{

    DPRINT((0,"FindDataSectionOffset()\n"));

    while(1)
    {
        DPRINT((0,"FindDataSectionOffset(): sh_offset %.8X sh_addr = %.8X\n",pSHdr->sh_offset,pSHdr->sh_addr));
        if((pSHdr->sh_flags & (SHF_WRITE|SHF_ALLOC)	) == (SHF_WRITE|SHF_ALLOC))
        {

            return pSHdr->sh_offset;
        }
        pSHdr++;
    }

    return 0;
}
*/

//*************************************************************************
// FindFunctionInModuleByNameViaKsyms()
//
//*************************************************************************
/* ei: not needed. no Ksyms!
ULONG FindFunctionInModuleByNameViaKsyms(struct module* pMod,LPSTR szFunctionname)
{
    ULONG i;

    ENTER_FUNC();

	if(pMod->nsyms)
    {
        DPRINT((0,"FindFunctionInModuleByNameViaKsyms(): %u symbols for module %s\n",pMod->nsyms,pMod->name));
        for(i=0;i<pMod->nsyms;i++)
        {
            DPRINT((0,"FindFunctionInModuleByNameViaKsyms(): %s\n",pMod->syms[i].name));
            if(PICE_strcmpi((LPSTR)pMod->syms[i].name,szFunctionname) == 0)
            {
                DPRINT((0,"FindFunctionInModuleByName(): symbol was in exports\n"));
                LEAVE_FUNC();
                return pMod->syms[i].value;
            }
        }
    }

    DPRINT((0,"FindFunctionInModuleByName(): symbol wasn't in exports\n"));
    LEAVE_FUNC();
    return 0;
}
*/

//*************************************************************************
// FindFunctionInModuleByName()
//
//*************************************************************************
ULONG FindFunctionInModuleByName(LPSTR szFunctionname, PDEBUG_MODULE pd)
{
    ULONG i,addr;
    PICE_SYMBOLFILE_HEADER* pSymbols=NULL;
	PIMAGE_SYMBOL pSym, pSymEnd;
	LPSTR pStr;
	PIMAGE_SECTION_HEADER pShdr;

    ENTER_FUNC();
    DPRINT((0,"FindFunctionInModuleByName(%s)\n",szFunctionname));
    DPRINT((0,"FindFunctionInModuleByName(): mod size = %x\n",pd->size));
    DPRINT((0,"FindFunctionInModuleByName(): module is %S\n",pd->name));

	addr = (ULONG)pd->BaseAddress;

    pSymbols = FindModuleSymbols(addr);
    if(pSymbols)
    {
        DPRINT((0,"FindFunctionInModuleByName(): found symbol table for %S\n",pSymbols->name));
		pSym = (PIMAGE_SYMBOL)((ULONG)pSymbols+pSymbols->ulOffsetToGlobals);
		pSymEnd = (PIMAGE_SYMBOL)((ULONG)pSym+pSymbols->ulSizeOfGlobals);
		pStr = (LPSTR)((ULONG)pSymbols+pSymbols->ulOffsetToGlobalsStrings);
        pShdr = (PIMAGE_SECTION_HEADER)((ULONG)pSymbols+pSymbols->ulOffsetToHeaders);

		while( pSym < pSymEnd )
		{
			//symbol is a function is it's type is 0x20, storage class is external and section>0
			//if(( (pSym->Type == 0x20)  && (pSym->StorageClass==IMAGE_SYM_CLASS_EXTERNAL) &&
			//   (pSym->SectionNumber > 0 )))

			if(((pSym->Type == 0x0) || (pSym->Type == 0x20) )  &&
			   ((pSym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) || (pSym->StorageClass==IMAGE_SYM_CLASS_STATIC)) &&
			   (pSym->SectionNumber > 0 ))

			{
                ULONG start;
                LPSTR pName;
				PIMAGE_SECTION_HEADER pShdrThis = (PIMAGE_SECTION_HEADER)pShdr + (pSym->SectionNumber-1);

				start = ((ULONG)pd->BaseAddress+pShdrThis->VirtualAddress+pSym->Value);
				DPRINT((0,"FindFunctionInModuleByName(): %s @ %x\n",szFunctionname,start));

				if(pSym->N.Name.Short){ //if name is stored in the structure
					//name may be not zero terminated but 8 characters max
					DPRINT((0,"FindFunctionInModuleByName: %.8s\n", pSym->N.ShortName));
					pName = pSym->N.ShortName;  //name is in the header
			        if((PICE_fnncmp(pName,szFunctionname, 8) == 0) && start)
			        {
						DPRINT((0,"FindFunctionInModuleByName(): symbol was in symbol table, start: %x\n", start));
			            LEAVE_FUNC();
			            return start;
			        }
				}else{
					pName = pStr+pSym->N.Name.Long;
					DPRINT((0,"FindFunctionInModuleByName: %s\n", pName));
					if((PICE_fncmp(pName,szFunctionname) == 0) && start)
	                {
	                    DPRINT((0,"FindFunctionInModuleByName(): symbol was in string table, start: %x\n", start));
	                    LEAVE_FUNC();
	                    return start;
	                }
				}
        	}
			//skip the auxiliary symbols and get the next symbol
			pSym += pSym->NumberOfAuxSymbols + 1;
    	}
	}
    LEAVE_FUNC();
    return 0;
}

//*************************************************************************
// ExtractTypeNumber()
//
//*************************************************************************
ULONG ExtractTypeNumber(LPSTR p)
{
	LPSTR pTypeNumber;
	ULONG ulTypeNumber = 0;

    DPRINT((0,"ExtractTypeNumber(%s)\n",p));

	pTypeNumber = PICE_strchr(p,'(');

	if(pTypeNumber)
	{
		pTypeNumber++;
		ulTypeNumber = ExtractNumber(pTypeNumber);
		ulTypeNumber <<= 16;
		pTypeNumber = PICE_strchr(p,',');
        if(pTypeNumber)
        {
		    pTypeNumber++;
		    ulTypeNumber += ExtractNumber(pTypeNumber);
        }
        else
        {
            ulTypeNumber = 0;
        }
	}
	return ulTypeNumber;
}

//*************************************************************************
// FindTypeDefinitionForCombinedTypes()
//
//*************************************************************************
LPSTR FindTypeDefinitionForCombinedTypes(PICE_SYMBOLFILE_HEADER* pSymbols,ULONG ulTypeNumber,ULONG ulFileNumber)
{
    ULONG i;
    PSTAB_ENTRY pStab;
    LPSTR pStr,pName,pTypeNumber,pTypeDefIncluded,pNameTemp;
    int nStabLen;
    int nOffset=0,nNextOffset=0,nLen;
	static char szAccumulatedName[2048];
	ULONG ulCurrentTypeNumber,ulCurrentFileNumber=0;
    static char szCurrentPath[256];

    ENTER_FUNC();

	*szAccumulatedName = 0;

    pStab = (PSTAB_ENTRY )((ULONG)pSymbols + pSymbols->ulOffsetToStabs);
    nStabLen = pSymbols->ulSizeOfStabs;
    pStr = (LPSTR)((ULONG)pSymbols + pSymbols->ulOffsetToStabsStrings);

	DPRINT((0,"FindTypeDefinitionForCombinedTypes()\n"));

    for(i=0;i<(nStabLen/sizeof(STAB_ENTRY));i++)
    {
        pName = &pStr[pStab->n_strx + nOffset];

        switch(pStab->n_type)
        {
            case N_UNDF:
                nOffset += nNextOffset;
                nNextOffset = pStab->n_value;
                break;
            case N_SO:
                if((nLen = PICE_strlen(pName)))
                {
                    if(pName[nLen-1]!='/')
                    {
						ulCurrentFileNumber++;
                        if(PICE_strlen(szCurrentPath))
                        {
                            PICE_strcat(szCurrentPath,pName);
                            DPRINT((0,"FindTypeDefinitionForCombinedTypes(): changing source file %s\n",szCurrentPath));
                        }
                        else
                        {
                            DPRINT((0,"FindTypeDefinitionForCombinedTypes(): changing source file %s\n",pName));
                        }
                    }
                    else
                        PICE_strcpy(szCurrentPath,pName);
                }
                else
				{
                    szCurrentPath[0]=0;
				}
				break;
			case N_GSYM:
				//ei File number count is not reliable
				if( 1 /*ulCurrentFileNumber == ulFileNumber*/)
                {
                    DPRINT((0,"FindTypeDefinitionForCombinedTypes(): %s\n",pName));

					// handle multi-line symbols
					if(PICE_strchr(pName,'\\'))
					{
						if(PICE_strlen(szAccumulatedName))
						{
							PICE_strcat(szAccumulatedName,pName);
						}
						else
						{
							PICE_strcpy(szAccumulatedName,pName);
						}
                        szAccumulatedName[PICE_strlen(szAccumulatedName)-1]=0;
                        //DPRINT((0,"accum. %s\n",szAccumulatedName));
					}
                    else
                    {
						if(PICE_strlen(szAccumulatedName)==0)
                        {
                            PICE_strcpy(szAccumulatedName,pName);
                        }
                        else
                        {
                            PICE_strcat(szAccumulatedName,pName);
                        }
                        pNameTemp = szAccumulatedName;

                        // symbol-name:type-identifier type-number =
				        nLen = StrLenUpToWhiteChar(pNameTemp,":");
                        if((pTypeDefIncluded = PICE_strchr(pNameTemp,'=')) && pNameTemp[nLen+1]=='G')
                        {
                            DPRINT((0,"FindTypeDefinitionForCombinedTypes(): symbol includes type definition (%s)\n",pNameTemp));
                            pTypeNumber = pNameTemp+nLen+1;
                            if((ulCurrentTypeNumber = ExtractTypeNumber(pTypeNumber)) )
                            {
                                DPRINT((0,"FindTypeDefinitionForCombinedTypes(): type-number %x\n",ulCurrentTypeNumber));
                                if(ulCurrentTypeNumber == ulTypeNumber)
                                {
                                    DPRINT((0,"FindTypeDefinitionForCombinedTypes(): typenumber %x matches!\n",ulCurrentTypeNumber));
                                    return pNameTemp;
                                }
                            }
				        }
                        *szAccumulatedName = 0;
                    }
                }
				break;
        }
        pStab++;
    }
    return NULL;
}

//*************************************************************************
// FindTypeDefinition()
//
//*************************************************************************
LPSTR FindTypeDefinition(PICE_SYMBOLFILE_HEADER* pSymbols,ULONG ulTypeNumber,ULONG ulFileNumber)
{
    ULONG i;
    PSTAB_ENTRY pStab;
    LPSTR pStr,pName,pTypeString;
    int nStabLen;
    int nOffset=0,nNextOffset=0,strLen;
	static char szAccumulatedName[2048];
	ULONG ulCurrentTypeNumber,ulCurrentFileNumber=0;
	LPSTR pTypeSymbol;
    static char szCurrentPath[256];

    ENTER_FUNC();
    DPRINT((0,"FindTypeDefinition(%u,%u)\n",ulTypeNumber,ulFileNumber));

	*szAccumulatedName = 0;

    pStab = (PSTAB_ENTRY )((ULONG)pSymbols + pSymbols->ulOffsetToStabs);
    nStabLen = pSymbols->ulSizeOfStabs;
    pStr = (LPSTR)((ULONG)pSymbols + pSymbols->ulOffsetToStabsStrings);

    for(i=0;i<(nStabLen/sizeof(STAB_ENTRY));i++)
    {
        pName = &pStr[pStab->n_strx + nOffset];

        switch(pStab->n_type)
        {
	case N_UNDF:
	  nOffset += nNextOffset;
	  nNextOffset = pStab->n_value;
	  break;
	case N_SO:
	  if((strLen = PICE_strlen(pName)))
	    {
	      if(pName[strLen-1]!='/')
		{
		  ulCurrentFileNumber++;
		  if(PICE_strlen(szCurrentPath))
		    {
		      PICE_strcat(szCurrentPath,pName);
		      DPRINT((0,"FindTypeDefinition()1: cha %s, %u\n",szCurrentPath, ulCurrentFileNumber));
		    }
		  else
		    {
		      DPRINT((0,"FindTypeDefinition(): cha %s, %u\n",pName, ulCurrentFileNumber));
		    }
		}
	      else
		PICE_strcpy(szCurrentPath,pName);
	    }
	  else
	    {
	      szCurrentPath[0]=0;
	    }
	  break;
	case N_LSYM:
				// stab has no value -> must be type definition
				//ei File number count is not reliable
	  if(pStab->n_value == 0 /*&& ulCurrentFileNumber==ulFileNumber*/)
	    {
	      DPRINT((0,"FindTypeDefinition(): pre type definition %s\n",pName));
	      // handle multi-line symbols
	      if(strrchr(pName,'\\'))
		{
		  if(PICE_strlen(szAccumulatedName))
		    {
		      PICE_strcat(szAccumulatedName,pName);
		      DPRINT((0,"FindTypeDefinition(): [1] accum. %s\n",szAccumulatedName));
		    }
		  else
		    {
		      PICE_strcpy(szAccumulatedName,pName);
		      DPRINT((0,"FindTypeDefinition(): [2] accum. %s\n",szAccumulatedName));
		    }
		  szAccumulatedName[PICE_strlen(szAccumulatedName)-1]=0;
		}
	      else
		{
		  DPRINT((0,"FindTypeDefinition(): [3] accum. %s, pname: %s\n",szAccumulatedName, pName));
		  if(PICE_strlen(szAccumulatedName)==0)
		    {
		      PICE_strcpy(szAccumulatedName,pName);
		    }
		  else
		    {
		      PICE_strcat(szAccumulatedName,pName);
		    }
		  pTypeString = szAccumulatedName;

		  pTypeSymbol = PICE_strchr(pTypeString,':');
		  if(pTypeSymbol && (*(pTypeSymbol+1)=='t' || *(pTypeSymbol+1)=='T'))
		    {
		      // parse it
		      ulCurrentTypeNumber = ExtractTypeNumber(pTypeString);
		      DPRINT((0,"FindTypeDefinition(): ulCurrType: %u, LSYM is type %s\n",ulCurrentTypeNumber,pName));
		      if(ulCurrentTypeNumber == ulTypeNumber)
			{
			  DPRINT((0,"FindTypeDefinition(): type definition %s\n",pTypeString));
			  return pTypeString;
			}
		    }
		  *szAccumulatedName=0;
		}
	    }
	  break;
        }
        pStab++;
    }

    return FindTypeDefinitionForCombinedTypes(pSymbols,ulTypeNumber,ulFileNumber);

}

//*************************************************************************
// TruncateString()
//
//*************************************************************************
LPSTR TruncateString(LPSTR p,char c)
{
	static char temp[1024];
	LPSTR pTemp;

	pTemp = temp;

	while(*p!=0 && *p!=c)
		*pTemp++ = *p++;

	*pTemp = 0;

	return temp;
}

//*************************************************************************
// FindLocalsByAddress()
//
// find all locals for a given address by first looking up the function
// and then it's locals
//*************************************************************************
PLOCAL_VARIABLE FindLocalsByAddress(ULONG addr)
{
    ULONG i;
    PSTAB_ENTRY pStab;
    LPSTR pStr,pName;
    int nStabLen;
    int nOffset=0,nNextOffset=0;
    PICE_SYMBOLFILE_HEADER* pSymbols;
    static char szCurrentFunction[256];
    static char szCurrentPath[256];
    LPSTR pFunctionName;
    ULONG start,end,strLen;
	ULONG ulTypeNumber,ulCurrentFileNumber=0;
	LPSTR pTypedef;
	ULONG ulNumLocalVars=0;

    DPRINT((0,"FindLocalsByAddress()\n"));

    pFunctionName = FindFunctionByAddress(addr,&start,&end);
    DPRINT((0,"FindLocalsByAddress(): pFunctionName = %s\n",pFunctionName));
    if(pFunctionName)
    {
        pSymbols = FindModuleSymbols(addr);
        if(pSymbols)
        {
            pStab = (PSTAB_ENTRY )((ULONG)pSymbols + pSymbols->ulOffsetToStabs);
            nStabLen = pSymbols->ulSizeOfStabs;
            pStr = (LPSTR)((ULONG)pSymbols + pSymbols->ulOffsetToStabsStrings);

            for(i=0;i<(nStabLen/sizeof(STAB_ENTRY));i++)
            {
                pName = &pStr[pStab->n_strx + nOffset];

                DPRINT((0,"FindLocalsByAddress(): %x %x %x %x %x\n",
                        pStab->n_strx,
                        pStab->n_type,
                        pStab->n_other,
                        pStab->n_desc,
                        pStab->n_value));

                switch(pStab->n_type)
                {
                    case N_UNDF:
                        nOffset += nNextOffset;
                        nNextOffset = pStab->n_value;
                        break;
                    case N_SO:
                        if((strLen = PICE_strlen(pName)))
                        {
                            if(pName[strLen-1]!='/')
                            {
                                ulCurrentFileNumber++;
                                if(PICE_strlen(szCurrentPath))
                                {
                                    PICE_strcat(szCurrentPath,pName);
                                    DPRINT((0,"changing source file1 %s, %u\n",szCurrentPath,ulCurrentFileNumber));
                                }
                                else
                                {
                                    DPRINT((0,"changing source file %s, %u\n",pName,ulCurrentFileNumber));
                                }
                            }
                            else
                                PICE_strcpy(szCurrentPath,pName);
                        }
                        else
						{
                            szCurrentPath[0]=0;
						}
                        break;
                    case N_LSYM:
						// if we're in the function we're looking for
                        if(szCurrentFunction[0] && PICE_fncmp(szCurrentFunction,pFunctionName)==0)
                        {
                            DPRINT((0,"local variable1 %.8X %.8X %.8X %.8X %.8X %s\n",pStab->n_strx,pStab->n_type,pStab->n_other,pStab->n_desc,pStab->n_value,pName));
							ulTypeNumber = ExtractTypeNumber(pName);
							DPRINT((0,"type number = %u\n",ulTypeNumber));
							if((pTypedef = FindTypeDefinition(pSymbols,ulTypeNumber,ulCurrentFileNumber)))
							{
								DPRINT((0,"pTypedef: %x\n", pTypedef));
								PICE_strcpy(local_vars[ulNumLocalVars].type_name,TruncateString(pTypedef,':'));
								PICE_strcpy(local_vars[ulNumLocalVars].name,TruncateString(pName,':'));
								local_vars[ulNumLocalVars].value = (CurrentEBP+pStab->n_value);
								local_vars[ulNumLocalVars].offset = pStab->n_value;
								local_vars[ulNumLocalVars].line = pStab->n_desc;
                                local_vars[ulNumLocalVars].bRegister = FALSE;
								ulNumLocalVars++;
							}
                        }
                        break;
					case N_PSYM:
						// if we're in the function we're looking for
                        if(szCurrentFunction[0] && PICE_fncmp(szCurrentFunction,pFunctionName)==0)
                        {
                            DPRINT((0,"parameter variable %.8X %.8X %.8X %.8X %.8X %s\n",pStab->n_strx,pStab->n_type,pStab->n_other,pStab->n_desc,pStab->n_value,pName));
							ulTypeNumber = ExtractTypeNumber(pName);
							DPRINT((0,"type number = %x\n",ulTypeNumber));
							if((pTypedef = FindTypeDefinition(pSymbols,ulTypeNumber,ulCurrentFileNumber)))
							{
								PICE_strcpy(local_vars[ulNumLocalVars].type_name,TruncateString(pTypedef,':'));
								PICE_strcpy(local_vars[ulNumLocalVars].name,TruncateString(pName,':'));
								local_vars[ulNumLocalVars].value = (CurrentEBP+pStab->n_value);
								local_vars[ulNumLocalVars].offset = pStab->n_value;
								ulNumLocalVars++;
							}
                        }
                        break;
                    case N_RSYM:
						// if we're in the function we're looking for
                        if(szCurrentFunction[0] && PICE_fncmp(szCurrentFunction,pFunctionName)==0)
                        {
                            DPRINT((0,"local variable2 %.8X %.8X %.8X %.8X %.8X %s\n",pStab->n_strx,pStab->n_type,pStab->n_other,pStab->n_desc,pStab->n_value,pName));
							ulTypeNumber = ExtractTypeNumber(pName);
							DPRINT((0,"type number = %x\n",ulTypeNumber));
							if((pTypedef = FindTypeDefinition(pSymbols,ulTypeNumber,ulCurrentFileNumber)))
							{
								PICE_strcpy(local_vars[ulNumLocalVars].type_name,TruncateString(pTypedef,':'));
								PICE_strcpy(local_vars[ulNumLocalVars].name,TruncateString(pName,':'));
								local_vars[ulNumLocalVars].value = (LocalRegs[pStab->n_value]);
								local_vars[ulNumLocalVars].offset = pStab->n_value;
								local_vars[ulNumLocalVars].line = pStab->n_desc;
                                local_vars[ulNumLocalVars].bRegister = TRUE;
								ulNumLocalVars++;
							}
                        }
                        break;
                    case N_FUN:
                        if(PICE_strlen(pName))
                        {
                            ULONG len;

	                        len=StrLenUpToWhiteChar(pName,":");
	                        PICE_strncpy(szCurrentFunction,pName,len);
                            szCurrentFunction[len]=0;
                            DPRINT((0,"function %s\n",szCurrentFunction));
                        }
						else
						{
                            DPRINT((0,"END of function %s\n",szCurrentFunction));
                            szCurrentFunction[0]=0;
							if(ulNumLocalVars)
							{
								*local_vars[ulNumLocalVars].name = 0;
								return local_vars;
							}
						}
                        break;
                }
                pStab++;
            }
        }
    }
	return NULL;
}

//*************************************************************************
// FindSourceLineForAddress()
//
//*************************************************************************
LPSTR FindSourceLineForAddress(ULONG addr,PULONG pulLineNumber,LPSTR* ppSrcStart,LPSTR* ppSrcEnd,LPSTR* ppFilename)
{
    ULONG i; // index for walking through STABS
    PSTAB_ENTRY pStab; // pointer to STABS
    LPSTR pStr,pName; // pointer to STAB strings and current STAB string
    int nStabLen;     // length of STAB section in bytes
    int nOffset=0,nNextOffset=0;    // offset and next offset in string table
    PICE_SYMBOLFILE_HEADER* pSymbols;   // pointer to module's STAB symbol table
    static char szCurrentFunction[256];
    static char szCurrentPath[256];
    static char szWantedPath[256];
    LPSTR pFunctionName; // name of function that brackets the current address
    ULONG start,end,strLen,ulMinValue=0xFFFFFFFF;
	LPSTR pSrcLine=NULL;
    BOOLEAN bFirstOccurence = TRUE;

    // lookup the functions name and start-end (external symbols)
    pFunctionName = FindFunctionByAddress(addr,&start,&end);
	DPRINT((0,"FindSourceLineForAddress: for function: %s\n", pFunctionName));

    if(pFunctionName)
    {
        // lookup the modules symbol table (STABS)
        pSymbols = FindModuleSymbols(addr);
		DPRINT((0,"FindSourceLineForAddress: pSymbols %x\n", pSymbols));
        if(pSymbols)
        {
			DPRINT((0,"FindSourceLineForAddress: pSymbols->ulNumberOfSrcFiles %x\n", pSymbols->ulNumberOfSrcFiles));
            // no source files so we don't need to lookup anything
            if(!pSymbols->ulNumberOfSrcFiles)
                return NULL;

            // prepare STABS access
            pStab = (PSTAB_ENTRY )((ULONG)pSymbols + pSymbols->ulOffsetToStabs);
            nStabLen = pSymbols->ulSizeOfStabs;
            pStr = (LPSTR)((ULONG)pSymbols + pSymbols->ulOffsetToStabsStrings);

            // walk over all STABS
            for(i=0;i<(nStabLen/sizeof(STAB_ENTRY));i++)
            {
                // the name string corresponding to the STAB
                pName = &pStr[pStab->n_strx + nOffset];

                // switch STAB type
                switch(pStab->n_type)
                {
                    // change offset of name strings
                    case N_UNDF:
                        nOffset += nNextOffset;
                        nNextOffset = pStab->n_value;
                        break;
                    // source file change
                    case N_SO:
                        DPRINT((0,"changing source file %s\n",pName));
                        // if filename has a length record it
                        if((strLen = PICE_strlen(pName)))
                        {
                            PICE_strcpy(szCurrentPath,pName);
                        }
                        // else empty filename
                        else
						{
                            szCurrentPath[0]=0;
						}
                        break;
                    // sub-source file change
                    case N_SOL:
                        DPRINT((0,"changing sub source file %s\n",pName));
                        // if filename has a length record it
                        if((strLen = PICE_strlen(pName)))
                        {
                            PICE_strcpy(szCurrentPath,pName);
                        }
                        // else empty filename
                        else
						{
                            szCurrentPath[0]=0;
						}
                        break;
                    // a function symbol
                    case N_FUN:
                        if(!PICE_strlen(pName))
						{// it's the end of a function
                            DPRINT((0,"END of function %s\n",szCurrentFunction));

							szCurrentFunction[0]=0;

                            // in case we haven't had a zero delta match we return from here
							if(pSrcLine)
								return pSrcLine;

							break;
						}
						else
                        {// if it has a length it's the start of a function
                            ULONG len;
                            // extract the name only, the type string is of no use here
	                        len=StrLenUpToWhiteChar(pName,":");
	                        PICE_strncpy(szCurrentFunction,pName,len);
                            szCurrentFunction[len]=0;

                            DPRINT((0,"function %s\n",szCurrentFunction));
                        }
						//intentional fall through

					// line number
                    case N_SLINE:
						// if we're in the function we're looking for
						if(szCurrentFunction[0] && PICE_fncmp(szCurrentFunction,pFunctionName)==0)
                        {
                            DPRINT((0,"cslnum#%u for addr.%x (fn @ %x) ulMinVal=%x ulDelta=%x\n",pStab->n_desc,start+pStab->n_value,start,ulMinValue,(addr-(start+pStab->n_value))));

                            if(bFirstOccurence)
                            {
                                PICE_strcpy(szWantedPath,szCurrentPath);
                                DPRINT((0,"source file must be %s\n",szWantedPath));
                                bFirstOccurence = FALSE;
                            }
							DPRINT((0,"wanted %s, current: %s\n",szWantedPath, szCurrentPath));
                            // we might have a match if our address is greater than the one in the STAB
                            // and we're lower or equal than minimum value
                            if(addr>=start+pStab->n_value &&
                               (addr-(start+pStab->n_value))<=ulMinValue &&
                               PICE_strcmpi(szWantedPath,szCurrentPath)==0 )
                            {
                                ULONG j;
                                PICE_SYMBOLFILE_SOURCE* pSrc = (PICE_SYMBOLFILE_SOURCE*)((ULONG)pSymbols+pSymbols->ulOffsetToSrcFiles);

	                            DPRINT((0,"code source line number #%u for addr. %x found!\n",pStab->n_desc,start+pStab->n_value));

                                // compute new minimum
								ulMinValue = addr-(start+pStab->n_value);

                                // if we have a pointer for storage of line number, store it
                                if(pulLineNumber)
                                    *pulLineNumber = pStab->n_desc;

                                // NB: should put this somewhere else so that it's not done all the time
                                // if we have source files at all
                                DPRINT((0,"%u source files @ %x\n",pSymbols->ulNumberOfSrcFiles,pSrc));

                                // for all source files in this module
                                for(j=0;j<pSymbols->ulNumberOfSrcFiles;j++)
                                {
                                    LPSTR pSlash;
									ULONG currlen, fnamelen;

									currlen = PICE_strlen( szCurrentPath );
									fnamelen = PICE_strlen( pSrc->filename );
									pSlash = pSrc->filename + fnamelen - currlen;

									//DPRINT((0,"pSlash: %s, szCurrentPath: %s\n", pSlash, szCurrentPath));
                                    // if base name matches current path we have found the correct source file
                                    if(PICE_strcmpi(pSlash,szCurrentPath)==0)
                                    {
                                        // the linenumber
                                        ULONG k = pStab->n_desc;

                                        DPRINT((0,"found src file %s @ %x\n",pSrc->filename,pSrc));

                                        // store the pointer to the filename
                                        if(ppFilename)
                                            *ppFilename = pSrc->filename;

                                        if(pSrc->ulOffsetToNext > sizeof(PICE_SYMBOLFILE_SOURCE))
                                        {
                                            // get a pointer to the source file (right after the file header)
                                            pSrcLine = (LPSTR)((ULONG)pSrc+sizeof(PICE_SYMBOLFILE_SOURCE));

                                            // store the source start and end address
                                            if(ppSrcStart)
                                                *ppSrcStart = pSrcLine;
                                            if(ppSrcEnd)
                                                *ppSrcEnd = pSrcLine+pSrc->ulOffsetToNext-sizeof(PICE_SYMBOLFILE_SOURCE);

                                            // goto to the right line
                                            while(--k)
                                            {
                                                while(*pSrcLine!=0 && *pSrcLine!=0x0a && *pSrcLine!=0x0d)
                                                    pSrcLine++;
                                                if(!IsAddressValid((ULONG)pSrcLine))
                                                    return NULL;
                                                pSrcLine++;
                                            }

										    if(ulMinValue == 0)
											    return pSrcLine;
                                        }
                                        else
                                        {
                                            DPRINT((0,"src file descriptor found, but contains no source\n"));
                                        }

										break;
                                    }
                                    (ULONG)pSrc += pSrc->ulOffsetToNext;
                                }
                            }
                        }
                        break;
                }
                pStab++;
            }
        }
    }
	DPRINT((0,"FindSourceLineForAddress: exit 1\n"));
    return NULL;
}

//*************************************************************************
// FindAddressForSourceLine()
//
//*************************************************************************
BOOLEAN FindAddressForSourceLine(ULONG ulLineNumber,LPSTR pFilename,PDEBUG_MODULE pMod,PULONG pValue)
{
    ULONG i;
    PSTAB_ENTRY pStab;
    LPSTR pStr,pName;
    int nStabLen;
    int nOffset=0,nNextOffset=0;
    PICE_SYMBOLFILE_HEADER* pSymbols;
    static char szCurrentFunction[256];
    static char szCurrentPath[256];
    ULONG strLen,addr,ulMinValue=0xFFFFFFFF;
    BOOLEAN bFound = FALSE;

    DPRINT((0,"FindAddressForSourceLine(%u,%s,%x)\n",ulLineNumber,pFilename,(ULONG)pMod));

    addr = (ULONG)pMod->BaseAddress;

    pSymbols = FindModuleSymbols(addr);
    if(pSymbols)
    {
        pStab = (PSTAB_ENTRY )((ULONG)pSymbols + pSymbols->ulOffsetToStabs);
        nStabLen = pSymbols->ulSizeOfStabs;
        pStr = (LPSTR)((ULONG)pSymbols + pSymbols->ulOffsetToStabsStrings);

        for(i=0;i<(nStabLen/sizeof(STAB_ENTRY));i++)
        {
            pName = &pStr[pStab->n_strx + nOffset];

            switch(pStab->n_type)
            {
                case N_UNDF:
                    nOffset += nNextOffset;
                    nNextOffset = pStab->n_value;
                    break;
                case N_SO:
					if((strLen = PICE_strlen(pName)))
                    {
                        if(pName[strLen-1]!='/')
                        {
                            if(PICE_strlen(szCurrentPath))
                            {
                                PICE_strcat(szCurrentPath,pName);
                                DPRINT((0,"changing source file %s\n",szCurrentPath));
                            }
                            else
                            {
                                DPRINT((0,"changing source file %s\n",pName));
                                PICE_strcpy(szCurrentPath,pName);
                            }
                        }
                        else
                            PICE_strcpy(szCurrentPath,pName);
                    }
                    else
					{
                        szCurrentPath[0]=0;
					}
                    break;
                case N_SLINE:
					// if we're in the function we're looking for
                    if(PICE_strcmpi(pFilename,szCurrentPath)==0)
                    {
                        if(pStab->n_desc>=ulLineNumber && (pStab->n_desc-ulLineNumber)<=ulMinValue)
                        {
                            ulMinValue = pStab->n_desc-ulLineNumber;

                            DPRINT((0,"code source line number #%u for offset %x in function @ %s)\n",pStab->n_desc,pStab->n_value,szCurrentFunction));
                            addr = FindFunctionInModuleByName(szCurrentFunction,pMod);
                            if(addr)
                            {
                                *pValue = addr + pStab->n_value;
                                bFound = TRUE;
                            }
                        }
                    }
                    break;
                case N_FUN:
                    if(PICE_strlen(pName))
                    {
                        ULONG len;

	                    len=StrLenUpToWhiteChar(pName,":");
	                    PICE_strncpy(szCurrentFunction,pName,len);
                        szCurrentFunction[len]=0;
                        DPRINT((0,"function %s\n",szCurrentFunction));
                    }
					else
					{
                        DPRINT((0,"END of function %s\n",szCurrentFunction));
						szCurrentFunction[0]=0;
					}
                    break;
            }
            pStab++;
        }
    }
    return bFound;
}

//*************************************************************************
// ListSymbolStartingAt()
//  iterate through the list of module symbols (both functions and variables)
//*************************************************************************
ULONG ListSymbolStartingAt(PDEBUG_MODULE pMod,PICE_SYMBOLFILE_HEADER* pSymbols,ULONG index,LPSTR pOutput)
{
	PIMAGE_SYMBOL pSym, pSymEnd;
	LPSTR pStr;
	PIMAGE_SECTION_HEADER pShdr;

	DPRINT((0,"ListSymbolStartingAt(%x,%u)\n",(ULONG)pSymbols,index));
    DPRINT((0,"ListSymbolStartingAt(): ulOffsetToGlobals = %x ulSizeofGlobals = %x\n",pSymbols->ulOffsetToGlobals,pSymbols->ulSizeOfGlobals));
	pSym = (PIMAGE_SYMBOL)((ULONG)pSymbols+pSymbols->ulOffsetToGlobals);
	pSymEnd = (PIMAGE_SYMBOL)((ULONG)pSym+pSymbols->ulSizeOfGlobals);
	pStr = (LPSTR)((ULONG)pSymbols+pSymbols->ulOffsetToGlobalsStrings);
    pShdr = (PIMAGE_SECTION_HEADER)((ULONG)pSymbols+pSymbols->ulOffsetToHeaders);

    pSym += index;

	while( pSym < pSymEnd )
	{
        LPSTR pName;

		if(((pSym->Type == 0x0) || (pSym->Type == 0x20) )  &&
		   ((pSym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) /*|| (pSym->StorageClass==IMAGE_SYM_CLASS_STATIC)*/) &&
		   (pSym->SectionNumber > 0 ))
		{
			PIMAGE_SECTION_HEADER pShdrThis = (PIMAGE_SECTION_HEADER)pShdr + (pSym->SectionNumber-1);
            ULONG section_flags;
            ULONG start;

			DPRINT((0,"ListSymbolStartingAt(): pShdr[%x] = %x\n",pSym->SectionNumber,(ULONG)pShdrThis));

			if(!IsRangeValid((ULONG)pShdrThis,sizeof(IMAGE_SECTION_HEADER)) )
			{
				DPRINT((0,"ListSymbolStartingAt(): pShdr[%x] = %x is not a valid pointer\n",pSym->SectionNumber,(ULONG)pShdrThis));
				return FALSE;
			}
			section_flags = pShdrThis->Characteristics;
			//to get address in the memory we base address of the module and
			//add offset of the section and then add offset of the symbol from
			//the begining of the section

			start = ((ULONG)pMod->BaseAddress+pShdrThis->VirtualAddress+pSym->Value);
			if(pSym->N.Name.Short){
				//name is in the header. it's not zero terminated. have to copy.
				PICE_sprintf(pOutput,"%.8X (%s) %.8s\n",start,(section_flags&IMAGE_SCN_CNT_CODE)?"TEXT":"DATA",pSym->N.ShortName);
			}
			else{
				ASSERT(pSym->N.Name.Long<=pSymbols->ulSizeOfGlobalsStrings); //sanity check
				pName = pStr+pSym->N.Name.Long;
				if(!IsAddressValid((ULONG)pName))
				{
					DPRINT((0,"ListSymbolStartingAt(): pName = %x is not a valid pointer\n",pName));
					return 0;
				}
            	PICE_sprintf(pOutput,"%.8X (%s) %s\n",start,(section_flags&IMAGE_SCN_CNT_CODE)?"TEXT":"DATA",pName);
			}

			if((pSym+pSym->NumberOfAuxSymbols+1)<(pSymEnd))
                return (index+pSym->NumberOfAuxSymbols+1);
        }
		index += pSym->NumberOfAuxSymbols + 1;
        pSym += pSym->NumberOfAuxSymbols + 1;
	}
    return 0;
}

//*************************************************************************
// SanityCheckExports()
//
//*************************************************************************
BOOLEAN SanityCheckExports(void)
{
    BOOLEAN bResult = FALSE;
    ULONG i,ulValue,incr;

    Print(OUTPUT_WINDOW,"pICE: sanity-checking exports...\n");
	return TRUE;
	/* fix later!!! do we really need to cross reference two kinds of symbolic info?
    if(fake_kernel_module.nsyms && fake_kernel_module.syms)
    {
        incr = (fake_kernel_module.nsyms/4);
        if(!incr)incr = 1;
        for(i=0;i<fake_kernel_module.nsyms;i+=incr)
        {
            if(ScanExports((char*)fake_kernel_module.syms[i].name,&ulValue) )
            {
                if(!(i%25))
                {
                    ClrLine(wWindow[OUTPUT_WINDOW].y + wWindow[OUTPUT_WINDOW].usCurY);
                    PICE_sprintf(tempSym,"pICE: sanity-checking exports %u/%u",
                                          i,
                                          fake_kernel_module.nsyms);
                    PutChar(tempSym,1,wWindow[OUTPUT_WINDOW].y + wWindow[OUTPUT_WINDOW].usCurY);
                }

                if(fake_kernel_module.syms[i].value != ulValue)
                {
                    PICE_sprintf(tempSym,"pICE: %s doesn't match (%.8X != %.8X)\n",
                                 fake_kernel_module.syms[i].name,
                                 fake_kernel_module.syms[i].value,
                                 ulValue);
                    Print(OUTPUT_WINDOW,tempSym);

                    return FALSE;
                }
            }
        }

        bResult = TRUE;
    }

    return bResult;
	*/
}

//*************************************************************************
// LoadExports()
//
//*************************************************************************
BOOLEAN LoadExports(void)
{
	HANDLE hf;
    BOOLEAN bResult = TRUE;

	ENTER_FUNC();

    Print(OUTPUT_WINDOW,"pICE: loading exports...\n");
	hf = PICE_open(L"\\SystemRoot\\symbols\\ntoskrnl.map",OF_READ);
	/*
	if(hf)
    {
        Print(OUTPUT_WINDOW,"pICE: no System.map in /boot\n");
	    hf = PICE_open("/System.map",OF_READ);
    }
	*/

    if(hf)
	{
		//mm_segment_t oldfs;
		size_t len;

		len = PICE_len(hf);
        if(len)
        {
		    DPRINT((0,"file len = %d\n",len));

		    pExports = PICE_malloc(len+1,NONPAGEDPOOL);  // maybe make pool setting an option

		    DPRINT((0,"pExports = %x\n",pExports));

            if(pExports)
		    {
        		//oldfs = get_fs(); set_fs(KERNEL_DS);
                ulExportLen = len;
			    ((PUCHAR)pExports)[len]=0;
			    if(len == PICE_read(hf,pExports,len))
			    {
				    DPRINT((0,"success reading system map!\n"));
            		PICE_sprintf(tempSym,"pICE: ntoskrnl.sym @ %x (size %x)\n",pExports,len);
		    		Print(OUTPUT_WINDOW,tempSym);
				}
				else
					DbgPrint("error reading ntoskrnl map!\n");
    		    //set_fs(oldfs);
		    }
        }
		PICE_close(hf);
	}
    else
    {
        Print(OUTPUT_WINDOW,"pICE: no ntoskrnl.sys \n");
        Print(OUTPUT_WINDOW,"pICE: could not load exports...\n");
        bResult = FALSE;
    }

    LEAVE_FUNC();

    return bResult;
}

//*************************************************************************
// UnloadExports()
//
//*************************************************************************
void UnloadExports(void)
{
	ENTER_FUNC();
	if(pExports)
	{
		DPRINT((0,"freeing %x\n",pExports));
		PICE_free(pExports);
        pExports = NULL;
	}
    LEAVE_FUNC();
}

//*************************************************************************
// LoadSymbols()
//
//*************************************************************************
PICE_SYMBOLFILE_HEADER* LoadSymbols(LPSTR filename)
{
	HANDLE hf;
    PICE_SYMBOLFILE_HEADER* pSymbols=NULL;
	WCHAR tempstr[256];
	int conv;
	ENTER_FUNC();

	if( !( conv = PICE_MultiByteToWideChar(CP_ACP, NULL, filename, -1, tempstr, 256 ) ) )
	{
		DPRINT((0,"Can't convert module name.\n"));
		return NULL;
	}
	DPRINT((0,"LoadSymbols: filename %s, tempstr %S, conv: %d\n", filename, tempstr, conv));

    if(ulNumSymbolsLoaded<DIM(apSymbols))
    {
	    hf = PICE_open(tempstr,OF_READ);
		DPRINT((0,"LoadSymbols: hf: %x, file: %S\n",hf, tempstr));
	    if(hf)
	    {
		    //mm_segment_t oldfs;
		    size_t len;

            DPRINT((0,"hf = %x\n",hf));

		    len = PICE_len(hf);
		    DPRINT((0,"file len = %d\n",len));

            if(len)
            {
		        pSymbols = PICE_malloc(len+1,NONPAGEDPOOL);  // maybe make pool setting an option
		        DPRINT((0,"pSymbols = %x\n",pSymbols));

		        if(pSymbols)
		        {
        		    //oldfs = get_fs(); set_fs(KERNEL_DS);
			        if(len == PICE_read(hf,(PVOID)pSymbols,len))
			        {
				        DPRINT((0,"LoadSymbols(): success reading symbols!\n"));
				        DPRINT((0,"LoadSymbols(): pSymbols->magic = %X\n",pSymbols->magic));
			        }
        		    //set_fs(oldfs);


					if(pSymbols->magic == PICE_MAGIC)
					{
                        DPRINT((0,"magic = %X\n",pSymbols->magic));
	                    DPRINT((0,"name = %S\n",pSymbols->name));
                        DPRINT((0,"ulOffsetToHeaders,ulSizeOfHeader = %X,%X\n",pSymbols->ulOffsetToHeaders,pSymbols->ulSizeOfHeader));
                        DPRINT((0,"ulOffsetToGlobals,ulSizeOfGlobals = %X,%X\n",pSymbols->ulOffsetToGlobals,pSymbols->ulSizeOfGlobals));
                        DPRINT((0,"ulOffsetToGlobalsStrings,ulSizeOfGlobalsStrings = %X,%X\n",pSymbols->ulOffsetToGlobalsStrings,pSymbols->ulSizeOfGlobalsStrings));
                        DPRINT((0,"ulOffsetToStabs,ulSizeOfStabs = %X,%X\n",pSymbols->ulOffsetToStabs,pSymbols->ulSizeOfStabs));
                        DPRINT((0,"ulOffsetToStabsStrings,ulSizeOfStabsStrings = %X,%X\n",pSymbols->ulOffsetToStabsStrings,pSymbols->ulSizeOfStabsStrings));
                        DPRINT((0,"ulOffsetToSrcFiles,ulNumberOfSrcFiles = %X,%X\n",pSymbols->ulOffsetToSrcFiles,pSymbols->ulNumberOfSrcFiles));
						DPRINT((0,"pICE: symbols loaded for module \"%S\" @ %x\n",pSymbols->name,pSymbols));
						apSymbols[ulNumSymbolsLoaded++]=pSymbols;
					}
					else
					{
    					DPRINT((0,"LoadSymbols(): freeing %x\n",pSymbols));
						DPRINT((0,"pICE: symbols file \"%s\" corrupt\n",filename));
	    				PICE_free(pSymbols);
					}
		        }

            }
		    PICE_close(hf);
	    }
        else
        {
			DPRINT((0,"pICE: could not load symbols for %s...\n",filename));
        }
    }

	LEAVE_FUNC();

    return pSymbols;
}

//*************************************************************************
// ReloadSymbols()
//
//*************************************************************************
BOOLEAN ReloadSymbols(void)
{
    BOOLEAN bResult;

	ENTER_FUNC();

    UnloadSymbols();

    bResult = LoadSymbolsFromConfig(TRUE);

    LEAVE_FUNC();

    return bResult;
}

//*************************************************************************
// UnloadSymbols()
//
//*************************************************************************
void UnloadSymbols()
{
    ULONG i;

	ENTER_FUNC();

    if(ulNumSymbolsLoaded)
	{
        for(i=0;i<ulNumSymbolsLoaded;i++)
        {
    		DPRINT((0,"freeing [%u] %x\n",i,apSymbols[i]));
	    	PICE_free(apSymbols[i]);
            apSymbols[i] = NULL;
        }
        ulNumSymbolsLoaded = 0;
	}
    LEAVE_FUNC();
}

//*************************************************************************
// LoadSymbolsFromConfig()
//
//*************************************************************************
BOOLEAN LoadSymbolsFromConfig(BOOLEAN bIgnoreBootParams)
{
	HANDLE hf;
	LPSTR pConfig,pConfigEnd,pTemp;
	char temp[256];
	ULONG line = 1;
    BOOLEAN bResult = FALSE;

	ENTER_FUNC();

	hf = PICE_open(L"\\SystemRoot\\symbols\\pice.cfg",OF_READ);
	if(hf)
	{
		//mm_segment_t oldfs;
		size_t len;

        DPRINT((0,"hf = %x\n",hf));

		len = PICE_len(hf);
		DPRINT((0,"file len = %d\n",len));

        if(len)
        {
		    pConfig = PICE_malloc(len+1,NONPAGEDPOOL);  // maybe make pool setting an option
		    DPRINT((0,"pConfig = %x\n",pConfig));
        	//oldfs = get_fs(); set_fs(KERNEL_DS);

			if(len == PICE_read(hf,(PVOID)pConfig,len))
			{
	    		//set_fs(oldfs);

				pConfigEnd = pConfig + len;

				while(pConfig<pConfigEnd)
				{
					// skip leading spaces
					while(*pConfig==' ' && pConfig<pConfigEnd)
						pConfig++;
					// get ptr to temporary
					pTemp = temp;
					// fill in temporary with symbol path
					while(*pConfig!=0 && *pConfig!=0x0a && *pConfig!=0x0d && pConfig<pConfigEnd)
						*pTemp++ = *pConfig++;
					// finish up symbol path string
					*pTemp = 0;
					// skip any line ends
					while((*pConfig==0x0a || *pConfig==0x0d) && pConfig<pConfigEnd)
						pConfig++;

					// finally try to load the symbols
					if(PICE_strlen(temp))
					{
                        PICE_SYMBOLFILE_HEADER *pSymbols;

                        // boot parameter
                        if(*temp == '!')
                        {
                            if(!bIgnoreBootParams)
                            {
                                if(!PICE_strlen(szBootParams))
                                {
                                    PICE_strcpy(szBootParams,temp+1);
                                    DPRINT((0,"pICE: boot params = %s\n",szBootParams));
                                }
                                else
                                {
                                    DPRINT((0,"pICE: boot params already exist! ignoring...\n",szBootParams));
                                }
                            }
                        }
                        // options
                        else if(*temp == '+')
                        {
                            if(PICE_strlen(temp)>1)
                            {
                                if(PICE_strcmpi(temp,"+vga")==0)
                                {
                                    eTerminalMode = TERMINAL_MODE_VGA_TEXT;
                                    DPRINT((0,"pICE: eTerminalMode = TERMINAL_MODE_VGA_TEXT\n"));
                                }
                                else if(PICE_strcmpi(temp,"+hercules")==0)
                                {
                                    eTerminalMode = TERMINAL_MODE_HERCULES_GRAPHICS;
                                    DPRINT((0,"pICE: eTerminalMode = TERMINAL_MODE_HERCULES_GRAPHICS\n"));
                                }
                                else if(PICE_strcmpi(temp,"+serial")==0)
                                {
                                    eTerminalMode = TERMINAL_MODE_SERIAL;
                                    DPRINT((0,"pICE: eTerminalMode = TERMINAL_MODE_SERIAL\n"));
                                }
                            }
                            else
                            {
                                DPRINT((0,"pICE: found option, but no value\n"));
                            }
                        }
                        // comment
                        else if(*temp == '#')
                        {
                            DPRINT((0,"comment out\n"));
                        }
                        // symbol file name/path
                        else
                        {
							DPRINT((0,"Load symbols from file %s\n", temp));
							pSymbols = LoadSymbols(temp);
							DPRINT((0,"Load symbols from file %s, pSymbols: %x\n", temp, pSymbols));
                            if(pSymbols)
                            {
                                PICE_SYMBOLFILE_SOURCE* pSrc;
                                LPSTR p;

                                pSrc = (PICE_SYMBOLFILE_SOURCE*)((ULONG)pSymbols + pSymbols->ulOffsetToSrcFiles);
                                pCurrentSymbols = pSymbols;
                                p = strrchr(pSrc->filename,'\\');
                                if(p)
                                {
                                    PICE_strcpy(szCurrentFile,p+1);
                                }
                                else
                                {
                                    PICE_strcpy(szCurrentFile,pSrc->filename);
                                }
                            }
                        }
					}
					else
					{
                        DPRINT((0,"invalid line [%u] in config!\n",line));
					}
					line++;
				}
			}
			else
			{
	    		//set_fs(oldfs);
			}
		}

	    PICE_close(hf);
        bResult = TRUE;
	}
	else
	{
		DPRINT((0,"pICE: config file not found! No symbols loaded.\n"));
		DPRINT((0,"pICE: Please make sure to create a file \\systemroot\\symbols\\pice.conf\n"));
		DPRINT((0,"pICE: if you want to have symbols for any module loaded.\n"));
	}

    LEAVE_FUNC();

    return bResult;
}


//*************************************************************************
// EVALUATION OF EXPRESSIONS
//*************************************************************************

//*************************************************************************
// SkipSpaces()
//
//*************************************************************************
void SkipSpaces(void)
{
	while(pExpression[ulIndex]==' ')
		ulIndex++;
};

//*************************************************************************
// FindGlobalStabSymbol()
//
//*************************************************************************
BOOLEAN FindGlobalStabSymbol(LPSTR pExpression,PULONG pValue,PULONG pulTypeNumber,PULONG pulFileNumber)
{
  ULONG i;
  PSTAB_ENTRY pStab;
  LPSTR pStr,pName;
  int nStabLen;
  int nOffset=0,nNextOffset=0,nLen,strLen;
  PICE_SYMBOLFILE_HEADER* pSymbols;
  ULONG ulTypeNumber;
  static char SymbolName[1024];
  static char szCurrentPath[256];
  ULONG ulCurrentFileNumber=0;
  LPSTR pTypeDefIncluded;
  ULONG addr;

  // must have a current module
  if(pCurrentMod)
    {
      // in case we query for the kernel we need to use the fake kernel module
      addr = (ULONG)pCurrentMod->BaseAddress;

      // find the symbols for the module
      pSymbols = FindModuleSymbols(addr);
      if(pSymbols)
	{
	  // prepare table access
	  pStab = (PSTAB_ENTRY )((ULONG)pSymbols + pSymbols->ulOffsetToStabs);
	  nStabLen = pSymbols->ulSizeOfStabs;
	  pStr = (LPSTR)((ULONG)pSymbols + pSymbols->ulOffsetToStabsStrings);
	  // starting at file 0
	  *pulFileNumber = 0;

	  // go through stabs
	  for(i=0;i<(nStabLen/sizeof(STAB_ENTRY));i++)
	    {
	      pName = &pStr[pStab->n_strx + nOffset];

	      switch(pStab->n_type)
		{
		  // an N_UNDF symbol marks a change of string table offset
		case N_UNDF:
		  nOffset += nNextOffset;
		  nNextOffset = pStab->n_value;
		  break;
		  // a source file symbol
		case N_SO:
		  if((strLen = PICE_strlen(pName)))
		    {
		      if(pName[strLen-1]!='/')
			{
			  ulCurrentFileNumber++;
			  if(PICE_strlen(szCurrentPath))
			    {
			      PICE_strcat(szCurrentPath,pName);
			      DPRINT((0,"changing source file %s\n",szCurrentPath));
			    }
			  else
			    {
			      DPRINT((0,"changing source file %s\n",pName));
			    }
			}
		      else
			PICE_strcpy(szCurrentPath,pName);
		    }
		  else
		    {
		      szCurrentPath[0]=0;
		    }
		  break;
		case N_GSYM:
		case N_LSYM:
		case N_PSYM:
		  // symbol-name:type-identifier type-number =
		  nLen = StrLenUpToWhiteChar(pName,":");
		  PICE_strncpy(SymbolName,pName,nLen);
		  SymbolName[nLen] = 0;
		  if(PICE_strcmpi(SymbolName,pExpression)==0)
		    {
		      DPRINT((0,"global symbol %s\n",pName));
		      // extract type-number from stab
		      ulTypeNumber = ExtractTypeNumber(pName);
		      DPRINT((0,"type number = %x, from %s\n",ulTypeNumber, pName));
		      *pulTypeNumber = ulTypeNumber;
		      // look for symbols address in external symbols
		      if( pStab->n_type == N_LSYM || pStab->n_type == N_PSYM )
			*pValue = CurrentEBP + pStab->n_value;
		      else *pValue = FindFunctionInModuleByName(SymbolName,pCurrentMod);

		      DPRINT((0,"value = %x\n",*pValue));
		      *pulFileNumber = ulCurrentFileNumber;
		      DPRINT((0,"file = %x\n",ulCurrentFileNumber));
		      if((pTypeDefIncluded = PICE_strchr(pName,'=')) )
			{
			  DPRINT((0,"symbol includes type definition (%s)\n",pTypeDefIncluded));
			}
		      return TRUE;
		    }
		  break;
		}
	      pStab++;
	    }
	}
    }
  return FALSE;
}

//*************************************************************************
// ExtractToken()
//
//*************************************************************************
void ExtractToken(LPSTR pStringToken)
{
	while(PICE_isalpha(pExpression[ulIndex]) || PICE_isdigit(pExpression[ulIndex]) || pExpression[ulIndex]=='_')
	{
		*pStringToken++=pExpression[ulIndex++];
		*pStringToken=0;
	}
}

//*************************************************************************
// ExtractTypeName()
//
//*************************************************************************
LPSTR ExtractTypeName(LPSTR p)
{
    static char temp[1024];
    ULONG i;

    DPRINT((1,"ExtractTypeName(%s)\n",p));

    for(i=0;IsAddressValid((ULONG)p) && *p!=0 && *p!=':';i++,p++)
        temp[i] = *p;

    if(!IsAddressValid((ULONG)p) )
    {
        DPRINT((1,"hit invalid page %x!\n",(ULONG)p));
    }

    temp[i]=0;

    return temp;
}

//*************************************************************************
// ExtractNumber()
//
//*************************************************************************
LONG ExtractNumber(LPSTR p)
{
    LONG lMinus = 1,lBase;
    ULONG lNumber = 0;

    DPRINT((0,"ExtractNumber(): %s\n",p));

    if(!IsAddressValid((ULONG)p) )
    {
        DPRINT((1,"ExtractNumber(): [1] invalid page %x hit!\n",p));
        return 0;
    }

    if(*p == '-')
    {
        lMinus = -1;
        p++;
    }

    if(!IsAddressValid((ULONG)p) )
    {
        DPRINT((1,"ExtractNumber(): [2] invalid page %x hit!\n",p));
        return 0;
    }

    if(*p != '0') // non-octal -> decimal number
        lBase = 10;
    else
        lBase = 8;

    if(!IsAddressValid((ULONG)p) )
    {
        DPRINT((1,"ExtractNumber(): [3] invalid page %x hit!\n",p));
        return 0;
    }

    while(PICE_isdigit(*p))
    {
        lNumber *= lBase;
        lNumber += *p-'0';
        p++;
        if(!IsAddressValid((ULONG)p) )
        {
            DPRINT((1,"ExtractNumber(): [4] invalid page %x hit!\n",p));
            return 0;
        }
    }

    return (lNumber*lMinus);
}

//*************************************************************************
// ExtractArray()
//
//*************************************************************************
BOOLEAN ExtractArray(PVRET pvr,LPSTR p)
{
    ULONG index_typenumber,type_number;
    ULONG lower_bound,upper_bound;
    LPSTR pTypeDef;

    DPRINT((1,"ExtractArray(%s)\n",p));

    // index-type index-type-number;lower;upper;element-type-number
    pvr->bArrayType = TRUE;
    p++;
    index_typenumber = ExtractTypeNumber(p);
    p = PICE_strchr(p,';');
    if(p)
    {
        p++;
        lower_bound = ExtractNumber(p);
        p = PICE_strchr(p,';');
        if(p)
        {
            p++;

            upper_bound = ExtractNumber(p);
            p = PICE_strchr(p,';');
            if(p)
            {
                p++;

                type_number = ExtractTypeNumber(p);

                DPRINT((1,"ExtractArray(): %x %x %x %x\n",index_typenumber,lower_bound,upper_bound,type_number));

                pTypeDef = FindTypeDefinition(pvr->pSymbols,type_number,pvr->file);
                if(pTypeDef)
                {
                    PICE_strcpy(pvr->type_name,ExtractTypeName(pTypeDef));
                    pvr->type = type_number;
                    return TRUE;
                }
            }
        }
    }
    return FALSE;
}

//*************************************************************************
// ExtractStructMembers()
//
//*************************************************************************
PVRET ExtractStructMembers(PVRET pvr,LPSTR p)
{
    ULONG len;
    static char member_name[128];
    LONG bit_offset,bit_size,type_number,byte_size;
    static VRET vr;
    LPSTR pTypeDef,pEqual;

    DPRINT((1,"ExtractStructMembers(): %s\n",p));

    PICE_memset(&vr,0,sizeof(vr));

    // name:type-number,bit-offset,bit-size
	len=StrLenUpToWhiteChar(p,":");
    if(len)
    {
        // extract member name
	    PICE_strncpy(member_name,p,len);
        member_name[len]=0;
        DPRINT((1,"ExtractStructMembers(): member_name = %s\n",member_name));

        // go to char following ':'
        p += (len+1);
        if(IsAddressValid((ULONG)p) )
        {
            type_number = ExtractTypeNumber(p);
            DPRINT((1,"ExtractStructMembers(): type_number = %x\n",type_number));

            vr.type = type_number;

            pEqual = PICE_strchr(p,')');
            // see if it includes type def
            if(pEqual)
            {
                p = pEqual+1;
                if(*p == '=')
                {
                    p++;
                    if(*p == 'a')
                    {
                        DPRINT((1,"ExtractStructMembers(): member is array\n"));
                        vr.bArrayType = TRUE;
                        p = PICE_strchr(p,';');
                        p = PICE_strchr(p,';');
                        p = PICE_strchr(p,';');
                        if(p)
                            p++;

                        type_number = ExtractTypeNumber(p);
                        vr.father_type = type_number;
                    }
                    else if(*p == '*')
                    {
                        DPRINT((1,"ExtractStructMembers(): member is ptr\n"));
                        vr.bPtrType = TRUE;
                        type_number = ExtractTypeNumber(p);
                        DPRINT((1,"ExtractStructMembers(): type_number = %x\n",type_number));
                        vr.father_type = type_number;
                    }
                    else if(*p == 'u')
                    {
                        DPRINT((1,"ExtractStructMembers(): member is union\n"));
                        while(*p!=';' && *(p+1)!=';' && *p!=0)p++;
                    }
                }
            }

            p = PICE_strchr(p,',');
            if(p)
            {
                p++;
                bit_offset = ExtractNumber(p);
                DPRINT((1,"ExtractStructMembers(): bit_offset = %x\n",bit_offset));
                p = PICE_strchr(p,',');
                if(p)
                {
                    p++;

                    bit_size = ExtractNumber(p);
                    DPRINT((1,"ExtractStructMembers(): bit_size = %x\n",bit_size));

                    vr.address = pvr->value + bit_offset/8;
                    vr.file = pvr->file;
                    vr.size = bit_size;
                    PICE_strcpy(vr.name,member_name);
                    byte_size = (bit_size+1)/8;
                    if(!byte_size)
                        byte_size = 4;
                    pvr->address = pvr->value;
                    if(IsRangeValid(vr.address,byte_size))
                    {
                        switch(byte_size)
                        {
                            case 1:
                                vr.value = *(PUCHAR)vr.address;
                                break;
                            case 2:
                                vr.value = *(PUSHORT)vr.address;
                                break;
                            case 4:
                                vr.value = *(PULONG)vr.address;
                                break;
                        }
                    }

                    DPRINT((1,"ExtractStructMembers(): member %s type %x bit_offset %x bit_size%x\n",member_name,type_number,bit_offset,bit_size));

                    pTypeDef = FindTypeDefinition(pvr->pSymbols,type_number,pvr->file);
                    if(pTypeDef)
                    {
                        DPRINT((1,"ExtractStructMembers(): pTypedef= %s\n",pTypeDef));
                        PICE_strcpy(vr.type_name,ExtractTypeName(pTypeDef));
                        pTypeDef = PICE_strchr(pTypeDef,':');
                        if(pTypeDef)
                        {
                            pTypeDef++;
                            type_number = ExtractTypeNumber(pTypeDef);
                            DPRINT((1,"ExtractStructMembers(): type_number = %x\n",type_number));
                            vr.father_type = type_number;
                        }
                    }
                }
            }
        }
    }

    return &vr;
}

//*************************************************************************
// EvaluateSymbol()
//
//*************************************************************************
BOOLEAN EvaluateSymbol(PVRET pvr,LPSTR pToken)
{
    LPSTR pTypeDef,pTypeName,pTypeBase,pSemiColon,pStructMembers;
    BOOLEAN bDone = FALSE;
    ULONG ulType,ulBits,ulBytes;
    LONG lLowerRange,lUpperRange,lDelta;
    static char type_def[2048];

    DPRINT((1,"EvaluateSymbol(%s)\n",pToken));

	if(FindGlobalStabSymbol(pToken,&pvr->value,&pvr->type,&pvr->file))
    {
        DPRINT((1,"EvaluateSymbol(%s) pvr->value = %x pvr->type = %x\n",pToken,pvr->value,pvr->type));
        while(!bDone)
        {
            if(!(pTypeDef = FindTypeDefinition(pvr->pSymbols,pvr->type,pvr->file)))
                break;
            PICE_strcpy(type_def,pTypeDef);

            pTypeDef = type_def;

            pTypeName = ExtractTypeName(pTypeDef);

            DPRINT((1,"%s %s\n",pTypeName,pToken));

            PICE_strcpy(pvr->type_name,pTypeName);

            pTypeBase = PICE_strchr(pTypeDef,'=');

            if(!pTypeBase)
                return FALSE;

            pTypeBase++;

            switch(*pTypeBase)
            {
                case '(': // type reference
                    ulType = ExtractTypeNumber(pTypeBase);
                    DPRINT((1,"%x is a type reference to %x\n",pvr->type,ulType));
                    pvr->type = ulType;
                    break;
                case 'r': // subrange
                    pTypeBase++;
                    ulType = ExtractTypeNumber(pTypeBase);
                    DPRINT((1,"%x is sub range of %x\n",pvr->type,ulType));
                    if(pvr->type == ulType)
                    {
                        DPRINT((1,"%x is a self reference\n",pvr->type));
                        pSemiColon = PICE_strchr(pTypeBase,';');
                        pSemiColon++;
                        lLowerRange = ExtractNumber(pSemiColon);
                        pSemiColon = PICE_strchr(pSemiColon,';');
                        pSemiColon++;
                        lUpperRange = ExtractNumber(pSemiColon);
                        lDelta = lUpperRange-lLowerRange;
                        DPRINT((1,"bounds %x-%x range %x\n",lLowerRange,lUpperRange,lDelta));
                        ulBits=0;
                        do
                        {
                            ulBits++;
                            lDelta /= 2;
                        }while(lDelta);
                        ulBytes = (ulBits+1)/8;
                        if(!ulBytes)
                            ulBytes = 4;
                        DPRINT((1,"# of bytes = %x\n",ulBytes));
                        pvr->address = pvr->value;
                        if(IsRangeValid(pvr->value,ulBytes))
                        {
                            switch(ulBytes)
                            {
                                case 1:
                                    pvr->value = *(PUCHAR)pvr->value;
                                    break;
                                case 2:
                                    pvr->value = *(PUSHORT)pvr->value;
                                    break;
                                case 4:
                                    pvr->value = *(PULONG)pvr->value;
                                    break;
                            }
                        }
                        bDone=TRUE;
                    }
                    else
                        pvr->type = ulType;
                    break;
                case 'a': // array type
                    DPRINT((1,"%x array\n",pvr->type));
                    pTypeBase++;
                    if(!ExtractArray(pvr,pTypeBase))
                    {
                        bDone = TRUE;
                        pvr->error = 1;
                    }
                    break;
                case '*': // ptr type
                    DPRINT((1,"%x is ptr to\n",pvr->type));
                    bDone = TRUE; // meanwhile
                    break;
                case 's': // struct type [name:T(#,#)=s#membername1:(#,#),#,#;membername1:(#,#),#,#;;]
                    // go past 's'
                    pTypeBase++;

                    // extract the the struct size
                    lLowerRange = ExtractNumber(pTypeBase);
                    DPRINT((1,"%x struct size = %x\n",pvr->type,lLowerRange));

                    // skip over the digits
                    while(PICE_isdigit(*pTypeBase))
                        pTypeBase++;

                    // the structs address is is value
                    pvr->address = pvr->value;
                    pvr->bStructType = TRUE;

                    // decode the struct members. pStructMembers now points to first member name
                    pStructMembers = pTypeBase;

                    while(pStructMembers && *pStructMembers && *pStructMembers!=';' && ulNumStructMembers<DIM(vrStructMembers))
                    {
                        DPRINT((1,"EvaluateSymbol(): member #%u\n",ulNumStructMembers));
                        // put this into our array
                        vrStructMembers[ulNumStructMembers] = *ExtractStructMembers(pvr,pStructMembers);

                        if(!PICE_strlen(vrStructMembers[ulNumStructMembers].type_name))
                        {
                            ULONG i;
                            PVRET pvrThis = &vrStructMembers[ulNumStructMembers];

                            DPRINT((1,"EvaluateSymbol(): no type name\n"));
                            for(i=0;i<ulNumStructMembers;i++)
                            {
                                DPRINT((1,"EvaluateSymbol(): vr[i].type_name = %s\n",vrStructMembers[i].type_name));
                                DPRINT((1,"EvaluateSymbol(): vr[i].name = %s\n",vrStructMembers[i].name));
                                DPRINT((1,"EvaluateSymbol(): vr[i].address = %.8X\n",vrStructMembers[i].address));
                                DPRINT((1,"EvaluateSymbol(): vr[i].value = %.8X\n",vrStructMembers[i].value));
                                DPRINT((1,"EvaluateSymbol(): vr[i].size = %.8X\n",vrStructMembers[i].size));
                                DPRINT((1,"EvaluateSymbol(): vr[i].type = %.8X\n",vrStructMembers[i].type));
                                if(pvrThis->type == vrStructMembers[i].type)
                                {
                                    PICE_strcpy(pvrThis->type_name,vrStructMembers[i].type_name);
                                    pvrThis->bArrayType = vrStructMembers[i].bArrayType;
                                    pvrThis->bPtrType = vrStructMembers[i].bPtrType;
                                    pvrThis->bStructType = vrStructMembers[i].bStructType;
                                    break;
                                }
                            }
                        }

                        DPRINT((1,"EvaluateSymbol(): vr.type_name = %s\n",vrStructMembers[ulNumStructMembers].type_name));
                        DPRINT((1,"EvaluateSymbol(): vr.name = %s\n",vrStructMembers[ulNumStructMembers].name));
                        DPRINT((1,"EvaluateSymbol(): vr.address = %.8X\n",vrStructMembers[ulNumStructMembers].address));
                        DPRINT((1,"EvaluateSymbol(): vr.value = %.8X\n",vrStructMembers[ulNumStructMembers].value));
                        DPRINT((1,"EvaluateSymbol(): vr.size = %.8X\n",vrStructMembers[ulNumStructMembers].size));
                        DPRINT((1,"EvaluateSymbol(): vr.type = %.8X\n",vrStructMembers[ulNumStructMembers].type));

                        ulNumStructMembers++;

                        // skip to next ':'
                        pStructMembers = PICE_strchr(pStructMembers,';');
                        pStructMembers = PICE_strchr(pStructMembers,':');
                        if(pStructMembers)
                        {
                            DPRINT((1,"EvaluateSymbol(): ptr is now %s\n",pStructMembers));
                            // go back to where member name starts
                            while(*pStructMembers!=';')
                                pStructMembers--;
                            // if ';' present, go to next char
                            if(pStructMembers)
                                pStructMembers++;
                        }
                    }

                    bDone = TRUE; // meanwhile
                    break;
                case 'u': // union type
                    DPRINT((1,"%x union\n",pvr->type));
                    bDone = TRUE; // meanwhile
                    break;
                case 'e': // enum type
                    DPRINT((1,"%x enum\n",pvr->type));
                    bDone = TRUE; // meanwhile
                    break;
                default:
                    DPRINT((1,"DEFAULT %x, base: %c\n",pvr->type, *pTypeBase));
		    pvr->address = pvr->value;
		    if(IsRangeValid(pvr->value,ulBytes))
		      {
			switch(ulBytes)
			  {
			  case 1:
			    pvr->value = *(PUCHAR)pvr->value;
			    break;
			  case 2:
			    pvr->value = *(PUSHORT)pvr->value;
			    break;
			  case 4:
			    pvr->value = *(PULONG)pvr->value;
			    break;
			  }
		      }
                    bDone = TRUE;
                    break;
            }

        }
        return TRUE;
	}
    return FALSE;
}

//*************************************************************************
// Symbol()
//
// Symbol := v
//*************************************************************************
BOOLEAN Symbol(PVRET pvr)
{
	char SymbolToken[128];

	ExtractToken(SymbolToken);

	DPRINT((1,"SymbolToken = %s\n",SymbolToken));

    return EvaluateSymbol(pvr,SymbolToken);
}

//*************************************************************************
// Expression()
//
// Expression := Symbol | Symbol->Symbol
//*************************************************************************
BOOLEAN Expression(PVRET pvr)
{
	if(!Symbol(pvr))
        return FALSE;

	return TRUE;
}

//*************************************************************************
// Evaluate()
//
//*************************************************************************
void Evaluate(PICE_SYMBOLFILE_HEADER* pSymbols,LPSTR p)
{
    ULONG i;

	PICE_memset(&vr,0,sizeof(vr));
	vr.pSymbols = pSymbols;

	pExpression = p;
	ulIndex=0;
    ulNumStructMembers=0;
	if(Expression(&vr))
	{
		DPRINT((1,"\nOK!\n"));
		DPRINT((1,"value = %x type = %x\n",vr.value,vr.type));
        if(vr.bStructType)
        {
            PICE_sprintf(tempSym,"struct %s %s @ %x\n",vr.type_name,p,vr.address);
            Print(OUTPUT_WINDOW,tempSym);
            for(i=0;i<ulNumStructMembers;i++)
            {
                if(vrStructMembers[i].bArrayType)
                {
                    PICE_sprintf(tempSym,"[%.8X %.8X] %s %s[%u]\n",
                            vrStructMembers[i].address,
                            vrStructMembers[i].size/8,
                            vrStructMembers[i].type_name,
                            vrStructMembers[i].name,
                            vrStructMembers[i].size/8);
                }
                else if(vrStructMembers[i].bPtrType)
                {
                    PICE_sprintf(tempSym,"[%.8X %.8X] %s* %s -> %x (%u)\n",
                            vrStructMembers[i].address,
                            vrStructMembers[i].size/8,
                            vrStructMembers[i].type_name,
                            vrStructMembers[i].name,
                            vrStructMembers[i].value,
                            vrStructMembers[i].value);
                }
                else
                {
                    PICE_sprintf(tempSym,"[%.8X %.8X] %s %s = %x (%u)\n",
                            vrStructMembers[i].address,
                            vrStructMembers[i].size/8,
                            vrStructMembers[i].type_name,
                            vrStructMembers[i].name,
                            vrStructMembers[i].value,
                            vrStructMembers[i].value);
                }
                Print(OUTPUT_WINDOW,tempSym);
            }
        }
        else if(vr.bArrayType)
        {
            Print(OUTPUT_WINDOW,"array\n");
        }
        else
        {
            PICE_sprintf(tempSym,"%s %s @ %x = %x (%u)\n",vr.type_name,p,vr.address,vr.value,vr.value);
            Print(OUTPUT_WINDOW,tempSym);
        }
	}
	else
	{
		DPRINT((1,"\nERROR: code %x\n",vr.error));
	}
}
