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