#$K{bmc deb.bmp} Debug Event Browser
Overviews
General Overview
Programming Overview

How To...
Using the Toolbar

Commands
File Menu
Edit Menu
Options Menu
Help Menu
Keyboard

#$KKGeneral Overview
Debug Event Browser (DEB) is a Win32 application demonstrating the Win32 debug API.  This preliminary version of DEB only performs the most rudimentary debugging operations.  DEB is not a debugger in the traditional sense but a browser which merely displays the debug events occurring in a debuggee.  The handling of debug events is restricted only to those actions which are necessary to display event information and continue the debuggee.

This Sample is brought to you by:
  Microsoft Developer Support
  Developed by Paul Tissue

#$KKKProgramming Overview
The Debug Event Browser (DEB) sample demonstrates the following Win32 debug API features:

Debug Event Handler
Modifying a Thread's Context
Reading the Executable's Header

#$KKKKDebug Event Handler
The debug event handler is responsible for the processing of the debug events.

// ************************************************************************
// FUNCTION : DebugEventThread( DWORD )
// PURPOSE  : Main debug event processing loop
// COMMENTS : The same debugger thread which creates a debuggee process or
//            attaches to a currently running process must also handle all
//            the debug events for that process.
// ************************************************************************
DWORD WINAPI
DebugEventThread( DWORD UserDefinedValue )
{
  DEBUG_EVENT DebugEvent;

  for(;;) {
    if( !WaitForDebugEvent( &DebugEvent, INFINITE ) ) 
      continue;
    switch( DebugEvent.dwDebugEventCode ) {
      case EXCEPTION_DEBUG_EVENT:
        // ...
        switch( DebugEvent.u.Exception.ExceptionRecord.ExceptionCode 
          case EXCEPTION_ACCESS_VIOLATION:
            // ...handle exception
            break;
          case EXCEPTION_BREAKPOINT:
            // ...handle exception
            break;
          //...
          default:  // An unknown exception occurred
            // ...handle exception
            break;
        }
      case CREATE_THREAD_DEBUG_EVENT:
        // ...handle debug event
        break;
      case CREATE_PROCESS_DEBUG_EVENT:
        // ...handle debug event
        break;
      // ...
      default:
        // ...handle debug event
        break;
    }
    //-- default action - just continue
    ContinueDebugEvent( DebugEvent.dwProcessId, DebugEvent.dwThreadId,
      DBG_CONTINUE );
  }

  return( NULL );
}

#$KKKKReading the Executable's Header
Reading the information stored in the executable's headers is important for obtaining such things as symbolic information and details about the object.

// ************************************************************************
// FUNCTION : GetModuleFileNameFromHeader( HANDLE, HANDLE, DWORD, LPTSTR, DWORD )
// PURPOSE  : Retrieves the DLL module name for a given file handle of a
//            the module.  Reads the module name from the EXE header.
// COMMENTS :
//   Retrieves only the module name and not the pathname.  Returns the
//   number of characters copies to the buffer, else returns 0.
// ************************************************************************
DWORD
GetModuleFileNameFromHeader( HANDLE hProcess, HANDLE hFile, DWORD BaseOfDll,
  LPTSTR lpszPath, DWORD cchPath )
{
  #define IMAGE_SECOND_HEADER_OFFSET    (15 * sizeof(ULONG)) // relative to file beginning
  #define IMAGE_BASE_OFFSET             (13 * sizeof(DWORD)) // relative to PE header base
  #define IMAGE_EXPORT_TABLE_RVA_OFFSET (30 * sizeof(DWORD)) // relative to PE header base
  #define IMAGE_NAME_RVA_OFFSET         offsetof(IMAGE_EXPORT_DIRECTORY, Name)

  WORD   DosSignature;
  DWORD  NtSignature;
  DWORD  dwNumberOfBytesRead = 0;
  DWORD  PeHeader, ImageBase, ExportTableRVA, NameRVA;

  //-- verify that the handle is not NULL
  if( !hFile ) {
    lstrcpy( lpszPath, "Invalid File Handle" );
    return( 0 );
  }

  //-- verify that the handle is for a disk file
  if( GetFileType(hFile) != FILE_TYPE_DISK ) {
    lstrcpy( lpszPath, "Invalid File Type" );
    return( 0 );
  }

  //-- Extract the filename from the EXE header
  SetFilePointer( hFile, 0L, NULL, FILE_BEGIN );
  ReadFile( hFile, &DosSignature, sizeof(DosSignature), &dwNumberOfBytesRead,
    (LPOVERLAPPED) NULL);

  //-- verify DOS signature found
  if( DosSignature != IMAGE_DOS_SIGNATURE ) {
    wsprintf( lpszPath, TEXT( "Bad MZ Signature: 0x%x" ), DosSignature );
    return( 0 );
  }

  SetFilePointer( hFile, IMAGE_SECOND_HEADER_OFFSET, (LPLONG) NULL,
    FILE_BEGIN );
  ReadFile( hFile, &PeHeader, sizeof(PeHeader), &dwNumberOfBytesRead,
    (LPOVERLAPPED) NULL );
  SetFilePointer( hFile, PeHeader, (LPLONG) NULL, FILE_BEGIN );
  ReadFile( hFile, &NtSignature, sizeof(NtSignature), &dwNumberOfBytesRead,
    (LPOVERLAPPED) NULL);

  //-- verify Windows NT (PE) signature found
  if( NtSignature != IMAGE_NT_SIGNATURE ) {
    wsprintf( lpszPath, TEXT( "Bad PE Signature: 0x%x" ), DosSignature );
    return( 0 );
  }

  SetFilePointer( hFile, PeHeader + IMAGE_BASE_OFFSET, (LPLONG) NULL,
    FILE_BEGIN );
  ReadFile( hFile, &ImageBase, sizeof(ImageBase), &dwNumberOfBytesRead,
    (LPOVERLAPPED) NULL);
  SetFilePointer( hFile, PeHeader + IMAGE_EXPORT_TABLE_RVA_OFFSET,
    (LPLONG) NULL, FILE_BEGIN );
  ReadFile( hFile, &ExportTableRVA, sizeof(ExportTableRVA),
    &dwNumberOfBytesRead, (LPOVERLAPPED) NULL);

  //-- now read from the virtual address space in the process
  ReadProcessMemory( hProcess,
     (LPVOID) (BaseOfDll + ExportTableRVA + IMAGE_NAME_RVA_OFFSET),
     &NameRVA, sizeof(NameRVA), &dwNumberOfBytesRead );
  lstrcpy( lpszPath, "Empty!" );
  if( !ReadProcessMemory( hProcess,
         (LPVOID) (BaseOfDll + NameRVA),
         lpszPath, cchPath, &dwNumberOfBytesRead ) )
     lstrcpy( lpszPath, "Access Denied!" );

  return( dwNumberOfBytesRead );
}

#$KKKKKModifying a Thread's Context
The ability to query and modify a thread's context is one of the more powerful features of the Win32 debug API set.

// ************************************************************************
// FUNCTION : SkipThreadBreakPoint( HANDLE );
// PURPOSE  : Skip over the break point instruction belonging to
//            hThread.
// COMMENTS :
//   Only the MIPS R4x00 and Alpha AXP require this.
// ************************************************************************
BOOL
SkipBreakPoint( HANDLE hThread )
{
  static CONTEXT Context;

  Context.ContextFlags = CONTEXT_CONTROL;
  if( !GetThreadContext( hThread, &Context ) )
    return( FALSE );
  Context.Fir += 4L;  // Fir is the PC (program counter)
                      // BREAK (breakpoint instruction) occupies 4 bytes
  SetThreadContext( hThread, &Context );

  return( TRUE );
}

#$KHow To Use The Toolbar
The Toolbar allows quick and convenient access to several Debug Event Browser options simply with the click of the mouse.

{bmc toolbar.bmp}

#$KKFile Menu Commands
Allows the user to select the debuggee for this application.

Open...
Displays a dialog box that will allow you to open and run an executable file using a common dialog box.  This executable file will become the debuggee.

Attach...
Displays a dialog box that will allow you to select a currently running process to attach to.  This process will become the debuggee.

Exit
Exits the Debug Event Browser application.

#$KKEdit Menu Commands
Allows the user to copy text to the clipboard.

Cut
Copies the text in the Debug Event window and then delete it from the window.

Copy
Copies the text in the Debug Event window.

Delete
Deletes the text in the Debug Event window.

#$KKOptions Menu Commands
Allows the user to set various options and preferences for this application.

Fonts...
Displays a dialog box that will allow you to set the font for the Debug Event window.

Background Color...
Displays a dialog box that will allow you to set the background color for the Debug Event window.

Preferences...
Displays a dialog box that will allow you to set the options and preferences for this application.

Toolbar
Displays the Tool Bar when checked.

Use Saved Directory
This menu option will set the default directory to the one that was previously saved.  This only occurs when checked.

Save Settings On Exit
This menu option will save all the current session settings upon exiting. This only occurs when checked.

Save Settings Now
This menu option will save all the current session settings now.

#$KKHelp Menu Commands
Displays various types of information regarding to the Debug Event Browser application.

Contents
Displays the contents of the Online Help.

Search for Help on...
Displays a list of keywords to search for Online Help topics.

How to use Help
Displays the instructions for using the Online Help facilities.

About Debug Event Browser...
Displays product information about the Debug Event Browser.

#$KKeyboard Commands
The keyboard commands allows quick and convenient access to several Debug Event Browser options using simple key combinations.

Control Keys

Ctrl+A
Attaches to a currently running process and begins debugging it.

Ctrl+C
Copies the text in the Debug Event window.

Ctrl+O
Opens an executable and debugs it.

Ctrl+X
Copies the text in the Debug Event window and then delete it from the window.

Alternate Keys

Alt+F4
Exits the Debug Event Browser.

Single Keys

F1
Invokes the help file for the Debug Event Browser.

Del
Deletes the text in the Debug Event window.