`
aigo
  • 浏览: 2674692 次
  • 性别: Icon_minigender_1
  • 来自: 宜昌
社区版块
存档分类
最新评论

windows下捕获dump之守护进程

阅读更多

原文http://www.cnblogs.com/cswuyg/p/3293326.html

 

 

  一两个月前为产品写了一个独立的exe,由于产品使用的捕获dump是一个现成的进程外exe,如果以资源的方式集成它容易出现安全警告,由于时间关系没有寻求新的解决方法,还是遵循旧方案,不捕获dump。 最近业余看了会儿breakpad client,想到一个解决方案——其实也蛮简单的,最后exe大概会增加200多KB。下边从头分析。

  有这样一种需求,希望一个进程启动之后,有另一个进程来“守护”它,当它发生crash时,能生成dump,然后把它重启;还有一个要求,“守护”进程跟工作进程必须是在同一个物理文件里,就像chromium一样,它是多进程的,但只有exe文件只有一个。借助breakpad client,这是很容易实现的事情,“守护”进程即是breakpad client中的服务进程,工作进程即是breakpad client中的客户进程。

一、思路

1、dump捕获,基于breakpad client。

2、守护,在breakpad服务进程的客户端crash回调里重启工作进程(不能直接做重启,需要做些简单处理)。

3、一个物理文件多种功能进程,代码都放在一个物理文件里,不同类进程根据命令行参数做区分。

二、需要注意的问题  

1、首先启动的是工作进程,由工作进程启动守护进程,工作进程需要等待守护进程的初始化完毕(主要是用于进程通信的管道)才开始注册异常处理。现在我看到的chromium代码,没有使用进程外dump,所以没有等待逻辑。

2、工作进程没有后退策略,当守护进程被异常结束时,客户进程崩溃就没法处理了,可以考虑在客户进程的crash回调做处理,但这种处理是在crash线程做的,最好是让异常处理的安全线程在进程外dump触发的情况下仍然启动,作为后备策略,demo暂不考虑这特殊情况。 

3、进程crash之后,全局C++对象的析构函数不会被调用。 

4、守护进程在重启工作进程之前,需要等到工作进程已经退出、守护进程的管道已经停止,才能重启。

三、实现

1、工作进程启动守护进程时,加上命令行参数crash_server=XXX,XXX为GUID Event名,守护进程启动之后置位该Event,工作进程等待该Event置位再继续往下执行。

2、crash发生时,守护进程的主线程等待客户进程退出;接着主线程析构crash_server、启动客户进程;接着主线程等待工作线程的dump上传完毕;最后退出主线程。crash没有发生时:守护进程在主线程等待客户进程退出后退出。

3、chromium的crash_service.cc 为防止server进程上传dump时主线程突然退出,做了几个防止措施:(1)、在客户进程退出时,sleep 1000毫秒给dump上传函数执行的机会,然后再给自己发送WM_CLOSE消息;(2)、dump上传函数跟CrashService类的析构函数有临界区锁,当上传函数未执行完毕时,CrashService不会析构,所以主线程也就不会先退出。我写的demo,守护进程没有创建窗口,也不使用WM_CLOSE消息。

4、chromium也有重启机制,可以在breakpad_win.cc中看到,是在客户进程的crash回调中做的。

部分代码:

Process Entry:

复制代码
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int /*nCmdShow*/)
{
    CmdlineParser cmd_parse(lpstrCmdLine);
    std::wstring server_start_event_name = cmd_parse.GetValueByKey(L"crash_server");
    if (!server_start_event_name.empty())
    {
        GuardProcess::GuardProcessMain(server_start_event_name);
        return 0;
    }
    else
    {
        WorkProcess::WorkProcessMain(hInstance);
        return 0;
    }
}
复制代码

Guard process Main Function:

复制代码
void GuardProcessMain(const std::wstring& server_start_event_name)
    {
        if (!CrashServerStart(server_start_event_name))
        {
            return;
        }

        while(!g_client_exit)
        {
            ::Sleep(1000);
        }
        if (g_restart_client)
        {
            delete g_crash_server;
            g_crash_server = NULL;
            wchar_t lpszFileName[MAX_PATH] = {0};
            ::GetModuleFileName(NULL, lpszFileName, MAX_PATH);
            std::wstring strFullName = lpszFileName;
            ::ShellExecute(NULL, L"open", strFullName.c_str(), NULL, NULL, SW_SHOWNORMAL);
        }
        if (g_uploadover != NULL)
        {
            DWORD dwRet = ::WaitForSingleObject(g_uploadover, 15000);
            if (dwRet != WAIT_OBJECT_0)
            {
                //error
            }
        }

    }
复制代码

Work Process Main Function:

复制代码
    void WorkProcessMain(HINSTANCE hInstance)
    {
        StartServerExe();
        AddExceptionCatch();

        HRESULT hRes = ::CoInitialize(NULL);
        ATLASSERT(SUCCEEDED(hRes));
        ::DefWindowProc(NULL, 0, 0, 0L);
        AtlInitCommonControls(ICC_BAR_CLASSES);    
        hRes = _Module.Init(NULL, hInstance);
        ATLASSERT(SUCCEEDED(hRes));

        int nRet = 0;
        {
            CMainDlg dlgMain;
            nRet = dlgMain.DoModal();
        }
        _Module.Term();
        ::CoUninitialize();
    }
复制代码

四、总结

  本demo的主要难点是在细节的考虑上,思路是比较简单的。breakpad的使用极其方便;一个物理文件多个功能进程的思路也很常见。

五、一些基础

  当然就是breakpad client代码了,我做了一些学习分享放在:

《windows下捕获dump》http://www.cnblogs.com/cswuyg/p/3207576.html

《windows下捕获dump之Google breakpad_client的理解》http://www.cnblogs.com/cswuyg/p/3286244.html

  breakpad client的学习代码可从https://github.com/cswuyg/google_breakpad_client下载到。

分享到:
评论

相关推荐

    Troubleshooting Guide for Java

    - **jsadebugd Daemon**:用于远程调试的服务守护进程。 - **jstatd Daemon**:用于远程监控的守护进程。 #### 二、Java Flight Recordings Java Flight Recordings (JFR) 是一种高级的日志记录机制,它可以自动...

    Unix编程常见问题解答 高清PDF含书签目录

    但是,如果子进程是作为守护进程运行的,那么它可能已经脱离了终端,此时就不会接收到 `SIGHUP` 信号。 ##### 1.16 How can I kill all descendents of a process? 我怎样杀死一个进程的所有派生进程? - **方法**...

    snort manual

    - **Running Snort as a Daemon(作为守护进程运行Snort)**: 通过这种方式启动Snort可以在后台持续运行,而不会占用终端资源。 #### Snort的配置文件详解 - **Includes**: Snort支持在主配置文件中包含其他配置...

    snort配置手册

    - **守护进程模式**: 可以作为后台服务运行,提高系统的稳定性。 - **规则存根创建模式**: 用于生成规则文件的模板。 - **IP地址混淆**: 在输出中隐藏真实的IP地址信息。 - **多实例标识**: 允许多个Snort实例同时...

    PHP 信号管理知识整理汇总

    了解并有效地利用PHP的信号管理功能,能帮助开发人员更好地控制和管理PHP脚本,尤其是在处理长时间运行、守护进程或者需要响应外部事件的场景下,信号机制显得尤为重要。通过合理地注册信号处理函数,可以确保程序在...

    Snort 手册

    同时,也讨论了Snort的其他杂项功能,比如作为守护进程运行、在规则存根创建模式下运行、地址掩码打印以及多实例标识符的指定等。 Snort的配置涉及到许多高级选项和预处理器,手册分别介绍每一种预处理器的特定用途...

    snort 2.9.3 用户使用手册

    2. **杂项设置**:包括作为守护进程运行、规则存根创建模式、IP地址混淆、多实例标识符指定等。 3. **控制套接字**:实现远程管理和配置更新。 4. **更多信息获取**:提供官方文档、论坛、邮件列表等资源链接,以便...

    snort_manual.pdf

    手册还介绍了如何让Snort作为守护进程运行、在规则存根创建模式下运行、混淆IP地址打印输出、指定多个实例标识符、定义控制套接字、配置信号值等。 5. 其他资源 除了上述内容,Snort用户手册还提供了指向更多资源的...

    snort menu

    - **后台运行**:Snort 可以作为守护进程运行,以避免占用终端窗口。 - **规则存根创建模式**:这是一种特殊的运行模式,用于生成规则存根文件。 - **IP 地址混淆**:为了保护隐私,Snort 支持对 IP 地址进行混淆...

    HCI抓取环境搭建.zip

    这将启动蓝牙守护进程(bluetoothd)并使其开始记录HCI日志到/sdcard/hci.log。请注意,这个命令可能需要root权限才能执行。一旦日志开始记录,你可以进行TWS耳机的配对和连接操作,以便在日志中捕捉到相关活动。 ...

    snort 用户手册

    - **守护进程模式**:使Snort以后台服务的方式运行。 - **规则存根创建模式**:生成规则存根文件,便于编写新规则。 - **IP地址模糊化**:在输出中模糊化IP地址,保护隐私。 - **指定多个实例标识符**:允许同时运行...

    ceph知识树.pdf

    - **OSD**:对象存储守护进程,负责数据存储。 - **librados**:RADOS的C/C++库。 - **radosbench性能压测**:用于评估RADOS性能。 - **RBD**:块设备存储。 - **librbd**:RBD的C/C++库。 - **krbd**:RBD的内核...

    Java并发编程面试题(2022最新版)

    - 异常会传播到主线程,如果未被捕获,可能导致程序崩溃。 **Java线程数过多会造成什么异常** - 导致内存溢出(`OutOfMemoryError`)。 - 系统性能下降,甚至崩溃。 #### 二、并发理论 **Java内存模型** - **...

Global site tag (gtag.js) - Google Analytics