/*** backtrace.c ***/
/* Generate a stack backtrace
 * (c) Paul Field 1995
 * Based closely on code by Tom Hughes
 */

#include <assert.h>
#include <stdio.h>

#include "Desk.BackTrace.h"
#include "Desk.Debug.h"

#include "Defs.h"




void	Desk_BackTrace_OutputToFFunctionWithPrefix( Desk_backtrace_printf_fn fn, void* reference, const char* prefix)
{
	_kernel_unwindblock frame;
	char	*language;
	
	fn( reference, "%sStack-dump:\n", prefix);
	
	Desk_Backtrace_SupportCurrentFrame( &frame);
	
	while ( _kernel_unwind( &frame, &language) > 0)
		{
		
		Desk_function_name_info	*Desk_name_info;
		unsigned int		*Desk_save_code_pointer;
		unsigned int		*Desk_frame_create_instruction;
		unsigned int		*fp;
		unsigned int		Desk_test_words;
		
		fp = (unsigned int*) (frame.fp & PCMask);
		
		if (fp != NULL)	{
			
			Desk_save_code_pointer		= (unsigned *)(*fp & PCMask);
			Desk_frame_create_instruction	= Desk_save_code_pointer - SaveCodePointerOffset;
			
			Desk_Debug_Printf( Desk_error_PLACE "BackTrace: save_code_pointer=0x%p, frame_create_instruction=0x%p\n", 
				Desk_save_code_pointer,
				Desk_frame_create_instruction
				);
			
			/* Search backwards from the frame creation instruction looking for a 'name info' word */
			Desk_name_info = (Desk_function_name_info *)(Desk_frame_create_instruction-1);
			
			Desk_Debug_Printf( Desk_error_PLACE "BackTrace: name_info=0x%p\n", Desk_name_info);
			
			for (Desk_test_words = NameInfoSearchWordLimit; Desk_name_info->Desk_ff_code != 0xff && Desk_test_words > 0; Desk_test_words--)
				{
				Desk_Debug_Printf( Desk_error_PLACE "BackTrace: name_info=0x%p\n", Desk_name_info);
				Desk_name_info--;
				}
			
			/* If we found the name info word we can print the name, otherwise the function is anonymous */
			
			Desk_Debug_Printf( Desk_error_PLACE "Desk_name_info->Desk_ff_code=0x%x\n", Desk_name_info->Desk_ff_code);
			if ( Desk_name_info->Desk_ff_code == 0xff)
				Desk_Debug_Printf( Desk_error_PLACE "fn name = '%s'\n", (char *)Desk_name_info - Desk_name_info->length);
			
			fn( reference, "%s%s	(language is %s)\n",
				prefix,
				(Desk_name_info->Desk_ff_code == 0xff) ?
					(char *)Desk_name_info - Desk_name_info->length
					:
					"<anonymous function>",
				(language) ? language : "<unknown language>"
				);
			
			Desk_Debug_Printf( Desk_error_PLACE "\n");
			}
		}
	
	fn( reference, "%s\n", prefix);
	}
