获取崩溃时的调用栈和生成dump文件,然后自动重启
首先要说明的是:
1. linux 获取调用栈
- #include <execinfo.h> //在头文件"execinfo.h"中声明了三个函数用于获取当前线程的函数调用堆栈
- #include <fcntl.h>
- #include <sys/resource.h>
- #include <signal.h>
- static int _core_dump_signals[] = {
- SIGABRT, SIGFPE, SIGILL, SIGQUIT, SIGSEGV,
- SIGTRAP, SIGSYS, SIGBUS, SIGXCPU, SIGXFSZ
- #ifdef SIGEMT
- ,SIGEMT
- #endif
- };
- //安装崩溃时//打印当前线程的函数调用堆栈
- void installTrace()
- {
- struct sigaction act;
- size_t i;
- memset(&act, , sizeof(act));
- act.sa_handler = &CLog::LogTrace;
- sigfillset(&act.sa_mask);
- for (i = ; i < (sizeof(_core_dump_signals) / sizeof((_core_dump_signals)[])); i++)
- sigaction(_core_dump_signals[i], &act, NULL);
- /* unblock all the signals, because if the current process is
- * spawned in the previous signal handler, all the signals are
- * blocked. In order to make it sense of signals, we should
- * unblock them. Certainly, you should call this function as
- * early as possible. :) */
- sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL);
- //sigemptyset(&myAction.sa_mask);
- //myAction.sa_flags = SA_RESTART | SA_SIGINFO;
- //LOG(LOGLV_WARN, "Log::installTrace!!!\n");
- }
- //#include <sys/wait.h>
- ////等待fok的子进程信号,防止僵尸进程
- //void fok_chld_wait(int signo) {
- // pid_t pid;
- // int stat;
- // while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) {
- // printf("child %d exit\n", pid);
- // }
- // return;
- //}
- ////设置等待fok的子进程信号
- //int set_fok_chld_wait_signal() {
- // struct sigaction act, oact;
- // act.sa_handler = fok_chld_wait;
- // sigemptyset(&act.sa_mask);
- // act.sa_flags = 0;
- //
- // if (sigaction(SIGCHLD, &act, &oact) < 0) {
- // return -1;
- // }
- // return 0;
- //}
- //重新启动进程
- static void _restart(void)
- {
- char buf[];
- char exe[];
- char **argv;
- int fd, len;
- size_t argv_size, i;
- char *ptr, *ptr_end;
- struct rlimit limit;
- /* find the file executable. */
- len = readlink("/proc/self/exe", exe, sizeof(exe) - );
- if (len == - || len == sizeof(exe) - )
- _exit(EXIT_FAILURE);
- exe[len] = '\0';
- /* generate the variable argv. */
- fd = open("/proc/self/cmdline", O_RDONLY);
- if (fd == -)
- _exit(EXIT_FAILURE);
- len = read(fd, buf, sizeof(buf));
- if (len == - || len == sizeof(buf))
- _exit(EXIT_FAILURE);
- buf[len] = '\0';
- argv_size = ;
- argv = (char**)malloc(sizeof(char*) * argv_size);
- if (argv == NULL)
- _exit(EXIT_FAILURE);
- for (i = , ptr = buf, ptr_end = buf + len;
- ptr < ptr_end; i++, ptr += strlen(ptr) + ) {
- if (i >= argv_size - ) {
- argv_size <<= ;
- argv = (char**)realloc(argv, sizeof(char*) * argv_size);
- if (argv == NULL)
- _exit(EXIT_FAILURE);
- }
- argv[i] = ptr;
- }
- argv[i] = NULL;
- /* close all the file descriptors except of stdin/stdout/stderr. */
- getrlimit(RLIMIT_NOFILE, &limit);
- for (i = ; i < limit.rlim_cur; i++)
- close(i);
- execvp(exe, argv);
- /* exit if it fails to restart self. */
- _exit(EXIT_FAILURE);
- }
- //打印当前线程的函数调用堆栈
- void LogTrace(int signo)
- {
- //set_fok_chld_wait_signal();
- //父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,
- //那么子进程结束后,内核会回收, 并不再给父进程发送信号。
- //或用sigaction函数为SIGCHLD设置SA_NOCLDWAIT,这样子进程结束后,就不会进入僵死状态
- struct sigaction sa;
- sa.sa_handler = SIG_IGN;
- sa.sa_flags = SA_NOCLDWAIT;
- sigemptyset(&sa.sa_mask);
- sigaction(SIGCHLD, &sa, NULL);
- void *callstacks[];
- if (!_pLogFile)
- Log.ChangeFile();
- if (_pLogFile)
- {
- std::lock_guard<std::mutex> lock{ _csLog };
- struct timeval tv;
- struct tm *p;
- gettimeofday(&tv, NULL);
- p = localtime(&tv.tv_sec);
- size_t size = sizeof(callstacks);
- int fd = fileno(_pLogFile);
- fprintf(_pLogFile, "-----------------------------------0 SIG=%d-%s err=%d-%s tid=%d %d-%02d-%02d %02d:%02d:%02d.%06d\n"
- , signo, strsignal(signo), errno, strerror(errno), gettid(), p->tm_year + , p->tm_mon + , p->tm_mday, p->tm_hour, p->tm_min, (int)p->tm_sec, (int)tv.tv_usec );
- fflush(_pLogFile);
- size = backtrace(callstacks, size);
- backtrace_symbols_fd(callstacks, size, fd);
- fprintf(_pLogFile, "-----------------------------------1 callstack=20/%d\n", (int)size);
- fflush(_pLogFile);
- //定位源代码行
- char cmd[] = "addr2line -f -e ";
- char buff1[] = { }, buff2[] = { }, buff3[] = { };
- char* prog = cmd + ;
- readlink("/proc/self/exe", prog, );// 获取进程的完整路径
- int leftlen = strlen(cmd);
- prog = cmd + leftlen;
- leftlen = - leftlen;
- for (size_t i = ; i < size; ++i)
- {
- snprintf(prog, leftlen, " %p\n", callstacks[i]);
- FILE* fp = popen(cmd, "r");
- if (fp != NULL)
- {
- if (NULL != fgets(buff1, , fp))
- {
- fgets(buff2, , fp);
- if (buff2[strlen(buff2) - ] == '\n')
- buff2[strlen(buff2) - ] = ;
- snprintf(buff3, , "c++filt %s\n", buff1);//用c++filt 使函数名可视化
- FILE* fp2 = popen(buff3, "r");
- if (fp2 && fgets(buff3, , fp2)) {
- fprintf(_pLogFile, ">%s %s", buff2, buff3);
- pclose(fp2);
- }
- else
- fprintf(_pLogFile, ">%s %s", buff2, buff1);
- }
- pclose(fp);
- }
- }
- fprintf(_pLogFile, "-----------------------------------2 end\n");
- fflush(_pLogFile);
- }
- //core dump
- pid_t pid = fork();
- if (pid == ) {
- #ifdef _FORCE_CORE_DUMP
- #ifndef _CORE_SIZE
- #define _CORE_SIZE (256 * 1024 * 1024)
- #endif /* _CORE_SIZE */
- struct rlimit limit = {
- .rlim_cur = _CORE_SIZE,
- .rlim_max = _CORE_SIZE };
- setrlimit(RLIMIT_CORE, &limit);
- #endif /* _FORCE_CORE_DUMP */
- /* reset the signal handler to default handler,
- * then raise the corresponding signal. */
- signal(signo, SIG_DFL);
- raise(signo);
- _exit(EXIT_FAILURE);
- }
- else
- _restart();//自动重启
- }
- /* const char* sigstr[] = {
- "01 SIGHUP 挂起(hangup)",
- "02 SIGINT 中断,当用户从键盘按^c键或^break键时",
- "03 SIGQUIT 退出,当用户从键盘按quit键时",
- "04 SIGILL 非法指令",
- "05 SIGTRAP 跟踪陷阱(trace trap),启动进程,跟踪代码的执行",
- "06 SIGIOT IOT指令",
- "07 SIGEMT EMT指令",
- "08 SIGFPE 浮点运算溢出",
- "09 SIGKILL 杀死、终止进程 ",
- "10 SIGBUS 总线错误",
- "11 SIGSEGV 段违例(segmentation violation),进程试图去访问其虚地址空间以外的位置",
- "12 SIGSYS 系统调用中参数错,如系统调用号非法",
- "13 SIGPIPE 向某个非读管道中写入数据",
- "14 SIGALRM 闹钟。当某进程希望在某时间后接收信号时发此信号",
- "15 SIGTERM 软件终止(software termination)",
- "16 SIGUSR1 用户自定义信号1",
- "17 SIGUSR2 用户自定义信号2",
- "18 SIGCLD 某个子进程死",
- "19 SIGPWR 电源故障"
- };*/
- //设置线程优先级(设置为普通优先级)
- //参数为线程句柄,或 std::thread::native_handle()
- void SetThrPriorityNormal(void* handle)
- {
- sched_param sch;
- int policy, policy2;
- pthread_getschedparam(handle, &policy, &sch);
- sch.sched_priority = ;
- if (pthread_setschedparam(handle, SCHED_FIFO, &sch))
- LOG(LOGLV_NOTICE, "Failed to setschedparam normal: %s \n", std::strerror(errno));
- pthread_getschedparam(handle, &policy2, &sch);
- LOG(LOGLV_NOTICE, "ThreadPriority %d -> %d\n", policy, policy2);
- }
- //设置线程优先级(设置为高(HIGHEST)优先级)
- //参数为线程句柄,或 std::thread::native_handle()
- void SetThrPriorityHighst(void* handle)
- {
- sched_param sch;
- int policy, policy2;
- pthread_getschedparam(handle, &policy, &sch);
- sch.sched_priority = -;
- if (pthread_setschedparam(handle, SCHED_FIFO, &sch))
- LOG(LOGLV_NOTICE, "Failed to setschedparam normal: %s \n", std::strerror(errno));
- pthread_getschedparam(handle, &policy2, &sch);
- LOG(LOGLV_NOTICE, "ThreadPriority %d -> %d\n", policy, policy2);
- }
这些也是网上搜别人的代码,然后自己修改了的,可以直接运。
编译时,要加参数 -g 。或者加 -g3 -ggdb -gstabs。
2. win获取崩溃类型和生成dump文件
- //Dump调试
- #include <DbgHelp.h>
- #include <shellapi.h>
- typedef BOOL(*MINIDUMPWRITEDUMP)(HANDLE hProcess,
- DWORD ProcessId,
- HANDLE hFile,
- MINIDUMP_TYPE DumpType,
- PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
- PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
- PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
- MINIDUMPWRITEDUMP pDumpFunc = NULL; // 声明函数指针
- const char* seh_filer(DWORD code)
- {
- switch (code)
- {
- case EXCEPTION_ACCESS_VIOLATION:
- return ("存储保护异常(解空指针)");
- case EXCEPTION_DATATYPE_MISALIGNMENT:
- return ("数据类型未对齐异常");
- case EXCEPTION_BREAKPOINT:
- return ("中断异常");
- case EXCEPTION_SINGLE_STEP:
- return ("单步中断异常");
- case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- return ("数组越界异常");
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- case EXCEPTION_FLT_INEXACT_RESULT:
- case EXCEPTION_FLT_INVALID_OPERATION:
- case EXCEPTION_FLT_OVERFLOW:
- case EXCEPTION_FLT_STACK_CHECK:
- case EXCEPTION_FLT_UNDERFLOW:
- return ("浮点数计算异常");
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- return ("被0除异常");
- case EXCEPTION_INT_OVERFLOW:
- return ("数据溢出异常");
- case EXCEPTION_IN_PAGE_ERROR:
- return ("页错误异常");
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- return ("非法指令异常");
- case EXCEPTION_STACK_OVERFLOW:
- return ("堆栈溢出异常");
- case EXCEPTION_INVALID_HANDLE:
- return ("无效句柄异常");
- default:
- if (code & ( << ))
- return ("用户自定义的软件异常");
- else
- return ("其它异常");
- }
- }
- // 参数lpExceptionInfo包含了异常信息,由系统提供
- LONG WINAPI ExceptionFilterFunc(struct _EXCEPTION_POINTERS* lpExceptionInfo)
- {
- //if(pDumpFunc==NULL) return -1;
- LONG ret = EXCEPTION_CONTINUE_SEARCH;
- // 根据当前线程ID,时间创建dmp文件
- int irand = rand() % ;
- char strFile[];
- SYSTEMTIME st;
- DWORD ul = lpExceptionInfo->ExceptionRecord->ExceptionCode;
- LOG(LOGLV_CRIT, "exception %X,%s\n", ul, seh_filer(ul));
- GetLocalTime(&st);
- ::CreateDirectory("dumps\\", NULL);
- _snprintf_s(strFile, , "dumps\\DMP-%d_%04d%02d%02d_%02d%02d%02d.%03d_%04d.dmp", ::GetCurrentThreadId(), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, irand);
- HANDLE hFile = ::CreateFile(strFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile != INVALID_HANDLE_VALUE)
- {
- MINIDUMP_EXCEPTION_INFORMATION ExInfo;
- ExInfo.ThreadId = ::GetCurrentThreadId();
- ExInfo.ExceptionPointers = lpExceptionInfo;
- ExInfo.ClientPointers = NULL;
- MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(//MiniDumpWithFullMemory |
- MiniDumpWithHandleData | MiniDumpFilterModulePaths |
- MiniDumpWithProcessThreadData |
- MiniDumpWithIndirectlyReferencedMemory |
- MiniDumpWithPrivateReadWriteMemory |
- MiniDumpWithFullMemoryInfo |
- MiniDumpWithUnloadedModules |
- //MiniDumpWithDataSegs |
- MiniDumpWithThreadInfo );
- //加载DebugDump函数 //MiniDumpWriteDump 函数在头文件(DbgHelp.h)中有定义
- HMODULE hDll = LoadLibrary("dbghelp.dll");
- if (hDll == NULL)
- LOG(LOGLV_ALERT, "Error: load dbghelp.dll fail\n\n");
- else
- {
- //load MiniDumpWriteDump function
- pDumpFunc = (MINIDUMPWRITEDUMP)::GetProcAddress(hDll, "MiniDumpWriteDump");
- if (pDumpFunc == NULL)
- LOG(LOGLV_ALERT, "Error: load MiniDumpWriteDump function fail\n\n");
- else {
- //将崩溃信息记录到dmp文件中
- BOOL bRet = pDumpFunc(GetCurrentProcess(), GetCurrentProcessId(), hFile, mdt, &ExInfo, NULL, NULL);
- if (bRet) {
- ret = EXCEPTION_EXECUTE_HANDLER;
- LOG(LOGLV_WARN, "DumpFile: %s\n", strFile);
- }
- else
- LOG(LOGLV_CRIT, "call MiniDumpWriteDump fail...\n");
- }
- //卸载 dbghelp.dll
- if (hDll != NULL)
- FreeLibrary(hDll);
- }
- ::CloseHandle(hFile);
- }
- else
- LOG(LOGLV_CRIT, "CreateFile fail... %s\n", strFile);
- char *fullpth;
- _get_pgmptr(&fullpth);
- char* cmdl = strstr(GetCommandLine(), ".exe ");
- ShellExecute(NULL, "open", fullpth, (cmdl ? (cmdl + ) : nullptr), Log.CurPath(), SW_SHOW);
- return ret;
- }
- //安装崩溃时//打印当前线程的函数调用堆栈
- //该流程只对本线程有效,如果是多线程,需要对每个线程都做调用处理。
- void installTrace() {
- // 设置异常捕获函数
- ::SetUnhandledExceptionFilter(ExceptionFilterFunc);
- }
- //设置线程优先级(设置为普通优先级)
- ////如果进程的优先级为最高,则降低2级
- //参数为线程句柄,或 std::thread::native_handle()
- void SetThrPriorityNormal(void* handle)
- {
- int r0 = GetThreadPriority(handle);
- int r = ;
- //int p = GetPriorityClass(GetCurrentProcess());
- //if (p > 100)//如果进程的优先级为最高,则降低2级
- // r = -2;
- int r1 = SetThreadPriority(handle, r);
- r1 = GetThreadPriority(handle);
- LOG(LOGLV_NOTICE, "ThreadPriority %d -> %d\n", r0, r1);
- }
- //设置线程优先级(设置为高(HIGHEST)优先级)
- //参数为线程句柄,或 std::thread::native_handle()
- void SetThrPriorityHighst(void* handle)
- {
- int r0 = GetThreadPriority(handle);
- int r1 = SetThreadPriority(handle, THREAD_PRIORITY_HIGHEST);
- r1 = GetThreadPriority(handle);
- LOG(LOGLV_NOTICE, "ThreadPriority %d -> %d\n", r0, r1);
- }
网上搜索,说是 win有办法可以获取崩溃的函数和类名,但是比较复杂,就没有搞了。
获取崩溃时的调用栈和生成dump文件,然后自动重启的更多相关文章
- [转]让程序在崩溃时体面的退出之SEH+Dump文件
原文地址:http://blog.csdn.net/starlee/article/details/6649605 在我上篇文章<让程序在崩溃时体面的退出之SEH>中讲解了SEH中try/ ...
- 如何设置C++崩溃时生成Dump文件
Dump 文件是进程的内存镜像 , 可以把程序的执行状态通过调试器保存到dump文件中 ; Dump 文件是用来给驱动程序编写人员调试驱动程序用的 , 这种文件必须用专用工具软件打开 , 比如使用 W ...
- JVM在遇到OOM(OutOfMemoryError)时生成Dump文件
方法一: 命令:jmap -dump:format=b,file=heap.bin file:保存路径及文件名pid:进程编号(windows通过任务管理器查看,linux通过ps aux查看) du ...
- 程序自动生成Dump文件
前言:通过drwtsn32.NTSD.CDB等调试工具生成Dump文件, drwtsn32存在的缺点虽然NTSD.CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD.CDB等调试工具.了解了 ...
- 程序自动生成Dump文件()
前言:通过drwtsn32.NTSD.CDB等调试工具生成Dump文件, drwtsn32存在的缺点虽然NTSD.CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD.CDB等调试工具.了解了 ...
- 调试SQLSERVER (一)生成dump文件的方法
调试SQLSERVER (一)生成dump文件的方法 调试SQLSERVER (二)使用Windbg调试SQLSERVER的环境设置调试SQLSERVER (三)使用Windbg调试SQLSERVER ...
- 使用dbghelp生成dump文件以及事后调试分析
前言 在产品的实际应用环境中,如果我们的程序在客户那里出现了问题,例如程序异常了,而这个时候的现象又不能还原或者很难还原重现,那么只有使用dump文件来保存程序的当前运行信息,例如调用堆栈等,同时使用 ...
- 如何生成Dump文件
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:如何生成Dump文件.
- 使用ProcDump自动生成Dump文件
ProcDump工具来自Sysinternals Suite 最近用来自动产生Dump文件 一是用来监视服务器程序无响应 procdump -accepteula -64 -ma -h server. ...
随机推荐
- css animation动画
css 动画: 动画是CSS3中具有颠覆性的特征之一,可通过设置多个节点来精确控制一个或一组动画,常用来实现复杂的动画效果. 必要元素: a.通过@keyframes指定动画序列:自动补间动画,确定两 ...
- Ambari HDP集群搭建文档
一.配置主机和节点机器之间SSH无密登录 多台外网服务器配置时,需要在/etc/hosts中把本机的IP地址设置为内网IP地址 http://2d67df38.wiz02.com/share/s/0J ...
- WPF 使用MahApps.Metro UI库
在WPF中要想使用Metro风格是很简单的,可以自己画嘛.. 但是为了节省时间,哈,今天给大家推荐一款国外Metro风格的控件库. 本文只起到抛砖引玉的作用,有兴趣还是推荐大家上官网,Thanks,官 ...
- Jitsi 开源视频会议远程桌面共享&&文档共享工具
1. 特点 主要功能特点: 支持网络视频会议,使用SFU模式实现视频路由器功能. 支持SIP帐号注册电话呼叫. 支持安卓苹果终端. 支持文档共享功能,即时消息功能. 支持中文界面. 支持会议邀请,密码 ...
- warning: backslash and newline separated by space [enabled by default]
警告:反斜杠和换行符之间多了空格. 这种问题出现在宏定义 #define,并且有多行,每行之间要用 “\” 连接起来. 解决办法:删除 “\” 后面的空格,直接紧跟回车.
- ThinkPHP 分页功能梳理
最近在开发一个项目,使用了国内流行的ThinkPHP框架,我之前没怎么用过这个框架,也是临时抱佛脚,用的不怎么样?可能理解不是很深刻,如果有说的不对或不正确的地方,请大家多包涵,多指教. ThinkP ...
- 配置Jar包及相关依赖Jar包的本地存放路径
配置Jar包及相关依赖Jar包的本地存放路径 用 maven2 ,pom.xml中设置了依赖,会帮你下载所有依赖的.jar到 M2_REPO 指向的目录. M2_REPO是一个用来定义 maven 2 ...
- FPGA的CNN加速,你怎么看?
网上对于FPGACNN加速的研究已经很多了,神经网络的硬件加速似乎已经满大街都是了,这里我们暂且不讨论谁做的好谁做的不好,我们只是根据许许多多的经验来总结一下实现硬件加速,需要哪些知识,考虑哪些因素. ...
- Firewalld防火墙与ICMP攻击
原文地址:http://www.excelib.com/article/293/show 提到ICMP大家应该都很熟悉,可能有人会说:不就是ping吗?但是说到ICMP攻击以及相关防御措施可能就有的人 ...
- python 面向对象(其他相关)
python 面向对象(其他相关): (思维导图 ↑↑↑↑↑↑) 一.issubclass(obj,cls) 检查obj是否是类cls的对象 class Base(object): pass c ...