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