zoukankan      html  css  js  c++  java
  • win32调试工具原理OutputDebugString以及如何获取输出信息

    在应用程序和调试器之间传递数据是通过一个 4KB 大小的共享内存块完成的,并有一个互斥量和两个事件对象用来保护对他的访问。下面就是相关的四个内核对象:

    对象名称对象类型
    DBWinMutex Mutex
    DBWIN_BUFFER Section (共享内存)
    DBWIN_BUFFER_READY Event
    DBWIN_DATA_READY Event

    互斥量通常一直保留在系统中,其他三个对象仅当调试器要接收信息才出现。事实上 - 如果一个调试器发现后三个对象已经存在,它会拒绝运行。

    当 DBWIN_BUFFER 出现时,会被组织成以下结构。进程 ID 显示信息的来源,字符串数据填充这 4K 的剩余部分。按照约定,信息的末尾总是包括一个 NULL 字节。

    struct dbwin_buffer {
                    DWORD   dwProcessId;
                    char    data[4096-sizeof(DWORD)];
                    };
                    

    OutputDebugString() 被应用调用时,它执行以下步骤。注意在任意位置的错误都将放弃整个事情,调试请求被认为是什么也不做(不会发送字符串)。

    1. 打开 DBWinMutex 并且等待,直到我们取得了独占访问。
    2. 映射 DBWIN_BUFFER 段到内存中:如果没有发现,则没有调试器在运行,将忽略整个请求。
    3. 打开 DBWIN_BUFFER_READYDBWIN_DATA_READY 事件对象。就像共享内存段一样,缺少对象意味着没有可用的调试器。
    4. 等待 DBWIN_BUFFER_READY 事件对象为有信号状态:表示内存缓冲区不再被占用。大部分时候,这一事件对象一被检查就处于有信号状态,但等待缓冲区就绪不会超过 10 秒(超时将放弃请求)。
    5. 复制数据直到内存缓冲区中接近 4KB,再保存当前进程 ID。总是放置一个 NULL 字节到字符串结尾。
    6. 通过设置 DBWIN_DATA_READY 事件对象告诉调试器缓冲区就绪。调试器从那儿取走它。
    7. 释放互斥量。
    8. 关闭事件对象和段对象,但保留互斥量的句柄以备后用。

    在调试器端会简单一点。互斥量根本不需要,如果事件对象和/或共享内存对象已经存在,则假定其他调试器已经在运行。系统中任意时刻只能存在一个调试器。

    1. 创建共享内存段以及两个事件对象。如果失败,退出。
    2. 设置 DBWIN_BUFFER_READY 事件对象,由此应用程序得知缓冲区可用。
    3. 等待 DBWIN_DATA_READY 事件对象变为有信号状态。
    4. 从内存缓冲区中提取进程 ID 和 NULL 结尾的字符串。
    5. 转到步骤 2。

    这使我们认为这决不是一种低消耗的发送信息的方法,应用程序的运行速度会受到调试器的左右。

    #define WIN32_LEAN_AND_MEAN
    
    #include <Windows.h>
    #include <stdio.h>
    
    #define IfFalseRet(c) do{if(!(c)){return dwLastError = ::GetLastError();}}while(false)
    
    class CHandle
    {
    public:
      CHandle(HANDLE h = NULL): m_h(h)
      {
      }
      ~CHandle()
      {
        Release();
      }
      void Release()
      {
        if(*this)
        {
          ::CloseHandle(m_h);
        }
        m_h = NULL;
      }
      operator bool() const
      {
        return m_h != INVALID_HANDLE_VALUE && m_h != NULL;
      }
      operator HANDLE() const
      {
        return m_h;
      }
      CHandle& operator= (const HANDLE& h)
      {
        Release();
        m_h = h;
        return *this;
      }
      CHandle& operator= (CHandle& h)
      {
        if(this != &h)
        {
          HANDLE hSwap = m_h;
          m_h = h.m_h;
          h.m_h = hSwap;
          h.Release();
        }
        return *this;
      }
    private:
      HANDLE m_h;
    };
    
    LPCTSTR DBWIN_BUFFER = TEXT("DBWIN_BUFFER");
    LPCTSTR DBWIN_BUFFER_READY = TEXT("DBWIN_BUFFER_READY");
    LPCTSTR DBWIN_DATA_READY = TEXT("DBWIN_DATA_READY");
    LPCTSTR DBWIN_MUTEX = TEXT("DBWinMutex");
    
    #pragma pack(push, 1)
    struct CDBWinBuffer
    {
      DWORD dwProcessId;
      BYTE  abData[4096 - sizeof(DWORD)];
    };
    #pragma pack(pop)
    
    bool g_fContinue = true;
    
    BOOL CtrlHandler(DWORD fdwCtrlType)
    {
      switch(fdwCtrlType)
      {
      case CTRL_C_EVENT:
      case CTRL_CLOSE_EVENT:
      case CTRL_LOGOFF_EVENT:
      case CTRL_SHUTDOWN_EVENT:
        g_fContinue = false;
        return TRUE;
      }
      return FALSE;
    }
    
    int __cdecl main()
    {
      DWORD dwLastError = ERROR_SUCCESS;
    
      IfFalseRet(SetConsoleCtrlHandler((PHANDLER_ROUTINE)(CtrlHandler), TRUE) == TRUE);
    
      CHandle hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, DBWIN_MUTEX);
      if(!hMutex)
      {
        IfFalseRet(GetLastError() == ERROR_FILE_NOT_FOUND);
        IfFalseRet(hMutex = CreateMutex(NULL, FALSE, DBWIN_MUTEX));
      }
      
      CHandle hEventBufferReady = OpenEvent(EVENT_MODIFY_STATE, FALSE, DBWIN_BUFFER_READY);
      if(!hEventBufferReady)
      {
        IfFalseRet(GetLastError() == ERROR_FILE_NOT_FOUND);
        IfFalseRet(hEventBufferReady = CreateEvent(NULL, FALSE, TRUE, DBWIN_BUFFER_READY));
      }
      
      CHandle hEventDataReady = OpenEvent(EVENT_MODIFY_STATE, FALSE, DBWIN_DATA_READY);
      if(!hEventDataReady)
      {
        IfFalseRet(GetLastError() == ERROR_FILE_NOT_FOUND);
        IfFalseRet(hEventDataReady = CreateEvent(NULL, FALSE, FALSE, DBWIN_DATA_READY));
      }
    
      CHandle hFileMappingBuffer = OpenFileMapping(FILE_MAP_READ, FALSE, DBWIN_BUFFER);
      if(!hFileMappingBuffer)
      {
        IfFalseRet(GetLastError() == ERROR_FILE_NOT_FOUND);
        IfFalseRet(hFileMappingBuffer = CreateFileMapping(
          INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
          0, sizeof(CDBWinBuffer), DBWIN_BUFFER));
      }
    
      CDBWinBuffer* pDbgBuffer = (CDBWinBuffer*)(MapViewOfFile(
        hFileMappingBuffer, SECTION_MAP_READ, 0, 0, 0));
      IfFalseRet(pDbgBuffer);
    
      while(g_fContinue)
      {
        if(WaitForSingleObject(hEventDataReady, 100) == WAIT_OBJECT_0)
        {
          printf("%s", pDbgBuffer->abData);
          SetEvent(hEventBufferReady);
        }
      }
    
      UnmapViewOfFile(pDbgBuffer);
    
      return dwLastError;
    
    }
  • 相关阅读:
    hdu 1028 Ignatius and the Princess III (n的划分)
    CodeForces
    poj 3254 Corn Fields (状压DP入门)
    HYSBZ 1040 骑士 (基环外向树DP)
    PAT 1071 Speech Patterns (25)
    PAT 1077 Kuchiguse (20)
    PAT 1043 Is It a Binary Search Tree (25)
    PAT 1053 Path of Equal Weight (30)
    c++ 常用标准库
    常见数学问题
  • 原文地址:https://www.cnblogs.com/UnGeek/p/3443934.html
Copyright © 2011-2022 走看看