diff options
Diffstat (limited to 'indra/newview/llwindebug.cpp')
-rw-r--r-- | indra/newview/llwindebug.cpp | 250 |
1 files changed, 165 insertions, 85 deletions
diff --git a/indra/newview/llwindebug.cpp b/indra/newview/llwindebug.cpp index 07a5316816..1d4f1a64f5 100644 --- a/indra/newview/llwindebug.cpp +++ b/indra/newview/llwindebug.cpp @@ -123,7 +123,9 @@ MODULE32_NEST Module32Next_; #define NL L"\r\n" //new line 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 ) { @@ -186,69 +188,6 @@ BOOL GetProcessThreadIDs(DWORD process_id, std::vector<DWORD>& thread_ids) return( TRUE ); } -void WINAPI GetCallStackData(const CONTEXT* context_struct, 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; - - typedef struct STACK - { - STACK * Ebp; - PBYTE Ret_Addr; - DWORD Param[0]; - } STACK, * PSTACK; - - PSTACK Ebp; - - if(context_struct) - { - Ebp = (PSTACK)context_struct->Ebp; - } - else - { - // The context struct is NULL, - // so we will use the current stack. - Ebp = (PSTACK)&context_struct - 1; - - // Skip frame of GetCallStackData(). - 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, i = 0; - (Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr)); - Ret_Addr_I++, Ebp = Ebp->Ebp, ++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. - info["CallStack"][i]["ModuleName"] = ll_convert_wide_to_string(Module_Name); - info["CallStack"][i]["ModuleAddress"] = (int)Module_Addr; - info["CallStack"][i]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr); - - LLSD params; - // Save 5 params of the call. We don't know the real number of params. - if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD))) - { - for(int j = 0; j < 5; ++j) - { - params[j] = (int)Ebp->Param[j]; - } - } - info["CallStack"][i]["Parameters"] = params; - } - info["CallStack"][i]["ReturnAddress"] = (int)Ebp->Ret_Addr; - } -} - BOOL GetThreadCallStack(DWORD thread_id, LLSD& info) { if(GetCurrentThreadId() == thread_id) @@ -273,7 +212,7 @@ BOOL GetThreadCallStack(DWORD thread_id, LLSD& info) context_struct.ContextFlags = CONTEXT_FULL; if(GetThreadContext(thread_handle, &context_struct)) { - GetCallStackData(&context_struct, info); + Get_Call_Stack(NULL, &context_struct, info); result = true; } ResumeThread(thread_handle); @@ -328,16 +267,98 @@ BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & M 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; +} //****************************************************************** -void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info) +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 = 10; + int heuristic_walk_i = 0; + int Ret_Addr_I = 0; + typedef struct STACK { STACK * Ebp; @@ -348,15 +369,23 @@ void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info) STACK Stack = {0, 0}; PSTACK Ebp; - if (pException) //fake frame for exception address + if (exception_record && context_record) //fake frame for exception address { - Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp; - Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress; + 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)&pException - 1; //frame addr of Get_Call_Stack() + 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))) @@ -365,22 +394,21 @@ void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info) // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX. // Break trace on wrong stack frame. - for (int Ret_Addr_I = 0, i = 0; - (Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr)); - Ret_Addr_I++, Ebp = Ebp->Ebp, ++i) + 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. - info["CallStack"][i]["ModuleName"] = ll_convert_wide_to_string(Module_Name); - info["CallStack"][i]["ModuleAddress"] = (int)Module_Addr; - info["CallStack"][i]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr); + 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); - LLSD params; // 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 + if (fake_frame && !Ret_Addr_I) //fake frame for exception address params[0] = "Exception Offset"; else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD))) { @@ -389,10 +417,62 @@ void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info) params[j] = (int)Ebp->Param[j]; } } - info["CallStack"][i]["Parameters"] = params; + 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 + if( !ebp_used && + (IsBadReadPtr(Ebp->Ebp, sizeof(PSTACK)) || + IsBadCodePtr(FARPROC(Ebp->Ebp->Ret_Addr)) || + !Get_Module_By_Ret_Addr(Ebp->Ebp->Ret_Addr, Module_Name, Module_Addr))) + { + 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; } - info["CallStack"][i]["ReturnAddress"] = (int)Ebp->Ret_Addr; } + + // Now go back through and edit out heuristic stacks that could very well be bogus. + // Leave the top and the last 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; + } + + } //Get_Call_Stack //*********************************** @@ -509,7 +589,7 @@ LLSD WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException) } //if (pException) // Save call stack info. - Get_Call_Stack(pException, info); + Get_Call_Stack(pException->ExceptionRecord, pException->ContextRecord, info); return info; } //Get_Exception_Info @@ -566,7 +646,7 @@ LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter( llinfos << "Someone tried to set the exception filter. Listing call stack modules" << llendl; LLSD cs_info; - GetCallStackData(NULL, cs_info); + Get_Call_Stack(NULL, NULL, cs_info); if(cs_info.has("CallStack") && cs_info["CallStack"].isArray()) { |