File: stack_trace.cpp
Size: 3046
Date: Tue, 08 May 2012 23:13:40 +0200
Type: cpp
#include "pbvm.h"


// set of temporary values for building the stack string array.
// note that stack_info->caller_line_no is the line number we are going to return to

typedef struct{
	vm_state *vm;
	pb_array *values;
	int index;
	wchar_t *group_name;
	wchar_t *class_name;
	wchar_t *routine_name;
	wchar_t *trace;
}callback_state;

void set_string(vm_state *vm, wchar_t *source, value *val){
	int len=wcslen(source);
	wchar_t *dest = (wchar_t *)pbstg_alc(vm, (len+1)*2, GET_HEAP(vm));
	wcscpy(dest, source);

	if (!(val->flags&IS_NULL))
		ot_free_val_ptr(vm, val);

	val->value=(DWORD)dest;
	val->flags=0x0d00;
	val->type=pbvalue_string;
}

void stack_build_string(callback_state *state, short line_no){
	wchar_t temp[256];
	if (state->index==0 || state->group_name==NULL)
		return;

	wnsprintf(temp, 256, L"%s.%s.%s Line: %d",state->group_name, state->class_name, state->routine_name, line_no);
	if (state->values != NULL){
		value *val=ot_array_index(state->vm, state->values, state->index -1);
		set_string(state->vm, temp, val);
	}
	if (state->trace!=NULL)
		lstrcatW(state->trace, temp);
}

bool __stdcall callback(stack_info *info, void * arg_value){
    callback_state *state=(callback_state *)arg_value;
	
	stack_build_string(state, info->caller_line_no);
	state->index++;

	// note these are pointers to const memory addresses
    state->group_name= ob_get_group_name(state->vm, info->group_id);
    state->class_name = ob_class_name_not_indirect(state->vm, MAKELONG(info->group_id, info->class_id));

	group_data *str_group = ob_group_data_srch(state->vm,info->group_id);
	class_data *str_class = ob_get_class_entry(state->vm, &str_group, info->class_id);
	state->routine_name = ob_event_module_name(state->vm, str_group, str_class, info->routine_id)-1;
   
    return TRUE;
}

DWORD __declspec(dllexport) __stdcall Stack_Trace (vm_state *vm, DWORD arg_count){

	value ret;
	lvalue_ref *lv_values;
	callback_state state;
	DWORD isnull;
	
	last_vm = vm;

	lv_values=ot_get_next_lvalue_arg(vm, &isnull);
	state.values = ot_array_create_unbounded(vm, MAKELONG(-1,pbvalue_string), 0);

	state.vm=vm;
	state.index=0;
	state.trace=NULL;
	state.group_name=NULL;

    ret.value=shlist_traversal(GET_STACKLIST(vm), &state, callback);
	ret.type=7;
	ret.flags=0x0500;

	stack_build_string(&state, -1);
	
	ot_assign_ref_array(vm, lv_values->ptr, state.values, 0, 0);
	ot_set_return_val(vm, &ret);
    return 1;
}

int WINAPI filter(LPEXCEPTION_POINTERS ptrs){
	if (last_vm!=NULL){
		wchar_t buffer[4096];
		callback_state state;
		*buffer=0;
		state.trace = buffer;
		state.values = NULL;
		state.vm = last_vm;
		state.index = 0;
		state.group_name=NULL;

		void *stack_list = GET_STACKLIST(last_vm);
		shlist_traversal(stack_list, &state, callback);
		stack_build_string(&state, -1);
		MessageBoxW(NULL, buffer, L"Unexpected GPF", MB_OK);
	}
	return EXCEPTION_EXECUTE_HANDLER;
}

void Install_Crash_Hook(){
	SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)filter);
}

void Uninstall_Crash_Hook(){
	SetUnhandledExceptionFilter(NULL);
}