correct copyright
[AROS.git] / test / windebug.c
blob523e6c6b7ed8bbe1781a717dc624df5ae7b41605
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /*
7 * This little utility is specific for Windows-hosted port. It allows you to enter
8 * SAD even on completely frozen system.
9 * It is written specifically to facilitate finding long-standing lockup bug.
10 * Additionally it can serve as a short example showing how to interact with Windows
11 * host and use IRQs.
12 * The program installs a hook on Windows console, which generates a NMI whenever the
13 * user presses Ctrl-Break in the console.
16 #include <aros/debug.h>
17 #include <proto/exec.h>
18 #include <proto/hostlib.h>
19 #include <proto/kernel.h>
21 #include <stdio.h>
23 #ifdef __x86_64__
24 #define __stdcall __attribute__((ms_abi))
25 #else
26 #define __stdcall __attribute__((stdcall))
27 #endif
29 #define WAIT_TIMEOUT 0x00000102
31 struct KernelInterface
33 int (*KrnAllocIRQ)(void);
34 void (*KrnFreeIRQ)(unsigned char irq);
35 void (*KrnCauseIRQ)(unsigned char irq);
36 int *NonMaskableIRQ;
37 int *Supervisor;
40 struct Kernel32Interface
42 ULONG __stdcall (*SetConsoleCtrlHandler)(void *HandlerRoutine, ULONG Add);
43 APTR __stdcall (*CreateEvent)(void *lpEventAttributes, ULONG bManualReset, ULONG bInitialState, const char *lpName);
44 ULONG __stdcall (*CloseHandle)(APTR hObject);
45 ULONG __stdcall (*SetEvent)(APTR hEvent);
46 ULONG __stdcall (*WaitForSingleObject)(void *hHandle, ULONG dwMilliseconds);
49 static LONG debugIRQ;
50 static APTR intAck;
51 static struct KernelInterface *kernelIf;
52 static struct Kernel32Interface *winIf;
54 static const char *symbols[] =
56 "KrnAllocIRQ",
57 "KrnFreeIRQ",
58 "KrnCauseIRQ",
59 "NonMaskableInt",
60 "Supervisor",
61 NULL
64 static const char *kern32_symbols[] =
66 "SetConsoleCtrlHandler",
67 "CreateEventA",
68 "CloseHandle",
69 "SetEvent",
70 "WaitForSingleObject",
71 NULL
74 static void DebugInterrupt(void *a1, void *a2)
77 * Acknowledge the interrupt and call SAD.
78 * Acknowledgement mechanism is needed for very heavy lockups, when interrupts
79 * become inresponsive. Our console hook will wait for 3 seconds, and if this
80 * timeout expores, we consider that our virtualized CPU is dead, and run SAD
81 * right from within console hook. Doing this under normal circumstances results
82 * in crash because of asynchronous re-entering user-mode code.
84 winIf->SetEvent(intAck);
85 Debug(0);
89 * Be careful! This function is executed by Windows, in console's context!
90 * So no AROS calls here!!!
92 static ULONG __stdcall ConsoleHook(ULONG event)
94 if (event == 1) /* CTRL_BREAK_EVENT */
96 ULONG status;
98 kernelIf->KrnCauseIRQ(debugIRQ);
99 status = winIf->WaitForSingleObject(intAck, 3000);
101 if (status != WAIT_TIMEOUT)
102 return TRUE;
105 * This will set supervisor flag. After this it's OK to call kprintf().
106 * We add 1 instead of just setting 1 in order to be able to know
107 * its original value.
108 * Note that here we are running outside of both AROS threads
109 * (supervisor and user). It's OK only because if we are here, interrupt
110 * thread went defunct, and this is the only thread running.
112 *kernelIf->Supervisor += 1;
114 kprintf("Timeout waiting for NMI ACK, entering emergency SAD\n");
115 Debug(0);
117 return FALSE;
120 int __nocommandline = 1;
122 int main(void)
124 char *errStr;
125 APTR kern32, kernel;
126 ULONG unres;
127 APTR KernelBase, HostLibBase;
128 APTR intHandle;
130 KernelBase = OpenResource("kernel.resource");
131 if (!KernelBase)
133 printf("Failed to open kernel.resource ???\n");
134 return 20;
137 HostLibBase = OpenResource("hostlib.resource");
138 if (!HostLibBase)
140 printf("hostlib.resource not found, likely native system\n");
141 return 10;
144 kern32 = HostLib_Open("kernel32.dll", &errStr);
145 if (!kern32)
147 printf("kernel32.dll: %s\n", errStr);
148 HostLib_FreeErrorStr(errStr);
149 return 10;
152 winIf = (struct Kernel32Interface *)HostLib_GetInterface(kern32, kern32_symbols, &unres);
153 if ((!winIf) || unres)
155 printf("Failed to obtain kernel.dll interface, %u symbols unresolved\n", unres);
157 if (winIf)
158 HostLib_DropInterface((void **)winIf);
159 HostLib_Close(kern32, NULL);
160 return 10;
163 kernel = HostLib_Open("Libs\\Host\\kernel.dll", &errStr);
164 if (!kernel)
166 printf("kernel.dll: %s\n", errStr);
167 HostLib_FreeErrorStr(errStr);
168 HostLib_DropInterface((void **)winIf);
169 HostLib_Close(kern32, NULL);
170 return 10;
173 kernelIf = (struct KernelInterface *)HostLib_GetInterface(kernel, symbols, &unres);
174 if ((!kernelIf) || unres)
176 printf("Failed to obtain kernel.dll interface, %u symbols unresolved\n", unres);
178 if (kernelIf)
179 HostLib_DropInterface((void **)kernelIf);
180 HostLib_DropInterface((void **)winIf);
181 HostLib_Close(kernel, NULL);
182 HostLib_Close(kern32, NULL);
183 return 10;
186 debugIRQ = kernelIf->KrnAllocIRQ();
187 if (debugIRQ == -1)
189 printf("Failed to create NMI interrupt!\n");
190 HostLib_DropInterface((void **)kernelIf);
191 HostLib_DropInterface((void **)winIf);
192 HostLib_Close(kernel, NULL);
193 HostLib_Close(kern32, NULL);
195 return 10;
198 intHandle = KrnAddIRQHandler(debugIRQ, DebugInterrupt, NULL, NULL);
199 if (!intHandle)
201 printf("Failed to add IRQ handler\n");
203 HostLib_DropInterface((void **)kernelIf);
204 HostLib_DropInterface((void **)winIf);
205 HostLib_Close(kernel, NULL);
206 HostLib_Close(kern32, NULL);
207 return 10;
210 Forbid();
211 intAck = winIf->CreateEvent(NULL, FALSE, FALSE, NULL);
212 if (intAck)
213 unres = winIf->SetConsoleCtrlHandler(ConsoleHook, TRUE);
214 Permit();
216 if (unres)
218 /* Yes, NonMaskable IRQ exists solely for us dirty hackers */
219 *kernelIf->NonMaskableIRQ = debugIRQ; /* This turns IRQ into NMI */
221 printf("Debug NMI#%d installed, press Ctrl-C to uninstall\n", debugIRQ);
222 Wait(SIGBREAKF_CTRL_C);
224 printf("Done, exiting\n");
226 /* Disable NMI, or bad things may happen if someone reuses this IRQ number */
227 *kernelIf->NonMaskableIRQ = -1;
229 else
230 printf("Failed to install console hook\n");
232 Forbid();
233 if (unres)
234 winIf->SetConsoleCtrlHandler(ConsoleHook, FALSE);
235 winIf->CloseHandle(intAck);
236 Permit();
238 KrnRemIRQHandler(intHandle);
239 kernelIf->KrnFreeIRQ(debugIRQ);
240 HostLib_DropInterface((void **)kernelIf);
241 HostLib_DropInterface((void **)winIf);
242 HostLib_Close(kernel, NULL);
243 HostLib_Close(kern32, NULL);
245 return 0;