1 /*
2 * crashlog.c
3 *
4 * Copyright (C) 2003, 2004, 2005, 2007, 2011 Rob Caelers <robc@krandor.nl>
5 * Copyright (C) 2007 Ray Satiro <raysatiro@yahoo.com>
6 * All rights reserved.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * Based on Dr. Mingw. and OpenTTD
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <assert.h>
31
32 #include "crashlog.h"
33 #include "harpoon.h"
34
35 #include <fcntl.h>
36 #include <io.h>
37
38 #ifndef _O_APPEND
39 #define _O_APPEND 0x0008
40 #endif
41 #ifndef _O_TEXT
42 #define _O_TEXT 0x4000
43 #endif
44
45 #ifdef PLATFORM_OS_WIN32_NATIVE
46 #define snprintf _snprintf
47 #define snwprintf _snwprintf
48 #endif
49
50 static void unwind_stack(FILE *log, HANDLE process, PCONTEXT context);
51 static void dump_registers(FILE *log, PCONTEXT context);
52 static void dump_registry(FILE *log, HKEY key, char *name);
53 /* static void print_module_list(FILE *log); */
54
55 static
GetModuleBase(DWORD dwAddress)56 DWORD GetModuleBase(DWORD dwAddress)
57 {
58 MEMORY_BASIC_INFORMATION Buffer;
59
60 return VirtualQuery((LPCVOID) dwAddress, &Buffer, sizeof(Buffer)) ? (DWORD) Buffer.AllocationBase : 0;
61 }
62
63 #ifndef PLATFORM_OS_WIN32_NATIVE
64 static EXCEPTION_DISPOSITION __cdecl
double_exception_handler(struct _EXCEPTION_RECORD * exception_record,void * establisher_frame,struct _CONTEXT * context_record,void * dispatcher_context)65 double_exception_handler(struct _EXCEPTION_RECORD *exception_record,
66 void *establisher_frame,
67 struct _CONTEXT *context_record,
68 void *dispatcher_context)
69 {
70 (void) exception_record;
71 (void) establisher_frame;
72 (void) context_record;
73 (void) dispatcher_context;
74
75 MessageBox(NULL,
76 (LPCSTR)"Workrave has unexpectedly crashed and failed to create a crash "
77 "log. This is serious. Please report this to crashes@workrave.org or "
78 "file a bugreport at: http://issues.workrave.org/. " ,
79 (LPCSTR)"Double exception", MB_OK);
80
81 exit(1);
82 }
83 #endif
84
85 EXCEPTION_DISPOSITION __cdecl
exception_handler(struct _EXCEPTION_RECORD * exception_record,void * establisher_frame,struct _CONTEXT * context_record,void * dispatcher_context)86 exception_handler(struct _EXCEPTION_RECORD *exception_record,
87 void *establisher_frame,
88 struct _CONTEXT *context_record,
89 void *dispatcher_context)
90 {
91 char crash_log_name[MAX_PATH];
92 char crash_text[1024];
93 TCHAR szModule[MAX_PATH];
94 HMODULE hModule;
95 /*
96 Modified for Unicode >= WinNT. No UnicoWS check for Me/98/95.
97 jay satiro, workrave project, july 2007
98 */
99 WCHAR env_var[ 20 ] = { '\0', };
100 WCHAR crashlog[] = L"\\workrave-crashlog.txt";
101 WCHAR *wbuffer = NULL;
102 WCHAR *p_wbuffer = NULL; FILE *log;
103 DWORD ( WINAPI *GetEnvironmentVariableW ) ( LPCWSTR, LPWSTR, DWORD );
104 HANDLE ( WINAPI *CreateFileW ) ( LPCWSTR, DWORD, DWORD,
105 LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE );
106 SYSTEMTIME SystemTime;
107
108 (void) establisher_frame;
109 (void) dispatcher_context;
110
111 #ifdef PLATFORM_OS_WIN32_NATIVE
112 // FIXME: win32
113 #else
114 __try1(double_exception_handler);
115 #endif
116
117 harpoon_unblock_input();
118
119
120
121
122 GetEnvironmentVariableW = ( DWORD ( WINAPI * ) ( LPCWSTR, LPWSTR, DWORD ) )
123 GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "GetEnvironmentVariableW" );
124 CreateFileW = ( HANDLE ( WINAPI * ) ( LPCWSTR, DWORD, DWORD,
125 LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE ) )
126 GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "CreateFileW" );
127
128 if( GetEnvironmentVariableW && CreateFileW )
129 // >= WinNT
130 {
131 HANDLE handle;
132 DWORD bufsize, ret;
133 int fd = 0;
134
135 wcsncpy( env_var, L"APPDATA", 19 );
136 env_var[ 19 ] = '\0';
137 bufsize = ( *GetEnvironmentVariableW ) ( env_var, NULL, 0 );
138 // bufsize is size in wide chars, including null
139
140 if( !bufsize )
141 // If %appdata% is unsuitable, try temp:
142 {
143 wcsncpy( env_var, L"TEMP", 19 );
144 env_var[ 19 ] = '\0';
145 bufsize = ( *GetEnvironmentVariableW ) ( env_var, NULL, 0 );
146 }
147
148 ret = 0;
149 wbuffer = NULL;
150
151 if( bufsize )
152 {
153 // We will need room for \\?\ so add 4
154 if( (wbuffer = (WCHAR *)calloc( 4 + bufsize + wcslen( crashlog ), sizeof( WCHAR ) ) ) != NULL)
155 {
156 wcscpy( wbuffer, L"\\\\?\\" );
157 p_wbuffer = wbuffer + 4;
158 ret = ( *GetEnvironmentVariableW ) ( env_var, p_wbuffer, bufsize );
159 }
160 }
161
162 if( !ret )
163 // Environment unsuitable, notify & terminate.
164 {
165 free( wbuffer );
166 snprintf(crash_text, 1023,
167 "Workrave has unexpectedly crashed. The environment is "
168 "unsuitable to create a crash log. Please file a bug report:\n"
169 "http://issues.workrave.org/\n"
170 "Thanks.");
171 MessageBoxA( NULL, crash_text, "Exception", MB_OK );
172
173 #ifdef PLATFORM_OS_WIN32_NATIVE
174 // FIXME: win32
175 #else
176 __except1;
177 #endif
178 exit( 1 );
179 }
180
181 //last wchar
182 p_wbuffer = wbuffer + wcslen(wbuffer) - 1;
183
184 while( *p_wbuffer == L'\\' )
185 // remove trailing slashes
186 {
187 *p_wbuffer-- = L'\0';
188 }
189
190 // append filename to end of string
191 wcscpy( ++p_wbuffer, crashlog );
192
193
194 // compare first wchar of returned environment string
195 if( wbuffer[ 4 ] == L'\\' )
196 /*
197 If possible network path, don't include literal \\?\
198 \\?\\\1.2.3.4\workrave-crashlog.txt should be
199 \\1.2.3.4\workrave-crashlog.txt
200 */
201 p_wbuffer = wbuffer + 4;
202 else
203 // Point to start of wbuffer:
204 p_wbuffer = wbuffer;
205
206
207 handle = ( *CreateFileW ) (
208 p_wbuffer,
209 GENERIC_READ | GENERIC_WRITE,
210 FILE_SHARE_READ,
211 NULL,
212 CREATE_ALWAYS,
213 FILE_ATTRIBUTE_NORMAL,
214 NULL
215 );
216
217 fd = _open_osfhandle( (intptr_t) handle, _O_APPEND | _O_TEXT );
218 log = _fdopen( fd, "w" );
219 }
220 else // if( GetVersion() & (DWORD) 0x80000000 )
221 // Windows Me/98/95
222 {
223 char *s = NULL;
224 GetModuleFileName(GetModuleHandle(NULL), crash_log_name, sizeof(crash_log_name));
225 // crash_log_name == c:\program files\workrave\lib\workrave.exe
226 s = strrchr(crash_log_name, '\\');
227 assert (s);
228 *s = '\0';
229 // crash_log_name == c:\program files\workrave\lib
230 s = strrchr(crash_log_name, '\\');
231 assert (s);
232 *s = '\0';
233 // crash_log_name == c:\program files\workrave
234 strcat(crash_log_name, "\\workrave-crashlog.txt");
235
236 log = fopen(crash_log_name, "w");
237 }
238
239 if( log == NULL )
240 // workrave-crashlog.txt wasn't created.
241 {
242 snprintf(crash_text, 1023,
243 "Workrave has unexpectedly crashed. An attempt to create "
244 "a crashlog has failed. Please file a bug report:\n"
245 "http://issues.workrave.org/\n"
246 "Thanks.");
247 MessageBoxA( NULL, crash_text, "Exception", MB_OK );
248 #ifdef PLATFORM_OS_WIN32_NATIVE
249 // FIXME: win32
250 #else
251 __except1;
252 #endif
253 exit( 1 );
254 }
255
256
257 GetLocalTime(&SystemTime);
258 fprintf(log, "Crash log created on %02d/%02d/%04d at %02d:%02d:%02d.\n\n",
259 SystemTime.wDay,
260 SystemTime.wMonth,
261 SystemTime.wYear,
262 SystemTime.wHour,
263 SystemTime.wMinute,
264 SystemTime.wSecond);
265
266 fprintf(log, "version = %s\n", PACKAGE_VERSION);
267 fprintf(log, "compile date = %s\n", __DATE__);
268 fprintf(log, "compile time = %s\n", __TIME__);
269 fprintf(log, "features = "
270 #ifdef HAVE_DISTRIBUTION
271 "DISTRIBUTION "
272 #endif
273 #ifdef HAVE_EXERCISES
274 "EXERCISES "
275 #endif
276 #ifdef HAVE_GCONF
277 "GCONF?? "
278 #endif
279 #ifdef HAVE_GDOME
280 "GDOME "
281 #endif
282 #ifdef HAVE_GNET
283 "GNET "
284 #endif
285 #ifdef HAVE_GNET2
286 "GNET2 "
287 #endif
288 #ifdef HAVE_XRECORD
289 "XRECORD?? "
290 #endif
291 #ifndef NDEBUG
292 "DEBUG "
293 #endif
294 "\n"
295 );
296
297 // write locale info:
298 char *buffer = NULL;
299 int bufsize =
300 GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, buffer, 0);
301
302 if( bufsize )
303 buffer = (char *)calloc( bufsize + 1, 1 );
304
305 if( buffer )
306 {
307 GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, buffer, bufsize);
308 buffer[ bufsize ] = '\0';
309 fprintf( log, "locale = %s\n", buffer );
310 free( buffer );
311 }
312
313 fprintf(log, "\n\n");
314 fprintf(log, "code = %x\n", (int) exception_record->ExceptionCode);
315 fprintf(log, "flags = %x\n", (int) exception_record->ExceptionFlags);
316 fprintf(log, "address = %x\n", (int) exception_record->ExceptionAddress);
317 fprintf(log, "params = %d\n", (int) exception_record->NumberParameters);
318
319 fprintf(log, "%s caused ", GetModuleFileName(NULL, szModule, MAX_PATH) ? szModule : "Application");
320 switch (exception_record->ExceptionCode)
321 {
322 case EXCEPTION_ACCESS_VIOLATION:
323 fprintf(log, "an Access Violation");
324 break;
325
326 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
327 fprintf(log, "an Array Bound Exceeded");
328 break;
329
330 case EXCEPTION_BREAKPOINT:
331 fprintf(log, "a Breakpoint");
332 break;
333
334 case EXCEPTION_DATATYPE_MISALIGNMENT:
335 fprintf(log, "a Datatype Misalignment");
336 break;
337
338 case EXCEPTION_FLT_DENORMAL_OPERAND:
339 fprintf(log, "a Float Denormal Operand");
340 break;
341
342 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
343 fprintf(log, "a Float Divide By Zero");
344 break;
345
346 case EXCEPTION_FLT_INEXACT_RESULT:
347 fprintf(log, "a Float Inexact Result");
348 break;
349
350 case EXCEPTION_FLT_INVALID_OPERATION:
351 fprintf(log, "a Float Invalid Operation");
352 break;
353
354 case EXCEPTION_FLT_OVERFLOW:
355 fprintf(log, "a Float Overflow");
356 break;
357
358 case EXCEPTION_FLT_STACK_CHECK:
359 fprintf(log, "a Float Stack Check");
360 break;
361
362 case EXCEPTION_FLT_UNDERFLOW:
363 fprintf(log, "a Float Underflow");
364 break;
365
366 case EXCEPTION_GUARD_PAGE:
367 fprintf(log, "a Guard Page");
368 break;
369
370 case EXCEPTION_ILLEGAL_INSTRUCTION:
371 fprintf(log, "an Illegal Instruction");
372 break;
373
374 case EXCEPTION_IN_PAGE_ERROR:
375 fprintf(log, "an In Page Error");
376 break;
377
378 case EXCEPTION_INT_DIVIDE_BY_ZERO:
379 fprintf(log, "an Integer Divide By Zero");
380 break;
381
382 case EXCEPTION_INT_OVERFLOW:
383 fprintf(log, "an Integer Overflow");
384 break;
385
386 case EXCEPTION_INVALID_DISPOSITION:
387 fprintf(log, "an Invalid Disposition");
388 break;
389
390 case EXCEPTION_INVALID_HANDLE:
391 fprintf(log, "an Invalid Handle");
392 break;
393
394 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
395 fprintf(log, "a Noncontinuable Exception");
396 break;
397
398 case EXCEPTION_PRIV_INSTRUCTION:
399 fprintf(log, "a Privileged Instruction");
400 break;
401
402 case EXCEPTION_SINGLE_STEP:
403 fprintf(log, "a Single Step");
404 break;
405
406 case EXCEPTION_STACK_OVERFLOW:
407 fprintf(log, "a Stack Overflow");
408 break;
409
410 case DBG_CONTROL_C:
411 fprintf(log, "a Control+C");
412 break;
413
414 case DBG_CONTROL_BREAK:
415 fprintf(log, "a Control+Break");
416 break;
417
418 case DBG_TERMINATE_THREAD:
419 fprintf(log, "a Terminate Thread");
420 break;
421
422 case DBG_TERMINATE_PROCESS:
423 fprintf(log, "a Terminate Process");
424 break;
425
426 case RPC_S_UNKNOWN_IF:
427 fprintf(log, "an Unknown Interface");
428 break;
429
430 case RPC_S_SERVER_UNAVAILABLE:
431 fprintf(log, "a Server Unavailable");
432 break;
433
434 default:
435 fprintf(log, "an Unknown [0x%lX] Exception", exception_record->ExceptionCode);
436 break;
437 }
438
439 fprintf(log, " at location %08x", (int) exception_record->ExceptionAddress);
440 hModule = (HMODULE) GetModuleBase((DWORD) exception_record->ExceptionAddress);
441 if ((hModule != NULL && GetModuleFileName(hModule, szModule, sizeof(szModule))))
442 fprintf(log, " in module %s", szModule);
443
444 // If the exception was an access violation, print out some additional information, to the error log and the debugger.
445 if(exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && exception_record->NumberParameters >= 2)
446 fprintf(log, " %s location %08x\n\n", exception_record->ExceptionInformation[0] ? "writing to" : "reading from", exception_record->ExceptionInformation[1]);
447
448 DWORD pid = GetCurrentProcessId();
449 HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
450
451 dump_registers(log, context_record);
452 unwind_stack(log, process, context_record);
453
454 print_module_list(log);
455
456 fprintf(log, "\nRegistry dump:\n\n");
457 dump_registry(log, HKEY_CURRENT_USER, "Software\\Workrave");
458
459 fclose(log);
460
461 if( GetEnvironmentVariableW && CreateFileW )
462 // >= WinNT
463 {
464 WCHAR *one =
465 L"Workrave has unexpectedly crashed. A crash log has been saved to:\n";
466
467 WCHAR *two =
468 L"\nPlease file a bug report: http://issues.workrave.org/\n"
469 L"Thanks.";
470
471 WCHAR *nomem =
472 L"Workrave is out of memory!";
473
474 int size = wcslen( one ) + wcslen( p_wbuffer ) + wcslen( two ) + 1;
475
476 WCHAR *message = (WCHAR *)calloc( size, sizeof( WCHAR ) );
477 if( !message )
478 // Low memory...
479 {
480 // % + % + null = 3 extra
481 size = wcslen( one ) + wcslen( env_var ) + wcslen( crashlog ) + wcslen( two ) + 3;
482 message = (WCHAR *)calloc( size, sizeof( WCHAR ) );
483 if( message )
484 {
485 snwprintf( message, size - 1, L"%ws%%%ws%%%ws%ws",
486 one, env_var, crashlog, two );
487 message[ size - 1 ] = L'\0';
488 }
489 else
490 // No memory...
491 message = nomem;
492 }
493 else
494 // A buffer was allocated with enough memory to hold p_wbuffer
495 {
496 snwprintf( message, size - 1, L"%ws%ws%ws", one, p_wbuffer, two );
497 message[ size - 1 ] = L'\0';
498 }
499
500 MessageBoxW( NULL, message, L"Exception", MB_OK );
501 }
502 else
503 {
504 snprintf(crash_text, 1023,
505 "Workrave has unexpectedly crashed. A crash log has been saved to "
506 "%s. Please mail this file to crashes@workrave.org or "
507 "file a bugreport at: http://issues.workrave.org/. "
508 "Thanks.", crash_log_name);
509 MessageBoxA(NULL, crash_text, "Exception", MB_OK);
510 }
511
512 #ifdef PLATFORM_OS_WIN32_NATIVE
513 // FIXME: win32
514 #else
515 __except1;
516 #endif
517
518 exit(1);
519 }
520
521
522 static
stack_walk(HANDLE process,LPSTACKFRAME stack_frame,PCONTEXT context_record)523 BOOL WINAPI stack_walk(HANDLE process, LPSTACKFRAME stack_frame, PCONTEXT context_record)
524 {
525 if (!stack_frame->Reserved[0])
526 {
527 stack_frame->Reserved[0] = 1;
528
529 stack_frame->AddrPC.Mode = AddrModeFlat;
530 stack_frame->AddrPC.Offset = context_record->Eip;
531 stack_frame->AddrStack.Mode = AddrModeFlat;
532 stack_frame->AddrStack.Offset = context_record->Esp;
533 stack_frame->AddrFrame.Mode = AddrModeFlat;
534 stack_frame->AddrFrame.Offset = context_record->Ebp;
535
536 stack_frame->AddrReturn.Mode = AddrModeFlat;
537 if (!ReadProcessMemory(process,
538 (LPCVOID) (stack_frame->AddrFrame.Offset + sizeof(DWORD)),
539 &stack_frame->AddrReturn.Offset, sizeof(DWORD), NULL))
540 return FALSE;
541 }
542 else
543 {
544 stack_frame->AddrPC.Offset = stack_frame->AddrReturn.Offset;
545
546 if (!ReadProcessMemory(process, (LPCVOID) stack_frame->AddrFrame.Offset,
547 &stack_frame->AddrFrame.Offset, sizeof(DWORD), NULL))
548 return FALSE;
549
550 if (!ReadProcessMemory(process, (LPCVOID) (stack_frame->AddrFrame.Offset + sizeof(DWORD)),
551 &stack_frame->AddrReturn.Offset, sizeof(DWORD), NULL))
552 return FALSE;
553 }
554
555 ReadProcessMemory(process, (LPCVOID) (stack_frame->AddrFrame.Offset + 2*sizeof(DWORD)),
556 stack_frame->Params, sizeof(stack_frame->Params), NULL);
557
558 return TRUE;
559 }
560
561 static void
unwind_stack(FILE * log,HANDLE process,PCONTEXT context)562 unwind_stack(FILE *log, HANDLE process, PCONTEXT context)
563 {
564 STACKFRAME sf;
565
566 fprintf(log, "Stack trace:\n\n");
567
568 ZeroMemory(&sf, sizeof(STACKFRAME));
569 sf.AddrPC.Offset = context->Eip;
570 sf.AddrPC.Mode = AddrModeFlat;
571 sf.AddrStack.Offset = context->Esp;
572 sf.AddrStack.Mode = AddrModeFlat;
573 sf.AddrFrame.Offset = context->Ebp;
574 sf.AddrFrame.Mode = AddrModeFlat;
575
576 fprintf(log, "PC Frame Ret\n");
577
578 while (TRUE)
579 {
580 if (!stack_walk(process, &sf, context))
581 break;
582
583 if (sf.AddrFrame.Offset == 0)
584 break;
585
586 fprintf(log, "%08X %08X %08X\n",
587 (int) sf.AddrPC.Offset,
588 (int) sf.AddrFrame.Offset,
589 (int) sf.AddrReturn.Offset);
590 }
591 }
592
593 static void
print_module_info(FILE * log,HMODULE mod)594 print_module_info(FILE *log, HMODULE mod)
595 {
596 TCHAR buffer[MAX_PATH];
597 HANDLE file;
598 SYSTEMTIME file_time;
599 FILETIME write_time;
600
601 GetModuleFileName(mod, buffer, MAX_PATH);
602
603 file = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
604 if (file != INVALID_HANDLE_VALUE)
605 {
606 if (GetFileTime(file, NULL, NULL, &write_time))
607 {
608 FileTimeToSystemTime(&write_time, &file_time);
609 }
610 CloseHandle(file);
611 }
612
613 fprintf(log, " %-20s handle: %p date: %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
614 buffer,
615 mod,
616 file_time.wYear,
617 file_time.wMonth,
618 file_time.wDay,
619 file_time.wHour,
620 file_time.wMinute,
621 file_time.wSecond
622 );
623 }
624
625 void
print_module_list(FILE * log)626 print_module_list(FILE *log)
627 {
628 HMODULE lib;
629 BOOL (WINAPI *EnumProcessModules)(HANDLE, HMODULE*, DWORD, LPDWORD);
630
631 EnumProcessModules = NULL;
632 lib = LoadLibrary("psapi.dll");
633 if (lib != NULL)
634 {
635 EnumProcessModules = (BOOL (WINAPI *)(HANDLE, HMODULE*, DWORD, LPDWORD)) GetProcAddress(lib, "EnumProcessModules");
636 }
637
638 if (EnumProcessModules != NULL)
639 {
640 HMODULE modules[100];
641 DWORD needed;
642 BOOL res;
643 int count, i;
644
645 HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
646 if (proc != NULL)
647 {
648 res = EnumProcessModules(proc, modules, sizeof(modules), &needed);
649 CloseHandle(proc);
650 if (res)
651 {
652 count = min(needed / sizeof(HMODULE), 100);
653
654 for (i = 0; i != count; i++)
655 {
656 print_module_info(log, modules[i]);
657 }
658 return;
659 }
660 }
661 }
662
663 print_module_info(log, NULL);
664 }
665
666 static void
dump_registers(FILE * log,PCONTEXT context)667 dump_registers(FILE *log, PCONTEXT context)
668 {
669 fprintf(log, "Registers:\n\n");
670
671 if (context->ContextFlags & CONTEXT_INTEGER)
672 {
673 fprintf(log, "eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
674 context->Eax, context->Ebx, context->Ecx, context->Edx,
675 context->Esi, context->Edi);
676 }
677
678 if (context->ContextFlags & CONTEXT_CONTROL)
679 {
680 fprintf(log, "eip=%08lx esp=%08lx ebp=%08lx iopl=%1lx %s %s %s %s %s %s %s %s %s %s\n",
681 context->Eip, context->Esp, context->Ebp,
682 (context->EFlags >> 12) & 3, // IOPL level value
683 context->EFlags & 0x00100000 ? "vip" : " ", // VIP (virtual interrupt pending)
684 context->EFlags & 0x00080000 ? "vif" : " ", // VIF (virtual interrupt flag)
685 context->EFlags & 0x00000800 ? "ov" : "nv", // VIF (virtual interrupt flag)
686 context->EFlags & 0x00000400 ? "dn" : "up", // OF (overflow flag)
687 context->EFlags & 0x00000200 ? "ei" : "di", // IF (interrupt enable flag)
688 context->EFlags & 0x00000080 ? "ng" : "pl", // SF (sign flag)
689 context->EFlags & 0x00000040 ? "zr" : "nz", // ZF (zero flag)
690 context->EFlags & 0x00000010 ? "ac" : "na", // AF (aux carry flag)
691 context->EFlags & 0x00000004 ? "po" : "pe", // PF (parity flag)
692 context->EFlags & 0x00000001 ? "cy" : "nc" // CF (carry flag)
693 );
694 }
695
696 if (context->ContextFlags & CONTEXT_SEGMENTS)
697 {
698 fprintf(log, "cs=%04lx ss=%04lx ds=%04lx es=%04lx fs=%04lx gs=%04lx",
699 context->SegCs, context->SegSs, context->SegDs, context->SegEs,
700 context->SegFs, context->SegGs);
701
702 if(context->ContextFlags & CONTEXT_CONTROL)
703 {
704 fprintf(log, " efl=%08lx", context->EFlags);
705 }
706 }
707 else
708 {
709 if (context->ContextFlags & CONTEXT_CONTROL)
710 {
711 fprintf(log, " efl=%08lx",
712 context->EFlags);
713 }
714 }
715
716 fprintf(log, "\n\n");
717 }
718
719 static void
save_key(FILE * log,HKEY key,char * name)720 save_key(FILE *log, HKEY key, char *name)
721 {
722 DWORD i;
723 char keyname[512];
724 int keyname_len = strlen(keyname);
725
726 fprintf(log, "key = %s\n", name);
727
728 for (i = 0; ; i++)
729 {
730 char val[256];
731 DWORD val_size = sizeof(val);
732 BYTE data[0x4000];
733 DWORD data_size = sizeof(data);
734 DWORD type;
735
736 LONG rc = RegEnumValue(key, i, val, &val_size, 0, &type, data, &data_size);
737
738 if (rc != ERROR_SUCCESS)
739 break;
740
741 if (val_size)
742 fprintf(log, " value = %s\n", val);
743
744 if (strcmp("password", val) == 0)
745 {
746 fprintf(log, " string data = <hidden>\n");
747 }
748 else if (type == REG_SZ)
749 {
750 fprintf(log, " string data = %s\n", data);
751 }
752 else if (type == REG_DWORD && data_size==4)
753 {
754 fprintf(log, " dword data = %08lx\n", (long)data);
755 }
756 else
757 {
758 fprintf(log, " hex data = [unsupported]\n");
759 }
760 }
761
762 fprintf(log, "\n");
763
764 strcpy(keyname, name);
765 strcat(keyname, "\\");
766 keyname_len = strlen(keyname);
767
768 for (i = 0; ; i++)
769 {
770 HKEY subkey;
771 LONG rc = RegEnumKey(key, i, keyname + keyname_len,
772 sizeof(keyname) - keyname_len);
773
774 if (rc != ERROR_SUCCESS)
775 break;
776
777 rc = RegOpenKey(key, keyname + keyname_len, &subkey);
778 if (rc == ERROR_SUCCESS)
779 {
780 dump_registry(log, subkey, keyname);
781 RegCloseKey(subkey);
782 }
783 }
784 }
785
786
787 static void
dump_registry(FILE * log,HKEY key,char * name)788 dump_registry(FILE *log, HKEY key, char *name)
789 {
790 (void) key;
791
792 HKEY handle;
793 LONG rc = RegOpenKeyEx(HKEY_CURRENT_USER, name, 0, KEY_ALL_ACCESS, &handle);
794
795 if (rc == ERROR_SUCCESS)
796 {
797 save_key(log, handle, name);
798 RegCloseKey(handle);
799 }
800 }
801