/*** 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 "Desk.Error.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);
		
		Desk_Debug5_Printf( Desk_error_PLACE "BackTrace: fp=0x%p\n", fp);
		
		if (fp != NULL)	{
			
			Desk_save_code_pointer = (unsigned*) (*fp & PCMask);
			Desk_Debug5_Printf( Desk_error_PLACE "BackTrace: save_code_pointer=0x%p\n", Desk_save_code_pointer);
			
			if ( Desk_save_code_pointer)	{
				
				Desk_frame_create_instruction	= Desk_save_code_pointer - SaveCodePointerOffset;
				
				Desk_Debug5_Printf( Desk_error_PLACE "BackTrace: frame_create_instruction=0x%p\n", 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_Debug5_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_Debug5_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_Debug5_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_Debug5_Printf( Desk_error_PLACE "fn name = '%s'\n", (char *)Desk_name_info - Desk_name_info->length);
				
				fn( reference, "%s 0x%p (%s)	(language is %s)\n",
					prefix,
					Desk_save_code_pointer,
					(Desk_name_info->Desk_ff_code == 0xff) ?
						(char *)Desk_name_info - Desk_name_info->length
						:
						"<anonymous function>",
					(language) ? language : "<unknown language>"
					);
				
				Desk_Debug5_Printf( Desk_error_PLACE "\n");
				}
			}
		}
	
	fn( reference, "%s\n", prefix);
	}
