示例#1
0
VOID Get_Exception_Info(PEXCEPTION_POINTERS pException, FILE* fp, UINT dwLastError)
{
	CHAR		Module_Name[MAX_PATH];
	PBYTE		Module_Addr;
	HANDLE		hFile;
	FILETIME	Last_Write_Time;
	FILETIME	Local_File_Time;
	SYSTEMTIME	T;

	Get_Version_Str(fp);

	_ftprintf(fp, _T("------------------------------------------------------------------------------\n"));
	_ftprintf(fp, _T("Process:  ") );

	GetModuleFileName(NULL, Module_Name, MAX_PATH);
	_ftprintf(fp, _T("%s\n") , Module_Name);

	// If exception occurred.
	if (pException)
	{
		EXCEPTION_RECORD &	E = *pException->ExceptionRecord;
		CONTEXT &			C = *pException->ContextRecord;

		// If module with E.ExceptionAddress found - save its path and date.
		if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr))
		{
			_ftprintf(fp, _T("Module:   %s\n") , Module_Name);

			if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
				FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
			{
				if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time))
				{
					FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time);
					FileTimeToSystemTime(&Local_File_Time, &T);

					_ftprintf(fp, _T("Date Modified:  %02d/%02d/%d\n") , 
						T.wMonth, T.wDay, T.wYear);
				}
				CloseHandle(hFile);
			}
		}
		else
		{
			_ftprintf(fp, _T("Exception Addr:  %08X\n")  , (LONG_PTR)(E.ExceptionAddress));
		}

		_ftprintf(fp, _T("------------------------------------------------------------------------------\n"));

		//加入具体异常解释信息
		CreateExceptionDesc(pException, fp, dwLastError);

	}

	_ftprintf(fp, _T("------------------------------------------------------------------------------\n"));

	// Save call stack info.
	_ftprintf(fp, _T("Call Stack:\n"));
	Get_Call_Stack(pException, fp);
}
示例#2
0
bool shouldUseStackWalker(PSTACK Ebp, int max_depth)
{
	WCHAR	Module_Name[MAX_PATH];
	PBYTE	Module_Addr = 0;
	int depth = 0;

	while (depth < max_depth) 
	{
		if (IsBadReadPtr(Ebp, sizeof(PSTACK)) || 
			IsBadReadPtr(Ebp->Ebp, sizeof(PSTACK)) ||
			Ebp->Ebp < Ebp ||
			Ebp->Ebp - Ebp > 0xFFFFFF ||
			IsBadCodePtr(FARPROC(Ebp->Ebp->Ret_Addr)) ||
			!Get_Module_By_Ret_Addr(Ebp->Ebp->Ret_Addr, Module_Name, Module_Addr))
		{
			return true;
		}
		depth++;
		Ebp = Ebp->Ebp;
	}

	return false;
}
示例#3
0
PBYTE get_valid_frame(PBYTE esp)
{
	PDWORD cur_stack_loc = NULL;
	const int max_search = 400;
	WCHAR	module_name[MAX_PATH];
	PBYTE	module_addr = 0;

	// round to highest multiple of four
	esp = (esp + (4 - ((int)esp % 4)) % 4);

	// scroll through stack a few hundred places.
	for (cur_stack_loc = (PDWORD) esp; cur_stack_loc < (PDWORD)esp + max_search; cur_stack_loc += 1)
	{
		// if you can read the pointer,
		if (IsBadReadPtr(cur_stack_loc, sizeof(PDWORD)))
		{
			continue;
		}

		//  check if it's in a module
		if (!Get_Module_By_Ret_Addr((PBYTE)*cur_stack_loc, module_name, module_addr))
		{
			continue;
		}

		// check if the code before the instruction ptr is a call 
		if(!has_valid_call_before(cur_stack_loc))
		{
			continue;
		}
		
		// if these all pass, return that ebp, otherwise continue till we're dead
		return (PBYTE)(cur_stack_loc - 1);
	}

	return NULL;
}
示例#4
0
文件: Crash.cpp 项目: qiqisteve/wxsj2
//*************************************************************
void Get_Exception_Info(PEXCEPTION_POINTERS pException, FILE* fp, DWORD dwLastError)
//*************************************************************
// Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str.
{
	int			i;
	TCHAR		Module_Name[MAX_PATH];
	PBYTE		Module_Addr;
	HANDLE		hFile;
	FILETIME	Last_Write_Time;
	FILETIME	Local_File_Time;
	SYSTEMTIME	T;
	
	Get_Version_Str(fp);

	_ftprintf(fp, _T("------------------------------------------------------------------------------")NL);
	_ftprintf(fp, _T("Process:  ") );

	GetModuleFileName(NULL, Module_Name, MAX_PATH);
	_ftprintf(fp, _T("%s") NL, Module_Name);

	// If exception occurred.
	if (pException)
	{
		EXCEPTION_RECORD &	E = *pException->ExceptionRecord;
		CONTEXT &			C = *pException->ContextRecord;

		// If module with E.ExceptionAddress found - save its path and date.
		if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr))
		{
			_ftprintf(fp, _T("Module:   %s") NL, Module_Name);

			if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
				FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
			{
				if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time))
				{
					FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time);
					FileTimeToSystemTime(&Local_File_Time, &T);

					_ftprintf(fp, _T("Date Modified:  %02d/%02d/%d") NL, 
						T.wMonth, T.wDay, T.wYear);
				}
				CloseHandle(hFile);
			}
		}
		else
		{
			_ftprintf(fp, _T("Exception Addr:  %08X") NL , (LONG_PTR)(E.ExceptionAddress));
		}
		
		_ftprintf(fp, _T("------------------------------------------------------------------------------")NL);

		//加入具体异常解释信息
		CreateExceptionDesc(pException, fp, dwLastError);
		
		_ftprintf(fp, _T("------------------------------------------------------------------------------")NL);

		// Save instruction that caused exception.
		if(E.ExceptionAddress)
		{
			_ftprintf(fp, _T("Instruction: ")NL);
			for (i = 0; i < 16; i++)
				_ftprintf(fp, _T(" %02X"), PBYTE(E.ExceptionAddress)[i]);
		}
		// Save registers at exception.
		_ftprintf(fp, NL _T("Registers:") NL);
		_ftprintf(fp, _T("EAX: %08X  EBX: %08X  ECX: %08X  EDX: %08X") NL, C.Eax, C.Ebx, C.Ecx, C.Edx);
		_ftprintf(fp, _T("ESI: %08X  EDI: %08X  ESP: %08X  EBP: %08X")NL, C.Esi, C.Edi, C.Esp, C.Ebp);
		_ftprintf(fp, _T("EIP: %08X  EFlags: %08X")NL, C.Eip, C.EFlags);
	} //if (pException)
	
	_ftprintf(fp, _T("------------------------------------------------------------------------------")NL);

	// Save call stack info.
	_ftprintf(fp, _T("Call Stack:")NL);
	Get_Call_Stack(pException, fp);
} //Get_Exception_Info
示例#5
0
文件: Crash.cpp 项目: qiqisteve/wxsj2
void CreateExceptionDesc(PEXCEPTION_POINTERS pException, FILE* fp, DWORD dwLastError)
{
	if (!pException || !fp) return;

	EXCEPTION_RECORD &	E = *pException->ExceptionRecord;
	CONTEXT &			C = *pException->ContextRecord;

	//取得异常发生地
	TCHAR		szModeleInfo[MAX_PATH];
	TCHAR		Module_Name[MAX_PATH];
	PBYTE		Module_Addr;
	if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr))
	{
		_sntprintf(szModeleInfo, MAX_PATH, _T("%s"), Module_Name);
	}
	else
	{
		_sntprintf(szModeleInfo, MAX_PATH, _T("%08X"), (DWORD_PTR)(E.ExceptionAddress));
	}

	switch(E.ExceptionCode)
	{
	//核心软异常
	case 0XE000C0DE:
		{
			tException* pException = (tException*)E.ExceptionInformation[0];
			if(!pException) return;

			//断言错误
			if(pException->m_bAssert) 
			{
				_ftprintf(fp,
					_T("\t\tAssert  \n")
					_T("\n")
					_T("File:      %s\n")
					_T("Line:      %d\n")
					_T("Expr:      %s\n")
					_T("LastError: 0X%08X\n"),

					pException->m_strFileName.c_str(), 
					pException->m_nLineNum, 
					pException->m_strMessage.c_str(),
					pException->m_dwLastError);
			}
			else
			{
				_ftprintf(fp,
					_T("\t\tGeneral  \n")
					_T("\n")
					_T("Expr:      %s\n")
					_T("LastError: 0x%08X\n"),

					pException->m_strMessage.c_str(),
					pException->m_dwLastError);
			}
		}
		break;

		//试图对一个虚地址进行读写
	case EXCEPTION_ACCESS_VIOLATION:
		{
			// Access violation type - Write/Read.
			_ftprintf(fp,
				_T("\t\tAccess violation\n")
				_T("\n")
				_T("@:         %s\n")
				_T("Operate:   %s\n")
				_T("Address:   0x%08X\n")
				_T("LastError: 0x%08X\n"),
				szModeleInfo,
				(E.ExceptionInformation[0]) ? _T("Write") : _T("Read"), 
				E.ExceptionInformation[1], dwLastError);
		}
		break;

	default:
		{
			_ftprintf(fp,
				_T("\t\tOTHER\n")
				_T("\n")
				_T("@:         %s\n")
				_T("Code:      0x%08X\n")
				_T("LastError: 0x%08X\n"),
				szModeleInfo,
				E.ExceptionCode, dwLastError);
		}
		break;
	}

}
示例#6
0
文件: Crash.cpp 项目: qiqisteve/wxsj2
//******************************************************************
void Get_Call_Stack(PEXCEPTION_POINTERS pException, FILE* fp)
//******************************************************************
// Fill Str with call stack info.
// pException can be either GetExceptionInformation() or NULL.
// If pException = NULL - get current call stack.
{
	TCHAR	Module_Name[MAX_PATH];
	PBYTE	Module_Addr = 0;
	PBYTE	Module_Addr_1;
	
#pragma warning(disable: 4200)	//nonstandard extension used : zero-sized array in struct/union
	typedef struct STACK
	{
		STACK *	Ebp;
		PBYTE	Ret_Addr;
		DWORD	Param[0];
	} STACK, * PSTACK;
#pragma warning(default: 4200)

	STACK	Stack = {0, 0};
	PSTACK	Ebp;

	if (pException)		//fake frame for exception address
	{
		Stack.Ebp = (PSTACK)(DWORD_PTR)pException->ContextRecord->Ebp;
		Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress;
		Ebp = &Stack;
	}
	else
	{
		Ebp = (PSTACK)&pException - 1;	//frame addr of Get_Call_Stack()

		// Skip frame of Get_Call_Stack().
		if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))
			Ebp = Ebp->Ebp;		//caller ebp
	}

	// Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX.
	// Break trace on wrong stack frame.
	for (int Ret_Addr_I = 0;
		(Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));
		Ret_Addr_I++, Ebp = Ebp->Ebp)
	{
		// If module with Ebp->Ret_Addr found.
		if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr_1))
		{
			if (Module_Addr_1 != Module_Addr)	//new module
			{
				// Save module's address and full path.
				Module_Addr = Module_Addr_1;
				_ftprintf(fp, _T("%08X  %s")NL, (LONG_PTR)Module_Addr, Module_Name);
			}

			// Save call offset.
			_ftprintf(fp, _T("  +%08X"), Ebp->Ret_Addr - Module_Addr);

			// Save 5 params of the call. We don't know the real number of params.
			if (pException && !Ret_Addr_I)	//fake frame for exception address
				_ftprintf(fp, _T("  Exception Offset") NL);
			else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD)))
			{
				_ftprintf(fp, _T("  (%X, %X, %X, %X, %X)") NL,
					Ebp->Param[0], Ebp->Param[1], Ebp->Param[2], Ebp->Param[3], Ebp->Param[4]);
			}
		}
		else
			_ftprintf(fp, _T("%08X")NL, (LONG_PTR)(Ebp->Ret_Addr));
	}

} //Get_Call_Stack
示例#7
0
VOID CreateExceptionDesc(PEXCEPTION_POINTERS pException, FILE* fp, UINT dwLastError)
{
	if (!pException || !fp) return;

	EXCEPTION_RECORD &	E = *pException->ExceptionRecord;
	CONTEXT &			C = *pException->ContextRecord;

	//取得异常发生地
	TCHAR		szModeleInfo[MAX_PATH];
	TCHAR		Module_Name[MAX_PATH];
	PBYTE		Module_Addr;
	if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr))
	{
		_sntprintf(szModeleInfo, MAX_PATH, _T("%s"), Module_Name);
	}
	else
	{
		_sntprintf(szModeleInfo, MAX_PATH, _T("%08X"), (DWORD_PTR)(E.ExceptionAddress));
	}

	switch(E.ExceptionCode)
	{
		//转化后的c++异常
	case 0XE000C0DE:
		{
			_ftprintf(fp,
				_T("C++ Exception\n")
				_T("\n")
				_T("Expr:      %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n"),
				E.ExceptionInformation[0],
				E.ExceptionInformation[1],
				E.ExceptionInformation[2],
				E.ExceptionInformation[3],
				E.ExceptionInformation[4],
				E.ExceptionInformation[5],
				E.ExceptionInformation[6],
				E.ExceptionInformation[7],
				E.ExceptionInformation[8],
				E.ExceptionInformation[9],
				E.ExceptionInformation[10],
				E.ExceptionInformation[11],
				E.ExceptionInformation[12],
				E.ExceptionInformation[13],
				E.ExceptionInformation[14]);
		}
		break;

		//试图对一个虚地址进行读写
	case EXCEPTION_ACCESS_VIOLATION:
		{
			// Access violation type - Write/Read.
			_ftprintf(fp,
				_T("\t\tAccess violation\n")
				_T("\n")
				_T("@:         %s\n")
				_T("Operate:   %s\n")
				_T("Address:   0x%08X\n")
				_T("LastError: 0x%08X\n"),
				szModeleInfo,
				(E.ExceptionInformation[0]) ? _T("Write") : _T("Read"), 
				E.ExceptionInformation[1], dwLastError);
		}
		break;

	default:
		{
			_ftprintf(fp,
				_T("\t\tOTHER\n")
				_T("\n")
				_T("@:         %s\n")
				_T("Code:      0x%08X\n")
				_T("LastError: 0x%08X\n"),
				szModeleInfo,
				E.ExceptionCode, dwLastError);
		}
		break;
	}

}
示例#8
0
//*************************************************************
LLSD WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException)
//*************************************************************
// Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str.
{
	LLSD info;
	LPWSTR		Str;
	int			Str_Len;
//	int			i;
	LPWSTR		Module_Name = new WCHAR[MAX_PATH];
	PBYTE		Module_Addr;
	HANDLE		hFile;
	FILETIME	Last_Write_Time;
	FILETIME	Local_File_Time;
	SYSTEMTIME	T;

	Str = new WCHAR[DUMP_SIZE_MAX];
	Str_Len = 0;
	if (!Str)
		return NULL;
	
	Get_Version_Str(info);
	
	GetModuleFileName(NULL, Str, MAX_PATH);
	info["Process"] = ll_convert_wide_to_string(Str);
	info["ThreadID"] = (S32)GetCurrentThreadId();

	// If exception occurred.
	if (pException)
	{
		EXCEPTION_RECORD &	E = *pException->ExceptionRecord;
		CONTEXT &			C = *pException->ContextRecord;

		// If module with E.ExceptionAddress found - save its path and date.
		if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr))
		{
			info["Module"] = ll_convert_wide_to_string(Module_Name);

			if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
				FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
			{
				if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time))
				{
					FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time);
					FileTimeToSystemTime(&Local_File_Time, &T);

					info["DateModified"] = llformat("%02d/%02d/%d", T.wMonth, T.wDay, T.wYear);
				}
				CloseHandle(hFile);
			}
		}
		else
		{
			info["ExceptionAddr"] = (int)E.ExceptionAddress;
		}
		
		info["ExceptionCode"] = (int)E.ExceptionCode;
		
		/*
		//TODO: Fix this
		if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
		{
			// Access violation type - Write/Read.
			LLSD exception_info;
			exception_info["Type"] = E.ExceptionInformation[0] ? "Write" : "Read";
			exception_info["Address"] = llformat("%08x", E.ExceptionInformation[1]);
			info["Exception Information"] = exception_info;
		}
		*/

		
		// Save instruction that caused exception.
		/*
		std::string str;
		for (i = 0; i < 16; i++)
			str += llformat(" %02X", PBYTE(E.ExceptionAddress)[i]);
		info["Instruction"] = str;
		*/
		LLSD registers;
		registers["EAX"] = (int)C.Eax;
		registers["EBX"] = (int)C.Ebx;
		registers["ECX"] = (int)C.Ecx;
		registers["EDX"] = (int)C.Edx;
		registers["ESI"] = (int)C.Esi;
		registers["EDI"] = (int)C.Edi;
		registers["ESP"] = (int)C.Esp;
		registers["EBP"] = (int)C.Ebp;
		registers["EIP"] = (int)C.Eip;
		registers["EFlags"] = (int)C.EFlags;
		info["Registers"] = registers;
	} //if (pException)
	
	// Save call stack info.
	Get_Call_Stack(pException->ExceptionRecord, pException->ContextRecord, info);

	return info;
} //Get_Exception_Info
示例#9
0
//******************************************************************
void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record, 
						   const CONTEXT* context_record, 
						   LLSD& info)
//******************************************************************
// Fill Str with call stack info.
// pException can be either GetExceptionInformation() or NULL.
// If pException = NULL - get current call stack.
{
	LPWSTR	Module_Name = new WCHAR[MAX_PATH];
	PBYTE	Module_Addr = 0;
	LLSD params;
	PBYTE	Esp = NULL;
	LLSD tmp_info;

	bool fake_frame = false;
	bool ebp_used = false;
	const int HEURISTIC_MAX_WALK = 20;
	int heuristic_walk_i = 0;
	int Ret_Addr_I = 0;

	WSTACK	Stack = {0, 0};
	PSTACK	Ebp;

	if (exception_record && context_record)		//fake frame for exception address
	{
		Stack.Ebp = (PSTACK)(context_record->Ebp);
		Stack.Ret_Addr = (PBYTE)exception_record->ExceptionAddress;
		Ebp = &Stack;
		Esp = (PBYTE) context_record->Esp;
		fake_frame = true;
	}
	else if(context_record)
	{
        Ebp = (PSTACK)(context_record->Ebp);
		Esp = (PBYTE)(context_record->Esp);
	}
	else
	{
		Ebp = (PSTACK)&exception_record - 1;	//frame addr of Get_Call_Stack()
		Esp = (PBYTE)&exception_record;

		// Skip frame of Get_Call_Stack().
		if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))
			Ebp = Ebp->Ebp;		//caller ebp
	}

	// Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX.
	// Break trace on wrong stack frame.
	for (Ret_Addr_I = 0;
		heuristic_walk_i < HEURISTIC_MAX_WALK && 
		Ret_Addr_I < CALL_TRACE_MAX && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));
		Ret_Addr_I++)
	{
		// If module with Ebp->Ret_Addr found.
		if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr))
		{
			// Save module's address and full path.
			tmp_info["CallStack"][Ret_Addr_I]["ModuleName"] = ll_convert_wide_to_string(Module_Name);
			tmp_info["CallStack"][Ret_Addr_I]["ModuleAddress"] = (int)Module_Addr;
			tmp_info["CallStack"][Ret_Addr_I]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr);

			// Save 5 params of the call. We don't know the real number of params.
			if (fake_frame && !Ret_Addr_I)	//fake frame for exception address
				params[0] = "Exception Offset";
			else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD)))
			{
				for(int j = 0; j < 5; ++j)
				{
					params[j] = (int)Ebp->Param[j];
				}
			}
			tmp_info["CallStack"][Ret_Addr_I]["Parameters"] = params;
		}

		tmp_info["CallStack"][Ret_Addr_I]["ReturnAddress"] = (int)Ebp->Ret_Addr;

		// get ready for next frame
		// Set ESP to just after return address.  Not the real esp, but just enough after the return address
		if(!fake_frame) {
			Esp = (PBYTE)Ebp + 8;
		} 
		else
		{
			fake_frame = false;
		}

		// is next ebp valid?
		// only run if we've never found a good ebp
		// and make sure the one after is valid as well
		if(	!ebp_used && 
			shouldUseStackWalker(Ebp, 2))
		{
			heuristic_walk_i++;
			PBYTE new_ebp = get_valid_frame(Esp);
			if (new_ebp != NULL)
			{
				Ebp = (PSTACK)new_ebp;
			}
		}
		else
		{
			ebp_used = true;
			Ebp = Ebp->Ebp;
		}
	}
/* TODO remove or turn this code back on to edit the stack after i see a few raw ones. -Palmer
	// Now go back through and edit out heuristic stacks that could very well be bogus.
	// Leave the top and the last 3 stack chosen by the heuristic, however.
	if(heuristic_walk_i > 2)
	{
		info["CallStack"][0] = tmp_info["CallStack"][0];
		std::string ttest = info["CallStack"][0]["ModuleName"];
		for(int cur_frame = 1; 
			(cur_frame + heuristic_walk_i - 2 < Ret_Addr_I); 
			++cur_frame)
		{
			// edit out the middle heuristic found frames
			info["CallStack"][cur_frame] = tmp_info["CallStack"][cur_frame + heuristic_walk_i - 2];
		}
	}
	else
	{
		info = tmp_info;
	}
*/
	info = tmp_info;
	info["HeuristicWalkI"] = heuristic_walk_i;
	info["EbpUsed"] = ebp_used;

} //Get_Call_Stack