More consistent directory names for HIDDs: removed "hidd" prefix or
[AROS.git] / test / windebug.c
blobee9ceb0495b88d450fe2948e9b59464e9620cdf9
1 /*
2 * This little utility is specific for Windows-hosted port. It allows you to enter
3 * SAD even on completely frozen system.
4 * It is written specifically to facilitate finding long-standing lockup bug.
5 * Additionally it can serve as a short example showing how to interact with Windows
6 * host and use IRQs.
7 * The program installs a hook on Windows console, which generates a NMI whenever the
8 * user presses Ctrl-Break in the console.
9 */
11 #include <aros/debug.h>
12 #include <proto/exec.h>
13 #include <proto/hostlib.h>
14 #include <proto/kernel.h>
16 #include <stdio.h>
18 #ifdef __x86_64__
19 #define __stdcall __attribute__((ms_abi))
20 #else
21 #define __stdcall __attribute__((stdcall))
22 #endif
24 #define WAIT_TIMEOUT 0x00000102
26 struct KernelInterface
28 int (*KrnAllocIRQ)(void);
29 void (*KrnFreeIRQ)(unsigned char irq);
30 void (*KrnCauseIRQ)(unsigned char irq);
31 int *NonMaskableIRQ;
32 int *Supervisor;
35 struct Kernel32Interface
37 ULONG __stdcall (*SetConsoleCtrlHandler)(void *HandlerRoutine, ULONG Add);
38 APTR __stdcall (*CreateEvent)(void *lpEventAttributes, ULONG bManualReset, ULONG bInitialState, const char *lpName);
39 ULONG __stdcall (*CloseHandle)(APTR hObject);
40 ULONG __stdcall (*SetEvent)(APTR hEvent);
41 ULONG __stdcall (*WaitForSingleObject)(void *hHandle, ULONG dwMilliseconds);
44 static LONG debugIRQ;
45 static APTR intAck;
46 static struct KernelInterface *kernelIf;
47 static struct Kernel32Interface *winIf;
49 static const char *symbols[] =
51 "KrnAllocIRQ",
52 "KrnFreeIRQ",
53 "KrnCauseIRQ",
54 "NonMaskableInt",
55 "Supervisor",
56 NULL
59 static const char *kern32_symbols[] =
61 "SetConsoleCtrlHandler",
62 "CreateEventA",
63 "CloseHandle",
64 "SetEvent",
65 "WaitForSingleObject",
66 NULL
69 static void DebugInterrupt(void *a1, void *a2)
72 * Acknowledge the interrupt and call SAD.
73 * Acknowledgement mechanism is needed for very heavy lockups, when interrupts
74 * become inresponsive. Our console hook will wait for 3 seconds, and if this
75 * timeout expores, we consider that our virtualized CPU is dead, and run SAD
76 * right from within console hook. Doing this under normal circumstances results
77 * in crash because of asynchronous re-entering user-mode code.
79 winIf->SetEvent(intAck);
80 Debug(0);
84 * Be careful! This function is executed by Windows, in console's context!
85 * So no AROS calls here!!!
87 static ULONG __stdcall ConsoleHook(ULONG event)
89 if (event == 1) /* CTRL_BREAK_EVENT */
91 ULONG status;
93 kernelIf->KrnCauseIRQ(debugIRQ);
94 status = winIf->WaitForSingleObject(intAck, 3000);
96 if (status != WAIT_TIMEOUT)
97 return TRUE;
100 * This will set supervisor flag. After this it's OK to call kprintf().
101 * We add 1 instead of just setting 1 in order to be able to know
102 * its original value.
103 * Note that here we are running outside of both AROS threads
104 * (supervisor and user). It's OK only because if we are here, interrupt
105 * thread went defunct, and this is the only thread running.
107 *kernelIf->Supervisor += 1;
109 kprintf("Timeout waiting for NMI ACK, entering emergency SAD\n");
110 Debug(0);
112 return FALSE;
115 int __nocommandline = 1;
117 int main(void)
119 char *errStr;
120 APTR kern32, kernel;
121 ULONG unres;
122 APTR KernelBase, HostLibBase;
123 APTR intHandle;
125 KernelBase = OpenResource("kernel.resource");
126 if (!KernelBase)
128 printf("Failed to open kernel.resource ???\n");
129 return 20;
132 HostLibBase = OpenResource("hostlib.resource");
133 if (!HostLibBase)
135 printf("hostlib.resource not found, likely native system\n");
136 return 10;
139 kern32 = HostLib_Open("kernel32.dll", &errStr);
140 if (!kern32)
142 printf("kernel32.dll: %s\n", errStr);
143 HostLib_FreeErrorStr(errStr);
144 return 10;
147 winIf = (struct Kernel32Interface *)HostLib_GetInterface(kern32, kern32_symbols, &unres);
148 if ((!winIf) || unres)
150 printf("Failed to obtain kernel.dll interface, %u symbols unresolved\n", unres);
152 if (winIf)
153 HostLib_DropInterface((void **)winIf);
154 HostLib_Close(kern32, NULL);
155 return 10;
158 kernel = HostLib_Open("Libs\\Host\\kernel.dll", &errStr);
159 if (!kernel)
161 printf("kernel.dll: %s\n", errStr);
162 HostLib_FreeErrorStr(errStr);
163 HostLib_DropInterface((void **)winIf);
164 HostLib_Close(kern32, NULL);
165 return 10;
168 kernelIf = (struct KernelInterface *)HostLib_GetInterface(kernel, symbols, &unres);
169 if ((!kernelIf) || unres)
171 printf("Failed to obtain kernel.dll interface, %u symbols unresolved\n", unres);
173 if (kernelIf)
174 HostLib_DropInterface((void **)kernelIf);
175 HostLib_DropInterface((void **)winIf);
176 HostLib_Close(kernel, NULL);
177 HostLib_Close(kern32, NULL);
178 return 10;
181 debugIRQ = kernelIf->KrnAllocIRQ();
182 if (debugIRQ == -1)
184 printf("Failed to create NMI interrupt!\n");
185 HostLib_DropInterface((void **)kernelIf);
186 HostLib_DropInterface((void **)winIf);
187 HostLib_Close(kernel, NULL);
188 HostLib_Close(kern32, NULL);
190 return 10;
193 intHandle = KrnAddIRQHandler(debugIRQ, DebugInterrupt, NULL, NULL);
194 if (!intHandle)
196 printf("Failed to add IRQ handler\n");
198 HostLib_DropInterface((void **)kernelIf);
199 HostLib_DropInterface((void **)winIf);
200 HostLib_Close(kernel, NULL);
201 HostLib_Close(kern32, NULL);
202 return 10;
205 Forbid();
206 intAck = winIf->CreateEvent(NULL, FALSE, FALSE, NULL);
207 if (intAck)
208 unres = winIf->SetConsoleCtrlHandler(ConsoleHook, TRUE);
209 Permit();
211 if (unres)
213 /* Yes, NonMaskable IRQ exists solely for us dirty hackers */
214 *kernelIf->NonMaskableIRQ = debugIRQ; /* This turns IRQ into NMI */
216 printf("Debug NMI#%d installed, press Ctrl-C to uninstall\n", debugIRQ);
217 Wait(SIGBREAKF_CTRL_C);
219 printf("Done, exiting\n");
221 /* Disable NMI, or bad things may happen if someone reuses this IRQ number */
222 *kernelIf->NonMaskableIRQ = -1;
224 else
225 printf("Failed to install console hook\n");
227 Forbid();
228 if (unres)
229 winIf->SetConsoleCtrlHandler(ConsoleHook, FALSE);
230 winIf->CloseHandle(intAck);
231 Permit();
233 KrnRemIRQHandler(intHandle);
234 kernelIf->KrnFreeIRQ(debugIRQ);
235 HostLib_DropInterface((void **)kernelIf);
236 HostLib_DropInterface((void **)winIf);
237 HostLib_Close(kernel, NULL);
238 HostLib_Close(kern32, NULL);
240 return 0;