summaryrefslogtreecommitdiff
path: root/indra/newview/llwindebug.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llwindebug.cpp')
-rw-r--r--indra/newview/llwindebug.cpp250
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())
{