|
|
1.1 root 1: // ************************************************************************
2: // MODULE : DEBDebug.c
3: // PURPOSE : Debug support functions for the Debug Event Browser
4: // FUNCTIONS :
5: // DbgEventThread() - debug event processing thread
6: // GetModuleFileNameFromHeader() - get the module name
7: // SkipBreakPoint() - skips over the break point in the debugee
8: // COMMENTS :
9: // ************************************************************************
10: #include <Windows.H>
11: #include <String.H> // strcpy(), strcat()
12: #include <StdIO.H> // sprintf()
13:
14: #include "LinkList.H"
15: #include "DEBMain.H"
16: #include "DEBMisc.H"
17: #include "DEBDebug.H"
18:
19:
20: // ************************************************************************
21: // FUNCTION : DebugEventThread( LPCTSTR )
22: // PURPOSE : Main debug event processing loop
23: // COMMENTS : A new debug event thread is created for each debugee process.
24: // DebugeeFileName may be the process ID of and active process
25: // or the name of a process to create.
26: // Note: this build only supports browsing one process at a time.
27: // ************************************************************************
28: DWORD
29: DebugEventThread( LPCTSTR DebugeeFileName )
30: {
31: static BOOL fFirstTime = TRUE;
32: static PNODE ThreadNode; // used for inserting new thread nodes
33:
34: PNODE TempNode; // used for queries on thread linked list
35: DEBUG_EVENT DebugEvent;
36: TCHAR szDebugEventBuffer[256];
37: TCHAR szTempBuf[256];
38: DWORD NumberOfBytesRead;
39:
40: //-- temporary thread info node used for queries
41: CreateNode( &ProcessList, &TempNode );
42:
43: //-- determine if 'attach to' or 'open' debugee
44: // DebugeeFileName may be dwProcessId and an actual filename
45: if( !DebugActiveProcess( (DWORD) DebugeeFileName ) ) {
46:
47: //-- create the debugee process instead
48: if( !CreateProcess(
49: NULL,
50: DebugeeFileName,
51: (LPSECURITY_ATTRIBUTES) NULL,
52: (LPSECURITY_ATTRIBUTES) NULL,
53: TRUE,
54: DebugMode | DebugeePriority | CREATE_NEW_CONSOLE,
55: (LPVOID) NULL,
56: (LPTSTR) NULL,
57: &si, &pi ) ) {
58:
59: return( FALSE );
60:
61: }
62: else {
63:
64: hProcess = pi.hProcess;
65: CloseHandle( pi.hProcess );
66: CloseHandle( pi.hThread );
67:
68: }
69: }
70:
71: for(;;) {
72: if( !WaitForDebugEvent( &DebugEvent, (DWORD) -1L ) ) {
73: ListBoxPrintF( "%s", "Waiting..." );
74: continue;
75: }
76:
77: switch( DebugEvent.dwDebugEventCode ) {
78:
79: case EXCEPTION_DEBUG_EVENT:
80: MakeDebugEventString( szDebugEventBuffer, "Exception:",
81: &DebugEvent);
82:
83: switch( DebugEvent.u.Exception.ExceptionRecord.ExceptionCode ) {
84:
85: case EXCEPTION_ACCESS_VIOLATION:
86: strcat(szDebugEventBuffer, "ACCESS_VIOLATION");
87: break;
88:
89: case EXCEPTION_BREAKPOINT:
90: strcat(szDebugEventBuffer, "BREAKPOINT");
91: break;
92:
93: case EXCEPTION_DATATYPE_MISALIGNMENT:
94: strcat(szDebugEventBuffer, "DATATYPE_MISALIGNMENT");
95: break;
96:
97: case EXCEPTION_SINGLE_STEP:
98: strcat(szDebugEventBuffer, "SINGLE_STEP");
99: break;
100:
101: case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
102: strcat(szDebugEventBuffer, "ARRAY_BOUNDS_EXCEEDED");
103: break;
104:
105: case EXCEPTION_FLT_DIVIDE_BY_ZERO:
106: strcat(szDebugEventBuffer, "FLT_DIVIDE_BY_ZERO");
107: break;
108:
109: case EXCEPTION_FLT_INVALID_OPERATION:
110: strcat(szDebugEventBuffer, "FLT_INVALID_OPERATION");
111: break;
112:
113: case EXCEPTION_FLT_OVERFLOW:
114: strcat(szDebugEventBuffer, "FLT_OVERFLOW");
115: break;
116:
117: case EXCEPTION_FLT_STACK_CHECK:
118: strcat(szDebugEventBuffer, "FLT_STACK_CHECK");
119: break;
120:
121: case EXCEPTION_FLT_UNDERFLOW:
122: strcat(szDebugEventBuffer, "FLT_UNDERFLOW");
123: break;
124:
125: case EXCEPTION_INT_DIVIDE_BY_ZERO:
126: strcat(szDebugEventBuffer, "INT_DIVIDE_BY_ZERO");
127: break;
128:
129: case EXCEPTION_INT_OVERFLOW:
130: strcat(szDebugEventBuffer, "INT_OVERFLOW");
131: break;
132:
133: case EXCEPTION_PRIV_INSTRUCTION:
134: strcat(szDebugEventBuffer, "PRIV_INSTRUCTION");
135: break;
136:
137: default:
138: strcat(szDebugEventBuffer, "Unknown [0x");
139: strcat(szDebugEventBuffer,
140: LongToCharUpper( (LONG) DebugEvent.u.Exception.ExceptionRecord.ExceptionCode, szTempBuf, 16) );
141: strcat(szDebugEventBuffer, "]");
142: break;
143: }
144: if( fVerbose ) {
145: strcat(szDebugEventBuffer, " - dwFirstChance:");
146: strcat(szDebugEventBuffer,
147: LongToCharUpper( (LONG) DebugEvent.u.Exception.dwFirstChance, szTempBuf, 10) );
148: }
149: else {
150: if(DebugEvent.u.Exception.dwFirstChance != 0)
151: strcat(szDebugEventBuffer, " - First Chance");
152: else
153: strcat(szDebugEventBuffer, " - Second Chance");
154: }
155: break;
156:
157: case CREATE_THREAD_DEBUG_EVENT:
158: MakeDebugEventString(szDebugEventBuffer, "Create Thread",
159: &DebugEvent);
160: if( fVerbose ) {
161: strcat(szDebugEventBuffer, " - hThread:0x");
162: strcat(szDebugEventBuffer,
163: LongToCharUpper( (LONG) DebugEvent.u.CreateThread.hThread, szTempBuf, 16) );
164: strcat(szDebugEventBuffer, " - lpStartAddress:0x");
165: strcat(szDebugEventBuffer,
166: LongToCharUpper( (LONG) DebugEvent.u.CreateThread.lpStartAddress, szTempBuf, 16) );
167: }
168: break;
169:
170: case CREATE_PROCESS_DEBUG_EVENT:
171: MakeDebugEventString(szDebugEventBuffer, "Create Process",
172: &DebugEvent);
173: if( fVerbose ) {
174: strcat(szDebugEventBuffer, " - hFile:0x");
175: strcat(szDebugEventBuffer,
176: LongToCharUpper( (LONG) DebugEvent.u.CreateProcessInfo.hFile, szTempBuf, 16) );
177: strcat(szDebugEventBuffer, " - hProcess:0x");
178: strcat(szDebugEventBuffer,
179: LongToCharUpper( (LONG) DebugEvent.u.CreateProcessInfo.hProcess, szTempBuf, 16) );
180: strcat(szDebugEventBuffer, " - hThread:0x");
181: strcat(szDebugEventBuffer,
182: LongToCharUpper( (LONG) DebugEvent.u.CreateProcessInfo.hThread, szTempBuf, 16) );
183: strcat(szDebugEventBuffer, " - lpBaseOfImage:0x");
184: strcat(szDebugEventBuffer,
185: LongToCharUpper( (LONG) DebugEvent.u.CreateProcessInfo.lpBaseOfImage, szTempBuf, 16) );
186: strcat(szDebugEventBuffer, " - dwDebugInfoFileOffset:");
187: strcat(szDebugEventBuffer,
188: LongToCharUpper( (LONG) DebugEvent.u.CreateProcessInfo.dwDebugInfoFileOffset, szTempBuf, 10) );
189: strcat(szDebugEventBuffer, " - nDebugInfoSize:");
190: strcat(szDebugEventBuffer,
191: LongToCharUpper( (LONG) DebugEvent.u.CreateProcessInfo.nDebugInfoSize, szTempBuf, 10) );
192: strcat(szDebugEventBuffer, " - lpStartAddress:0x");
193: strcat(szDebugEventBuffer,
194: LongToCharUpper( (LONG) DebugEvent.u.CreateProcessInfo.lpStartAddress, szTempBuf, 16) );
195: }
196: break;
197:
198: case EXIT_THREAD_DEBUG_EVENT:
199: MakeDebugEventString(szDebugEventBuffer, "Exit Thread",
200: &DebugEvent);
201:
202: if( fVerbose ) {
203: strcat(szDebugEventBuffer, " - dwExitCode:");
204: }
205: else {
206: strcat(szDebugEventBuffer, " - Returned:");
207: }
208: strcat(szDebugEventBuffer,
209: LongToCharUpper( (LONG) DebugEvent.u.ExitThread.dwExitCode, szTempBuf, 10) );
210: break;
211:
212: case EXIT_PROCESS_DEBUG_EVENT:
213: MakeDebugEventString(szDebugEventBuffer, "Exit Process",
214: &DebugEvent);
215: if( fVerbose ) {
216: strcat(szDebugEventBuffer, " - dwExitCode:");
217: }
218: else {
219: strcat(szDebugEventBuffer, " - Returned:");
220: }
221: strcat(szDebugEventBuffer,
222: LongToCharUpper( (LONG) DebugEvent.u.ExitProcess.dwExitCode, szTempBuf, 10) );
223: break;
224:
225: case LOAD_DLL_DEBUG_EVENT:
226: MakeDebugEventString(szDebugEventBuffer, "Load DLL:",
227: &DebugEvent);
228:
229: GetModuleFileNameFromHeader(
230: hProcess, DebugEvent.u.LoadDll.hFile,
231: szTempBuf, 256 );
232: strcat( szDebugEventBuffer, szTempBuf );
233: if( fVerbose ) {
234: strcat(szDebugEventBuffer, " - hFile:0x");
235: strcat(szDebugEventBuffer,
236: LongToCharUpper( (LONG) DebugEvent.u.LoadDll.hFile, szTempBuf, 16) );
237: strcat(szDebugEventBuffer, " - lpBaseOfDll:0x");
238: strcat(szDebugEventBuffer,
239: LongToCharUpper( (LONG) DebugEvent.u.LoadDll.lpBaseOfDll, szTempBuf, 16) );
240: strcat(szDebugEventBuffer, " - dwDebugInfoFileOffset:");
241: strcat(szDebugEventBuffer,
242: LongToCharUpper( (LONG) DebugEvent.u.LoadDll.dwDebugInfoFileOffset, szTempBuf, 10) );
243: strcat(szDebugEventBuffer, " - nDebugInfoSize:");
244: strcat(szDebugEventBuffer,
245: LongToCharUpper( (LONG) DebugEvent.u.LoadDll.nDebugInfoSize, szTempBuf, 10) );
246: }
247: break;
248:
249: case UNLOAD_DLL_DEBUG_EVENT:
250: MakeDebugEventString(szDebugEventBuffer, "Unload DLL",
251: &DebugEvent);
252: if( fVerbose ) {
253: strcat(szDebugEventBuffer, " - lpBaseOfDLL:0x");
254: strcat(szDebugEventBuffer,
255: LongToCharUpper( (LONG) DebugEvent.u.UnloadDll.lpBaseOfDll, szTempBuf, 16) );
256: }
257: break;
258:
259: case OUTPUT_DEBUG_STRING_EVENT:
260: MakeDebugEventString(szDebugEventBuffer, "Output Debug String",
261: &DebugEvent);
262: strcat(szDebugEventBuffer, ":\"");
263:
264: //-- According to Win32 Specs Rev3, I need to use ReadVirtualMemory
265: // however this incorrect. ReadProcessMemory is the correct API
266: ReadProcessMemory( hProcess,
267: DebugEvent.u.DebugString.lpDebugStringData,
268: szTempBuf, DebugEvent.u.DebugString.nDebugStringLength,
269: &NumberOfBytesRead );
270: strcat(szDebugEventBuffer, szTempBuf );
271: strcat(szDebugEventBuffer, "\"" );
272: if( fVerbose ) {
273: strcat(szDebugEventBuffer, " - fUnicode:");
274: strcat(szDebugEventBuffer,
275: LongToCharUpper( (LONG) DebugEvent.u.DebugString.fUnicode, szTempBuf, 10) );
276: strcat(szDebugEventBuffer, " - nDebugStringLength:");
277: strcat(szDebugEventBuffer,
278: LongToCharUpper( (LONG) DebugEvent.u.DebugString.nDebugStringLength, szTempBuf, 10) );
279: }
280: break;
281:
282: default:
283: MakeDebugEventString(szDebugEventBuffer, "Debug Event:",
284: &DebugEvent);
285: strcat(szDebugEventBuffer, "Unknown [0x");
286: strcat(szDebugEventBuffer,
287: LongToCharUpper( (LONG) DebugEvent.dwDebugEventCode, szTempBuf, 16) );
288: strcat(szDebugEventBuffer, "]");
289: break;
290: }
291:
292: //-- insert the debug event string into the listbox
293: ListBoxPrintF( "%s", szDebugEventBuffer );
294:
295: //-- handle minimal exception handling needs for particular events
296: switch( DebugEvent.dwDebugEventCode ) {
297:
298: case EXCEPTION_DEBUG_EVENT:
299: switch( DebugEvent.u.Exception.ExceptionRecord.ExceptionCode ) {
300:
301: #if( MIPS == 1 )
302: case STATUS_BREAKPOINT:
303: //-- increment instruction pointer past the break point
304: // only needed for the MIPS R4000
305: if( !SkipBreakPoint( DebugEvent.dwThreadId ) )
306: ListBoxInsert( hWndDebugList, &MaxStrLen,
307: "--> Failed To skip over the Break Point" );
308: break;
309: #endif
310:
311: case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
312: case EXCEPTION_FLT_DIVIDE_BY_ZERO:
313: case EXCEPTION_FLT_INVALID_OPERATION:
314: case EXCEPTION_FLT_OVERFLOW:
315: case EXCEPTION_FLT_STACK_CHECK:
316: case EXCEPTION_FLT_UNDERFLOW:
317: case EXCEPTION_INT_DIVIDE_BY_ZERO:
318: case EXCEPTION_INT_OVERFLOW:
319: case EXCEPTION_PRIV_INSTRUCTION:
320: case STATUS_ACCESS_VIOLATION:
321: ContinueDebugEvent( DebugEvent.dwProcessId, DebugEvent.dwThreadId,
322: DBG_EXCEPTION_NOT_HANDLED );
323: }
324: break;
325:
326: case CREATE_PROCESS_DEBUG_EVENT:
327: CreateNode( &ProcessList, &ThreadNode );
328: (ThreadNode->NodeData).dwThreadId = DebugEvent.dwThreadId;
329: (ThreadNode->NodeData).hThread = DebugEvent.u.CreateProcessInfo.hThread;
330: InsertNode( &ProcessList, ThreadNode );
331: if( ++ActiveProcesses == 1 ) {
332: //-- store the current process handle in the temp global handle
333: hProcess = DebugEvent.u.CreateProcessInfo.hProcess;
334: }
335: break;
336:
337: case CREATE_THREAD_DEBUG_EVENT:
338: CreateNode( &ProcessList, &ThreadNode );
339: (ThreadNode->NodeData).dwThreadId = DebugEvent.dwThreadId;
340: (ThreadNode->NodeData).hThread = DebugEvent.u.CreateThread.hThread;
341: InsertNode( &ProcessList, ThreadNode );
342: break;
343:
344: case EXIT_THREAD_DEBUG_EVENT:
345: (ThreadNode->NodeData).dwThreadId = DebugEvent.dwThreadId;
346: GetNode( &ProcessList, &ThreadNode, OrderFunc, 1 );
347: DeleteCurrentNode( &ProcessList );
348: break;
349:
350: case EXIT_PROCESS_DEBUG_EVENT:
351: //-- if the event was EXIT_PROCESS_DEBUG_EVENT and it was the
352: // original process opened/attached to then exit the
353: // debug event processing thread. Also do some cleanup first.
354: (ThreadNode->NodeData).dwThreadId = DebugEvent.dwThreadId;
355: GetNode( &ProcessList, &ThreadNode, OrderFunc, 1 );
356: DeleteCurrentNode( &ProcessList );
357: DestroyNode( TempNode );
358: if( --ActiveProcesses == 0 ) {
359: ExitThread( TRUE );
360: }
361: break;
362: }
363:
364: //-- default action - just continue
365: ContinueDebugEvent( DebugEvent.dwProcessId, DebugEvent.dwThreadId,
366: DBG_CONTINUE );
367: }
368:
369: return( FALSE );
370: }
371:
372:
373: // ************************************************************************
374: // FUNCTION : GetModuleFileNameFromHeader( HANDLE, HANDLE, LPTSTR, DWORD )
375: // PURPOSE : Retrieves the DLL module name for a given file handle of a
376: // the module. Reads the module name from the EXE header.
377: // COMMENTS : Retrieves only the module name and not the pathname
378: // ************************************************************************
379: DWORD APIENTRY
380: GetModuleFileNameFromHeader( HANDLE hProcess, HANDLE hFile, LPTSTR lpszPath,
381: DWORD cbPath )
382: {
383: #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
384: #define IMAGE_OS2_SIGNATURE 0x454E // NE
385: #define IMAGE_NT_SIGNATURE 0x00004550 // PE00
386:
387: #define IMAGE_SECOND_HEADER_OFFSET (15 * sizeof(ULONG)) // relative to file beginning
388: #define IMAGE_BASE_OFFSET (13 * sizeof(DWORD)) // relative to PE header base
389: #define IMAGE_EXPORT_TABLE_RVA_OFFSET (30 * sizeof(DWORD)) // relative to PE header base
390: #define IMAGE_NAME_RVA_OFFSET (3 * sizeof(DWORD)) // relative to Exports/Imports table base
391:
392: WORD DosSignature;
393: DWORD NtSignature;
394: DWORD NumberOfBytesRead;
395:
396: DWORD PeHeader, ImageBase, ExportTableRVA, NameRVA;
397:
398: //-- verify that the handle is not NULL
399: if( !hFile ) {
400: strcpy( lpszPath, "hFile is NULL!" );
401: return( 0 );
402: }
403:
404: //-- verify that the handle is for a disk file
405: if( GetFileType(hFile) != FILE_TYPE_DISK ) {
406: strcpy( lpszPath, "Incorrect hFile Type!" );
407: return( 0 );
408: }
409:
410: //-- Extract the filename from the EXE header
411: ReadFile( hFile, &DosSignature, sizeof(DosSignature), &NumberOfBytesRead,
412: (LPOVERLAPPED) NULL);
413:
414: if( DosSignature == IMAGE_DOS_SIGNATURE ) {
415:
416: SetFilePointer( hFile, IMAGE_SECOND_HEADER_OFFSET, (LPLONG) NULL,
417: FILE_BEGIN );
418: ReadFile( hFile, &PeHeader, sizeof(PeHeader),
419: &NumberOfBytesRead, (LPOVERLAPPED) NULL );
420:
421: SetFilePointer( hFile, PeHeader, (LPLONG) NULL,
422: FILE_BEGIN );
423: ReadFile( hFile, &NtSignature, sizeof(NtSignature),
424: &NumberOfBytesRead, (LPOVERLAPPED) NULL);
425:
426: if( NtSignature == IMAGE_NT_SIGNATURE ) {
427:
428: SetFilePointer( hFile, PeHeader+IMAGE_BASE_OFFSET,
429: (LPLONG) NULL, FILE_BEGIN );
430: ReadFile( hFile, &ImageBase, sizeof(ImageBase),
431: &NumberOfBytesRead, (LPOVERLAPPED) NULL);
432:
433: SetFilePointer( hFile, PeHeader + IMAGE_EXPORT_TABLE_RVA_OFFSET,
434: (LPLONG) NULL, FILE_BEGIN );
435: ReadFile( hFile, &ExportTableRVA, sizeof(ExportTableRVA),
436: &NumberOfBytesRead, (LPOVERLAPPED) NULL);
437:
438: //-- now read from the virtual address space in the process
439: ReadProcessMemory( hProcess,
440: (LPVOID) (ImageBase + ExportTableRVA + IMAGE_NAME_RVA_OFFSET),
441: &NameRVA, sizeof(NameRVA), &NumberOfBytesRead );
442:
443: ReadProcessMemory( hProcess,
444: (LPVOID) (ImageBase+NameRVA),
445: lpszPath, cbPath, &NumberOfBytesRead );
446:
447: return( NumberOfBytesRead );
448: }
449: else
450: sprintf( lpszPath, "NtSignature is 0x%x!", NtSignature );
451:
452: }
453: else
454: sprintf( lpszPath, "DosSignature is 0x%x!", DosSignature );
455:
456: return( 0 );
457: }
458:
459:
460: #if( MIPS == 1 )
461: // ************************************************************************
462: // FUNCTION : SkipThreadBreakPoint( DWORD );
463: // PURPOSE : Skip over the break point instruction belonging to
464: // dwThreadId
465: // COMMENTS : Only the MIPS R4000 requires this
466: // ************************************************************************
467: BOOL
468: SkipBreakPoint( DWORD dwThreadId )
469: {
470: CONTEXT Context;
471: PNODE ThreadNode;
472: PNODE InputNode;
473:
474: CreateNode( &ProcessList, &InputNode );
475: ThreadNode = InputNode;
476: (InputNode->NodeData).dwThreadId = dwThreadId;
477:
478: if( GetNode( &ProcessList, &ThreadNode, OrderFunc, 1 ) == NO_MATCH_ERROR ) {
479: ListBoxInsert( hWndDebugList, &MaxStrLen, "--> Error: Node not found" );
480: return( FALSE );
481: }
482:
483: Context.ContextFlags = CONTEXT_CONTROL;
484:
485: if( !GetThreadContext( (ThreadNode->NodeData).hThread, &Context ) ) {
486: char szTempBuf[64];
487:
488: sprintf(szTempBuf, "--> Error: dwThreadId = 0x%8.8lx", dwThreadId );
489: ListBoxInsert( hWndDebugList, &MaxStrLen, szTempBuf );
490: sprintf(szTempBuf, "--> Error: GetThreadContext( %lx ) failed, error 0x%8.8lx",
491: (DWORD) (ThreadNode->NodeData).hThread,
492: (DWORD) GetLastError() );
493: ListBoxInsert( hWndDebugList, &MaxStrLen, szTempBuf);
494:
495: return( FALSE );
496: }
497:
498: Context.Fir += 4L; // Fir is the PC (program counter)
499: // BREAK (breakpoint instruction) occupies 4 bytes
500:
501: // -----------------------------------------------------------------------
502: // Below would be equvalent for the Intel 80x86 if it were necessary
503: // Context.Eip += 2L; // Eip is the PC (program counter)
504: // // int 3 (breakpoint instruction) occupies 2 bytes
505: // -----------------------------------------------------------------------
506:
507: SetThreadContext( (ThreadNode->NodeData).hThread, &Context );
508: DestroyNode( InputNode );
509:
510: return( TRUE );
511: }
512: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.