aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llwindebug.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/llwindebug.cpp')
-rw-r--r--linden/indra/newview/llwindebug.cpp250
1 files changed, 165 insertions, 85 deletions
diff --git a/linden/indra/newview/llwindebug.cpp b/linden/indra/newview/llwindebug.cpp
index 7d44fcd..b595073 100644
--- a/linden/indra/newview/llwindebug.cpp
+++ b/linden/indra/newview/llwindebug.cpp
@@ -122,7 +122,9 @@ MODULE32_NEST Module32Next_;
122#define NL L"\r\n" //new line 122#define NL L"\r\n" //new line
123 123
124BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr); 124BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr);
125 125void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record,
126 const CONTEXT* context_record,
127 LLSD& info);
126 128
127void printError( CHAR* msg ) 129void printError( CHAR* msg )
128{ 130{
@@ -185,69 +187,6 @@ BOOL GetProcessThreadIDs(DWORD process_id, std::vector<DWORD>& thread_ids)
185 return( TRUE ); 187 return( TRUE );
186} 188}
187 189
188void WINAPI GetCallStackData(const CONTEXT* context_struct, LLSD& info)
189{
190 // Fill Str with call stack info.
191 // pException can be either GetExceptionInformation() or NULL.
192 // If pException = NULL - get current call stack.
193
194 LPWSTR Module_Name = new WCHAR[MAX_PATH];
195 PBYTE Module_Addr = 0;
196
197 typedef struct STACK
198 {
199 STACK * Ebp;
200 PBYTE Ret_Addr;
201 DWORD Param[0];
202 } STACK, * PSTACK;
203
204 PSTACK Ebp;
205
206 if(context_struct)
207 {
208 Ebp = (PSTACK)context_struct->Ebp;
209 }
210 else
211 {
212 // The context struct is NULL,
213 // so we will use the current stack.
214 Ebp = (PSTACK)&context_struct - 1;
215
216 // Skip frame of GetCallStackData().
217 if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))
218 Ebp = Ebp->Ebp; //caller ebp
219 }
220
221 // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX.
222 // Break trace on wrong stack frame.
223 for (int Ret_Addr_I = 0, i = 0;
224 (Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));
225 Ret_Addr_I++, Ebp = Ebp->Ebp, ++i)
226 {
227 // If module with Ebp->Ret_Addr found.
228
229 if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr))
230 {
231 // Save module's address and full path.
232 info["CallStack"][i]["ModuleName"] = ll_convert_wide_to_string(Module_Name);
233 info["CallStack"][i]["ModuleAddress"] = (int)Module_Addr;
234 info["CallStack"][i]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr);
235
236 LLSD params;
237 // Save 5 params of the call. We don't know the real number of params.
238 if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD)))
239 {
240 for(int j = 0; j < 5; ++j)
241 {
242 params[j] = (int)Ebp->Param[j];
243 }
244 }
245 info["CallStack"][i]["Parameters"] = params;
246 }
247 info["CallStack"][i]["ReturnAddress"] = (int)Ebp->Ret_Addr;
248 }
249}
250
251BOOL GetThreadCallStack(DWORD thread_id, LLSD& info) 190BOOL GetThreadCallStack(DWORD thread_id, LLSD& info)
252{ 191{
253 if(GetCurrentThreadId() == thread_id) 192 if(GetCurrentThreadId() == thread_id)
@@ -272,7 +211,7 @@ BOOL GetThreadCallStack(DWORD thread_id, LLSD& info)
272 context_struct.ContextFlags = CONTEXT_FULL; 211 context_struct.ContextFlags = CONTEXT_FULL;
273 if(GetThreadContext(thread_handle, &context_struct)) 212 if(GetThreadContext(thread_handle, &context_struct))
274 { 213 {
275 GetCallStackData(&context_struct, info); 214 Get_Call_Stack(NULL, &context_struct, info);
276 result = true; 215 result = true;
277 } 216 }
278 ResumeThread(thread_handle); 217 ResumeThread(thread_handle);
@@ -327,16 +266,98 @@ BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & M
327 return found; 266 return found;
328} //Get_Module_By_Ret_Addr 267} //Get_Module_By_Ret_Addr
329 268
269bool has_valid_call_before(PDWORD cur_stack_loc)
270{
271 PBYTE p_first_byte = (PBYTE)(*cur_stack_loc - 1);
272 PBYTE p_second_byte = (PBYTE)(*cur_stack_loc -2);
273 PBYTE p_fifth_byte = (PBYTE)(*cur_stack_loc - 5);
274 PBYTE p_sixth_byte = (PBYTE)(*cur_stack_loc - 6);
275
276 // make sure we can read it
277 if(IsBadReadPtr(p_sixth_byte, 6 * sizeof(BYTE)))
278 {
279 return false;
280 }
281
282 // check for 9a + 4 bytes
283 if(*p_fifth_byte == 0x9A)
284 {
285 return true;
286 }
287
288 // Check for E8 + 4 bytes and last byte is 00 or FF
289 if(*p_fifth_byte == 0xE8 && (*p_first_byte == 0x00 || *p_first_byte == 0xFF))
290 {
291 return true;
292 }
293
294 // the other is six bytes
295 if(*p_sixth_byte == 0xFF || *p_second_byte == 0xFF)
296 {
297 return true;
298 }
299
300 return false;
301}
302
303PBYTE get_valid_frame(PBYTE esp)
304{
305 PDWORD cur_stack_loc = NULL;
306 const int max_search = 400;
307 WCHAR module_name[MAX_PATH];
308 PBYTE module_addr = 0;
309
310 // round to highest multiple of four
311 esp = (esp + (4 - ((int)esp % 4)) % 4);
312
313 // scroll through stack a few hundred places.
314 for (cur_stack_loc = (PDWORD) esp; cur_stack_loc < (PDWORD)esp + max_search; cur_stack_loc += 1)
315 {
316 // if you can read the pointer,
317 if (IsBadReadPtr(cur_stack_loc, sizeof(PDWORD)))
318 {
319 continue;
320 }
321
322 // check if it's in a module
323 if (!Get_Module_By_Ret_Addr((PBYTE)*cur_stack_loc, module_name, module_addr))
324 {
325 continue;
326 }
327
328 // check if the code before the instruction ptr is a call
329 if(!has_valid_call_before(cur_stack_loc))
330 {
331 continue;
332 }
333
334 // if these all pass, return that ebp, otherwise continue till we're dead
335 return (PBYTE)(cur_stack_loc - 1);
336 }
337
338 return NULL;
339}
330//****************************************************************** 340//******************************************************************
331void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info) 341void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record,
342 const CONTEXT* context_record,
343 LLSD& info)
332//****************************************************************** 344//******************************************************************
333// Fill Str with call stack info. 345// Fill Str with call stack info.
334// pException can be either GetExceptionInformation() or NULL. 346// pException can be either GetExceptionInformation() or NULL.
335// If pException = NULL - get current call stack. 347// If pException = NULL - get current call stack.
336{ 348{
337 LPWSTR Module_Name = new WCHAR[MAX_PATH]; 349 LPWSTR Module_Name = new WCHAR[MAX_PATH];
338 PBYTE Module_Addr = 0; 350 PBYTE Module_Addr = 0;
339 351 LLSD params;
352 PBYTE Esp = NULL;
353 LLSD tmp_info;
354
355 bool fake_frame = false;
356 bool ebp_used = false;
357 const int HEURISTIC_MAX_WALK = 10;
358 int heuristic_walk_i = 0;
359 int Ret_Addr_I = 0;
360
340 typedef struct STACK 361 typedef struct STACK
341 { 362 {
342 STACK * Ebp; 363 STACK * Ebp;
@@ -347,15 +368,23 @@ void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info)
347 STACK Stack = {0, 0}; 368 STACK Stack = {0, 0};
348 PSTACK Ebp; 369 PSTACK Ebp;
349 370
350 if (pException) //fake frame for exception address 371 if (exception_record && context_record) //fake frame for exception address
351 { 372 {
352 Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp; 373 Stack.Ebp = (PSTACK)(context_record->Ebp);
353 Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress; 374 Stack.Ret_Addr = (PBYTE)exception_record->ExceptionAddress;
354 Ebp = &Stack; 375 Ebp = &Stack;
376 Esp = (PBYTE) context_record->Esp;
377 fake_frame = true;
378 }
379 else if(context_record)
380 {
381 Ebp = (PSTACK)(context_record->Ebp);
382 Esp = (PBYTE)(context_record->Esp);
355 } 383 }
356 else 384 else
357 { 385 {
358 Ebp = (PSTACK)&pException - 1; //frame addr of Get_Call_Stack() 386 Ebp = (PSTACK)&exception_record - 1; //frame addr of Get_Call_Stack()
387 Esp = (PBYTE)&exception_record;
359 388
360 // Skip frame of Get_Call_Stack(). 389 // Skip frame of Get_Call_Stack().
361 if (!IsBadReadPtr(Ebp, sizeof(PSTACK))) 390 if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))
@@ -364,22 +393,21 @@ void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info)
364 393
365 // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX. 394 // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX.
366 // Break trace on wrong stack frame. 395 // Break trace on wrong stack frame.
367 for (int Ret_Addr_I = 0, i = 0; 396 for (Ret_Addr_I = 0;
368 (Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr)); 397 heuristic_walk_i < HEURISTIC_MAX_WALK &&
369 Ret_Addr_I++, Ebp = Ebp->Ebp, ++i) 398 Ret_Addr_I < CALL_TRACE_MAX && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));
399 Ret_Addr_I++)
370 { 400 {
371 // If module with Ebp->Ret_Addr found. 401 // If module with Ebp->Ret_Addr found.
372
373 if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr)) 402 if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr))
374 { 403 {
375 // Save module's address and full path. 404 // Save module's address and full path.
376 info["CallStack"][i]["ModuleName"] = ll_convert_wide_to_string(Module_Name); 405 tmp_info["CallStack"][Ret_Addr_I]["ModuleName"] = ll_convert_wide_to_string(Module_Name);
377 info["CallStack"][i]["ModuleAddress"] = (int)Module_Addr; 406 tmp_info["CallStack"][Ret_Addr_I]["ModuleAddress"] = (int)Module_Addr;
378 info["CallStack"][i]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr); 407 tmp_info["CallStack"][Ret_Addr_I]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr);
379 408
380 LLSD params;
381 // Save 5 params of the call. We don't know the real number of params. 409 // Save 5 params of the call. We don't know the real number of params.
382 if (pException && !Ret_Addr_I) //fake frame for exception address 410 if (fake_frame && !Ret_Addr_I) //fake frame for exception address
383 params[0] = "Exception Offset"; 411 params[0] = "Exception Offset";
384 else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD))) 412 else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD)))
385 { 413 {
@@ -388,10 +416,62 @@ void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info)
388 params[j] = (int)Ebp->Param[j]; 416 params[j] = (int)Ebp->Param[j];
389 } 417 }
390 } 418 }
391 info["CallStack"][i]["Parameters"] = params; 419 tmp_info["CallStack"][Ret_Addr_I]["Parameters"] = params;
420 }
421
422 tmp_info["CallStack"][Ret_Addr_I]["ReturnAddress"] = (int)Ebp->Ret_Addr;
423
424 // get ready for next frame
425 // Set ESP to just after return address. Not the real esp, but just enough after the return address
426 if(!fake_frame) {
427 Esp = (PBYTE)Ebp + 8;
428 }
429 else
430 {
431 fake_frame = false;
432 }
433
434 // is next ebp valid?
435 // only run if we've never found a good ebp
436 if( !ebp_used &&
437 (IsBadReadPtr(Ebp->Ebp, sizeof(PSTACK)) ||
438 IsBadCodePtr(FARPROC(Ebp->Ebp->Ret_Addr)) ||
439 !Get_Module_By_Ret_Addr(Ebp->Ebp->Ret_Addr, Module_Name, Module_Addr)))
440 {
441 heuristic_walk_i++;
442 PBYTE new_ebp = get_valid_frame(Esp);
443 if (new_ebp != NULL)
444 {
445 Ebp = (PSTACK)new_ebp;
446 }
447 }
448 else
449 {
450 ebp_used = true;
451 Ebp = Ebp->Ebp;
392 } 452 }
393 info["CallStack"][i]["ReturnAddress"] = (int)Ebp->Ret_Addr;
394 } 453 }
454
455 // Now go back through and edit out heuristic stacks that could very well be bogus.
456 // Leave the top and the last stack chosen by the heuristic, however.
457 if(heuristic_walk_i > 2)
458 {
459 info["CallStack"][0] = tmp_info["CallStack"][0];
460 std::string ttest = info["CallStack"][0]["ModuleName"];
461 for(int cur_frame = 1;
462 (cur_frame + heuristic_walk_i - 2 < Ret_Addr_I);
463 ++cur_frame)
464 {
465 // edit out the middle heuristic found frames
466 info["CallStack"][cur_frame] = tmp_info["CallStack"][cur_frame + heuristic_walk_i - 2];
467 }
468 }
469 else
470 {
471 info = tmp_info;
472 }
473
474
395} //Get_Call_Stack 475} //Get_Call_Stack
396 476
397//*********************************** 477//***********************************
@@ -508,7 +588,7 @@ LLSD WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException)
508 } //if (pException) 588 } //if (pException)
509 589
510 // Save call stack info. 590 // Save call stack info.
511 Get_Call_Stack(pException, info); 591 Get_Call_Stack(pException->ExceptionRecord, pException->ContextRecord, info);
512 592
513 return info; 593 return info;
514} //Get_Exception_Info 594} //Get_Exception_Info
@@ -565,7 +645,7 @@ LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(
565 645
566 llinfos << "Someone tried to set the exception filter. Listing call stack modules" << llendl; 646 llinfos << "Someone tried to set the exception filter. Listing call stack modules" << llendl;
567 LLSD cs_info; 647 LLSD cs_info;
568 GetCallStackData(NULL, cs_info); 648 Get_Call_Stack(NULL, NULL, cs_info);
569 649
570 if(cs_info.has("CallStack") && cs_info["CallStack"].isArray()) 650 if(cs_info.has("CallStack") && cs_info["CallStack"].isArray())
571 { 651 {