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.cpp194
1 files changed, 193 insertions, 1 deletions
diff --git a/linden/indra/newview/llwindebug.cpp b/linden/indra/newview/llwindebug.cpp
index cf30f34..e6c11d8 100644
--- a/linden/indra/newview/llwindebug.cpp
+++ b/linden/indra/newview/llwindebug.cpp
@@ -121,6 +121,172 @@ MODULE32_NEST Module32Next_;
121#define CALL_TRACE_MAX ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40)) //max number of traced calls 121#define CALL_TRACE_MAX ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40)) //max number of traced calls
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);
125
126
127void printError( CHAR* msg )
128{
129 DWORD eNum;
130 TCHAR sysMsg[256];
131 TCHAR* p;
132
133 eNum = GetLastError( );
134 FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
135 NULL, eNum,
136 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
137 sysMsg, 256, NULL );
138
139 // Trim the end of the line and terminate it with a null
140 p = sysMsg;
141 while( ( *p > 31 ) || ( *p == 9 ) )
142 ++p;
143 do { *p-- = 0; } while( ( p >= sysMsg ) &&
144 ( ( *p == '.' ) || ( *p < 33 ) ) );
145
146 // Display the message
147 printf( "\n WARNING: %s failed with error %d (%s)", msg, eNum, sysMsg );
148}
149
150BOOL GetProcessThreadIDs(DWORD process_id, std::vector<DWORD>& thread_ids)
151{
152 HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
153 THREADENTRY32 te32;
154
155 // Take a snapshot of all running threads
156 hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
157 if( hThreadSnap == INVALID_HANDLE_VALUE )
158 return( FALSE );
159
160 // Fill in the size of the structure before using it.
161 te32.dwSize = sizeof(THREADENTRY32 );
162
163 // Retrieve information about the first thread,
164 // and exit if unsuccessful
165 if( !Thread32First( hThreadSnap, &te32 ) )
166 {
167 printError( "Thread32First" ); // Show cause of failure
168 CloseHandle( hThreadSnap ); // Must clean up the snapshot object!
169 return( FALSE );
170 }
171
172 // Now walk the thread list of the system,
173 // and display information about each thread
174 // associated with the specified process
175 do
176 {
177 if( te32.th32OwnerProcessID == process_id )
178 {
179 thread_ids.push_back(te32.th32ThreadID);
180 }
181 } while( Thread32Next(hThreadSnap, &te32 ) );
182
183// Don't forget to clean up the snapshot object.
184 CloseHandle( hThreadSnap );
185 return( TRUE );
186}
187
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)
252{
253 if(GetCurrentThreadId() == thread_id)
254 {
255 // Early exit for the current thread.
256 // Suspending the current thread would be a bad idea.
257 // Plus you can't retrieve a valid current thread context.
258 return false;
259 }
260
261 HANDLE thread_handle = INVALID_HANDLE_VALUE;
262 thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id);
263 if(INVALID_HANDLE_VALUE == thread_handle)
264 {
265 return FALSE;
266 }
267
268 BOOL result = false;
269 if(-1 != SuspendThread(thread_handle))
270 {
271 CONTEXT context_struct;
272 context_struct.ContextFlags = CONTEXT_FULL;
273 if(GetThreadContext(thread_handle, &context_struct))
274 {
275 GetCallStackData(&context_struct, info);
276 result = true;
277 }
278 ResumeThread(thread_handle);
279 }
280 else
281 {
282 // Couldn't suspend thread.
283 }
284
285 CloseHandle(thread_handle);
286 return result;
287}
288
289
124//Windows Call Stack Construction idea from 290//Windows Call Stack Construction idea from
125//http://www.codeproject.com/tools/minidump.asp 291//http://www.codeproject.com/tools/minidump.asp
126 292
@@ -490,7 +656,33 @@ LONG LLWinDebug::handleException(struct _EXCEPTION_POINTERS *exception_infop)
490 656
491 LLSD info; 657 LLSD info;
492 info = Get_Exception_Info(exception_infop); 658 info = Get_Exception_Info(exception_infop);
493 if (info) 659
660
661 LLSD threads;
662 std::vector<DWORD> thread_ids;
663 GetProcessThreadIDs(GetCurrentProcessId(), thread_ids);
664
665 for(std::vector<DWORD>::iterator th_itr = thread_ids.begin();
666 th_itr != thread_ids.end();
667 ++th_itr)
668 {
669 LLSD thread_info;
670 if(*th_itr != GetCurrentThreadId())
671 {
672 GetThreadCallStack(*th_itr, thread_info);
673 }
674
675 if(thread_info)
676 {
677
678 threads[llformat("ID %d", *th_itr)] = thread_info;
679 }
680 }
681
682
683 info["Threads"] = threads;
684
685 if (info)
494 { 686 {
495 std::ofstream out_file(log_path.c_str()); 687 std::ofstream out_file(log_path.c_str());
496 LLSDSerialize::toPrettyXML(info, out_file); 688 LLSDSerialize::toPrettyXML(info, out_file);