#include "Desk.Debug.h"
#include "Desk.Error.h"

#include "Desk.BackTrace.h"

#include "Defs.h"






typedef struct	{
	char*		fnname;
	unsigned int*	Desk_save_instruction;
	unsigned int*	Desk_frame_create_instruction;
	unsigned int*	fp;
	}
	Desk_BackTrace_frameblock;




static void	Desk_BackTrace_GetFrameInfo( Desk_BackTrace_frameblock* frameblock, const _kernel_unwindblock* frame)
	{
	Desk_function_name_info	*Desk_name_info;
	unsigned int		Desk_test_words;
	
	frameblock->fnname			= NULL;
	frameblock->Desk_save_instruction	= NULL;
	frameblock->Desk_frame_create_instruction	= NULL;
	
	frameblock->fp = (unsigned int*) (frame->fp & PCMask);
	
	if ( frameblock->fp)	{
		
		frameblock->Desk_save_instruction		= (unsigned int*) (*(frameblock->fp) & PCMask);
		
		if ( frameblock->Desk_save_instruction)	{
			frameblock->Desk_frame_create_instruction	= frameblock->Desk_save_instruction - SaveCodePointerOffset;
			
			/* Search backwards from the frame creation instruction looking for a 'name info' word */
			Desk_name_info = (Desk_function_name_info *)(frameblock->Desk_frame_create_instruction-1);
			
			for ( Desk_test_words = NameInfoSearchWordLimit; Desk_name_info->Desk_ff_code != 0xff && Desk_test_words > 0; Desk_test_words--)
				{
				Desk_name_info--;
				}
			
			if ( Desk_name_info->Desk_ff_code == 0xff)
				frameblock->fnname = (char*) Desk_name_info - Desk_name_info->length;
			else	frameblock->fnname = NULL;
			}
		
		
		}
	}


const char*	Desk_BackTrace_GetFunctionName( const void* ptr)
{
Desk_function_name_info*	fn = (Desk_function_name_info*) ptr;
int			i;

Desk_Debug2_Printf( "Desk_BackTrace_GetFunctionName( 0x%p)\n", ptr);

for ( i=0; i<5; i++, fn--)	{
	
	Desk_Debug2_Printf( "fn->Desk_ff_code = %i, fn->length = %i\n",
		fn->Desk_ff_code, fn->length
		);
		
	if ( fn->Desk_ff_code == 0xff && fn->length<4096)	{
		const char*	c = (const char*) fn - fn->length;
		Desk_Debug2_Printf( "Desk_BackTrace_GetFunctionName returning 0x%p '%s'\n",
			c, c
			);
		return c;
		}
	}

Desk_Debug2_Printf( "Desk_BackTrace_GetFunctionName returning NULL\n");
return NULL;
}



const Desk_BackTrace_functionlist*	Desk_BackTrace_GetCurrentFunctions( void)
	{
	static Desk_BackTrace_functionlist	functionlist;
	static unsigned int*			functions[ Desk_BackTrace_MAXFNS];
	
	_kernel_unwindblock		frame;
	Desk_BackTrace_frameblock	frameblock;
	char				*language;
	/*int			n;*/
	
	Desk_BackTrace_SupportCurrentFrame( &frame);
	
	functionlist.n = 0;
	functionlist.functions	= functions;
	
	while ( _kernel_unwind( &frame, &language) > 0)	{
		if ( frame.fp)	{
			Desk_BackTrace_GetFrameInfo( &frameblock, &frame);
			if ( !frameblock.Desk_save_instruction)	break;
			
			functions[ functionlist.n] = frameblock.Desk_frame_create_instruction;
			Desk_Debug_Printf( Desk_error_PLACE "0x%p\n", functions[ functionlist.n]);
			functionlist.n++ ;
			if ( functionlist.n >= Desk_BackTrace_MAXFNS)	break;
			}
		}
	
	return &functionlist;
	}
