diff options
Diffstat (limited to 'linden/indra/newview/llwindebug.cpp')
-rw-r--r-- | linden/indra/newview/llwindebug.cpp | 250 |
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 | ||
124 | BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr); | 124 | BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr); |
125 | 125 | void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record, | |
126 | const CONTEXT* context_record, | ||
127 | LLSD& info); | ||
126 | 128 | ||
127 | void printError( CHAR* msg ) | 129 | void 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 | ||
188 | void 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 | |||
251 | BOOL GetThreadCallStack(DWORD thread_id, LLSD& info) | 190 | BOOL 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 | ||
269 | bool 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 | |||
303 | PBYTE 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 | //****************************************************************** |
331 | void WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, LLSD& info) | 341 | void 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 | { |