llwindebug.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:24k
- /**
- * @file llwindebug.cpp
- * @brief Windows debugging functions
- *
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2010, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include <tchar.h>
- #include <tlhelp32.h>
- #include "llwindebug.h"
- #include "llviewercontrol.h"
- #include "lldir.h"
- #include "llsd.h"
- #include "llsdserialize.h"
- #pragma warning(disable: 4200) //nonstandard extension used : zero-sized array in struct/union
- #pragma warning(disable: 4100) //unreferenced formal parameter
- /*
- LLSD Block for Windows Dump Information
- <llsd>
- <map>
- <key>Platform</key>
- <string></string>
- <key>Process</key>
- <string></string>
- <key>Module</key>
- <string></string>
- <key>DateModified</key>
- <string></string>
- <key>ExceptionCode</key>
- <string></string>
- <key>ExceptionRead/WriteAddress</key>
- <string></string>
- <key>Instruction</key>
- <string></string>
- <key>Registers</key>
- <map>
- <!-- Continued for all registers -->
- <key>EIP</key>
- <string>...</string>
- <!-- ... -->
- </map>
- <key>Call Stack</key>
- <array>
- <!-- One map per stack frame -->
- <map>
- <key>ModuleName</key>
- <string></string>
- <key>ModuleBaseAddress</key>
- <string></string>
- <key>ModuleOffsetAddress</key>
- <string></string>
- <key>Parameters</key>
- <array>
- <string></string>
- </array>
- </map>
- <!-- ... -->
- </array>
- </map>
- </llsd>
- */
- extern void (*gCrashCallback)(void);
- // based on dbghelp.h
- typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
- CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
- CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
- CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
- );
- MINIDUMPWRITEDUMP f_mdwp = NULL;
- #undef UNICODE
- static LPTOP_LEVEL_EXCEPTION_FILTER gFilterFunc = NULL;
- HMODULE hDbgHelp;
- // Tool Help functions.
- typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);
- typedef BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
- typedef BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
- CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_;
- MODULE32_FIRST Module32First_;
- MODULE32_NEST Module32Next_;
- #define DUMP_SIZE_MAX 8000 //max size of our dump
- #define CALL_TRACE_MAX ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40)) //max number of traced calls
- #define NL L"rn" //new line
- typedef struct STACK
- {
- STACK * Ebp;
- PBYTE Ret_Addr;
- DWORD Param[0];
- } STACK, * PSTACK;
- BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr);
- void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record,
- const CONTEXT* context_record,
- LLSD& info);
- void printError( CHAR* msg )
- {
- DWORD eNum;
- TCHAR sysMsg[256];
- TCHAR* p;
- eNum = GetLastError( );
- FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, eNum,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- sysMsg, 256, NULL );
- // Trim the end of the line and terminate it with a null
- p = sysMsg;
- while( ( *p > 31 ) || ( *p == 9 ) )
- ++p;
- do { *p-- = 0; } while( ( p >= sysMsg ) &&
- ( ( *p == '.' ) || ( *p < 33 ) ) );
- // Display the message
- printf( "n WARNING: %s failed with error %d (%s)", msg, eNum, sysMsg );
- }
- BOOL GetProcessThreadIDs(DWORD process_id, std::vector<DWORD>& thread_ids)
- {
- HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
- THREADENTRY32 te32;
-
- // Take a snapshot of all running threads
- hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
- if( hThreadSnap == INVALID_HANDLE_VALUE )
- return( FALSE );
-
- // Fill in the size of the structure before using it.
- te32.dwSize = sizeof(THREADENTRY32 );
-
- // Retrieve information about the first thread,
- // and exit if unsuccessful
- if( !Thread32First( hThreadSnap, &te32 ) )
- {
- printError( "Thread32First" ); // Show cause of failure
- CloseHandle( hThreadSnap ); // Must clean up the snapshot object!
- return( FALSE );
- }
- // Now walk the thread list of the system,
- // and display information about each thread
- // associated with the specified process
- do
- {
- if( te32.th32OwnerProcessID == process_id )
- {
- thread_ids.push_back(te32.th32ThreadID);
- }
- } while( Thread32Next(hThreadSnap, &te32 ) );
- // Don't forget to clean up the snapshot object.
- CloseHandle( hThreadSnap );
- return( TRUE );
- }
- BOOL GetThreadCallStack(DWORD thread_id, LLSD& info)
- {
- if(GetCurrentThreadId() == thread_id)
- {
- // Early exit for the current thread.
- // Suspending the current thread would be a bad idea.
- // Plus you can't retrieve a valid current thread context.
- return false;
- }
- HANDLE thread_handle = INVALID_HANDLE_VALUE;
- thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id);
- if(INVALID_HANDLE_VALUE == thread_handle)
- {
- return FALSE;
- }
- BOOL result = false;
- if(-1 != SuspendThread(thread_handle))
- {
- CONTEXT context_struct;
- context_struct.ContextFlags = CONTEXT_FULL;
- if(GetThreadContext(thread_handle, &context_struct))
- {
- Get_Call_Stack(NULL, &context_struct, info);
- result = true;
- }
- ResumeThread(thread_handle);
- }
- else
- {
- // Couldn't suspend thread.
- }
- CloseHandle(thread_handle);
- return result;
- }
- //Windows Call Stack Construction idea from
- //http://www.codeproject.com/tools/minidump.asp
- //****************************************************************************************
- BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr)
- //****************************************************************************************
- // Find module by Ret_Addr (address in the module).
- // Return Module_Name (full path) and Module_Addr (start address).
- // Return TRUE if found.
- {
- MODULEENTRY32 M = {sizeof(M)};
- HANDLE hSnapshot;
- bool found = false;
-
- if (CreateToolhelp32Snapshot_)
- {
- hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0);
-
- if ((hSnapshot != INVALID_HANDLE_VALUE) &&
- Module32First_(hSnapshot, &M))
- {
- do
- {
- if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize)
- {
- lstrcpyn(Module_Name, M.szExePath, MAX_PATH);
- Module_Addr = M.modBaseAddr;
- found = true;
- break;
- }
- } while (Module32Next_(hSnapshot, &M));
- }
- CloseHandle(hSnapshot);
- }
- return found;
- } //Get_Module_By_Ret_Addr
- bool has_valid_call_before(PDWORD cur_stack_loc)
- {
- PBYTE p_first_byte = (PBYTE)(*cur_stack_loc - 1);
- PBYTE p_second_byte = (PBYTE)(*cur_stack_loc -2);
- PBYTE p_fifth_byte = (PBYTE)(*cur_stack_loc - 5);
- PBYTE p_sixth_byte = (PBYTE)(*cur_stack_loc - 6);
- // make sure we can read it
- if(IsBadReadPtr(p_sixth_byte, 6 * sizeof(BYTE)))
- {
- return false;
- }
- // check for 9a + 4 bytes
- if(*p_fifth_byte == 0x9A)
- {
- return true;
- }
- // Check for E8 + 4 bytes and last byte is 00 or FF
- if(*p_fifth_byte == 0xE8 && (*p_first_byte == 0x00 || *p_first_byte == 0xFF))
- {
- return true;
- }
-
- // the other is six bytes
- if(*p_sixth_byte == 0xFF || *p_second_byte == 0xFF)
- {
- return true;
- }
- return false;
- }
- 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;
- }
- 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;
- }
- //******************************************************************
- 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;
- STACK 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
- //***********************************
- void WINAPI Get_Version_Str(LLSD& info)
- //***********************************
- // Fill Str with Windows version.
- {
- OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)}; //EX for NT 5.0 and later
- if (!GetVersionEx((POSVERSIONINFO)&V))
- {
- ZeroMemory(&V, sizeof(V));
- V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx((POSVERSIONINFO)&V);
- }
- if (V.dwPlatformId != VER_PLATFORM_WIN32_NT)
- V.dwBuildNumber = LOWORD(V.dwBuildNumber); //for 9x HIWORD(dwBuildNumber) = 0x04xx
- info["Platform"] = llformat("Windows: %d.%d.%d, SP %d.%d, Product Type %d", //SP - service pack, Product Type - VER_NT_WORKSTATION,...
- V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor, V.wServicePackMinor, V.wProductType);
- } //Get_Version_Str
- //*************************************************************
- 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
- #define UNICODE
- class LLMemoryReserve {
- public:
- LLMemoryReserve();
- ~LLMemoryReserve();
- void reserve();
- void release();
- protected:
- unsigned char *mReserve;
- static const size_t MEMORY_RESERVATION_SIZE;
- };
- LLMemoryReserve::LLMemoryReserve() :
- mReserve(NULL)
- {
- };
- LLMemoryReserve::~LLMemoryReserve()
- {
- release();
- }
- // I dunno - this just seemed like a pretty good value.
- const size_t LLMemoryReserve::MEMORY_RESERVATION_SIZE = 5 * 1024 * 1024;
- void LLMemoryReserve::reserve()
- {
- if(NULL == mReserve)
- mReserve = new unsigned char[MEMORY_RESERVATION_SIZE];
- };
- void LLMemoryReserve::release()
- {
- delete [] mReserve;
- mReserve = NULL;
- };
- static LLMemoryReserve gEmergencyMemoryReserve;
- #ifndef _M_IX86
- #error "The following code only works for x86!"
- #endif
- LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(
- LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
- {
- if(lpTopLevelExceptionFilter == gFilterFunc)
- return gFilterFunc;
- llinfos << "Someone tried to set the exception filter. Listing call stack modules" << llendl;
- LLSD cs_info;
- Get_Call_Stack(NULL, NULL, cs_info);
-
- if(cs_info.has("CallStack") && cs_info["CallStack"].isArray())
- {
- LLSD cs = cs_info["CallStack"];
- for(LLSD::array_iterator i = cs.beginArray();
- i != cs.endArray();
- ++i)
- {
- llinfos << "Module: " << (*i)["ModuleName"] << llendl;
- }
- }
-
- return gFilterFunc;
- }
- BOOL PreventSetUnhandledExceptionFilter()
- {
- HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));
- if (hKernel32 == NULL)
- return FALSE;
- void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
- if(pOrgEntry == NULL)
- return FALSE;
-
- unsigned char newJump[ 100 ];
- DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
- dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far
- void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
- DWORD dwNewEntryAddr = (DWORD) pNewFunc;
- DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
- newJump[ 0 ] = 0xE9; // JMP absolute
- memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc));
- SIZE_T bytesWritten;
- BOOL bRet = WriteProcessMemory(GetCurrentProcess(),
- pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);
- return bRet;
- }
- // static
- void LLWinDebug::initExceptionHandler(LPTOP_LEVEL_EXCEPTION_FILTER filter_func)
- {
- static bool s_first_run = true;
- // Load the dbghelp dll now, instead of waiting for the crash.
- // Less potential for stack mangling
- if (s_first_run)
- {
- // First, try loading from the directory that the app resides in.
- std::string local_dll_name = gDirUtilp->findFile("dbghelp.dll", gDirUtilp->getWorkingDir(), gDirUtilp->getExecutableDir());
- HMODULE hDll = NULL;
- hDll = LoadLibraryA(local_dll_name.c_str());
- if (!hDll)
- {
- hDll = LoadLibrary(L"dbghelp.dll");
- }
- if (!hDll)
- {
- LL_WARNS("AppInit") << "Couldn't find dbghelp.dll!" << LL_ENDL;
- }
- else
- {
- f_mdwp = (MINIDUMPWRITEDUMP) GetProcAddress(hDll, "MiniDumpWriteDump");
- if (!f_mdwp)
- {
- FreeLibrary(hDll);
- hDll = NULL;
- }
- }
- gEmergencyMemoryReserve.reserve();
- s_first_run = false;
- }
- // Try to get Tool Help library functions.
- HMODULE hKernel32;
- hKernel32 = GetModuleHandle(_T("KERNEL32"));
- CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot");
- Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32FirstW");
- Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32NextW");
- LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
- prev_filter = SetUnhandledExceptionFilter(filter_func);
- // *REMOVE:Mani
- //PreventSetUnhandledExceptionFilter();
- if(prev_filter != gFilterFunc)
- {
- LL_WARNS("AppInit")
- << "Replacing unknown exception (" << (void *)prev_filter << ") with (" << (void *)filter_func << ") !" << LL_ENDL;
- }
-
- gFilterFunc = filter_func;
- }
- bool LLWinDebug::checkExceptionHandler()
- {
- bool ok = true;
- LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
- prev_filter = SetUnhandledExceptionFilter(gFilterFunc);
- if (prev_filter != gFilterFunc)
- {
- LL_WARNS("AppInit") << "Our exception handler (" << (void *)gFilterFunc << ") replaced with " << prev_filter << "!" << LL_ENDL;
- ok = false;
- }
- if (prev_filter == NULL)
- {
- ok = FALSE;
- if (gFilterFunc == NULL)
- {
- LL_WARNS("AppInit") << "Exception handler uninitialized." << LL_ENDL;
- }
- else
- {
- LL_WARNS("AppInit") << "Our exception handler (" << (void *)gFilterFunc << ") replaced with NULL!" << LL_ENDL;
- }
- }
- return ok;
- }
- void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename)
- {
- if(f_mdwp == NULL || gDirUtilp == NULL)
- {
- return;
- //write_debug("No way to generate a minidump, no MiniDumpWriteDump function!n");
- }
- else
- {
- std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, filename);
- HANDLE hFile = CreateFileA(dump_path.c_str(),
- GENERIC_WRITE,
- FILE_SHARE_WRITE,
- NULL,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (hFile != INVALID_HANDLE_VALUE)
- {
- // Write the dump, ignoring the return value
- f_mdwp(GetCurrentProcess(),
- GetCurrentProcessId(),
- hFile,
- type,
- ExInfop,
- NULL,
- NULL);
- CloseHandle(hFile);
- }
- }
- }
- // static
- void LLWinDebug::generateCrashStacks(struct _EXCEPTION_POINTERS *exception_infop)
- {
- // *NOTE:Mani - This method is no longer the exception handler.
- // Its called from viewer_windows_exception_handler() and other places.
- //
- // Let go of a bunch of reserved memory to give library calls etc
- // a chance to execute normally in the case that we ran out of
- // memory.
- //
- LLSD info;
- std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
- "SecondLifeException");
- std::string log_path = dump_path + ".log";
- if (exception_infop)
- {
- // Since there is exception info... Release the hounds.
- gEmergencyMemoryReserve.release();
- if(gSavedSettings.getControl("SaveMinidump").notNull() && gSavedSettings.getBOOL("SaveMinidump"))
- {
- _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
- ExInfo.ThreadId = ::GetCurrentThreadId();
- ExInfo.ExceptionPointers = exception_infop;
- ExInfo.ClientPointers = NULL;
- writeDumpToFile(MiniDumpNormal, &ExInfo, "SecondLife.dmp");
- writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLifePlus.dmp");
- }
- info = Get_Exception_Info(exception_infop);
- }
- LLSD threads;
- std::vector<DWORD> thread_ids;
- GetProcessThreadIDs(GetCurrentProcessId(), thread_ids);
- for(std::vector<DWORD>::iterator th_itr = thread_ids.begin();
- th_itr != thread_ids.end();
- ++th_itr)
- {
- LLSD thread_info;
- if(*th_itr != GetCurrentThreadId())
- {
- GetThreadCallStack(*th_itr, thread_info);
- }
- if(thread_info)
- {
- threads[llformat("ID %d", *th_itr)] = thread_info;
- }
- }
- info["Threads"] = threads;
- llofstream out_file(log_path);
- LLSDSerialize::toPrettyXML(info, out_file);
- out_file.close();
- }
- void LLWinDebug::clearCrashStacks()
- {
- LLSD info;
- std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLifeException.log");
- LLFile::remove(dump_path);
- }