【C/C++】软件异常状态快速定位技巧

前言

在软件开发维护过程中,开发人员难免会遇到软件发版或者上线后出现异常,且通过日志无法分析出造成异常具体原因;也许是程序出现死锁导致运行阻塞,也许是程序出现内存出现异常导致软件崩溃,也许这个问题是偶现难以找到快速复现手段。当你无法通过Debug调试时,你需要掌握抓取程序运行过程中和程序奔溃时的程序运行快照技巧,便于开发人员定位问题。

本文主要介绍在Window和Linux平台上定位软件异常状态的技巧。

WinDbg工具下载地址:https://docs.microsoft.com/zh-cn/windows-hardware/drivers/debugger/debugger-download-tools

Window PC软件崩溃位置定位

在程序中嵌入dump文件生成对象,用于捕捉崩溃时刻软件运行状态。

dump.h

#pragma once
#include <Windows.h>
namespace dump
{
	class Dump
	{
	public:
		Dump();
		~Dump();

	private:
		static long __stdcall UnhandleExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo);
	};
}

dump.cpp

#include <Windows.h>
#include <ratio>   
#include <chrono>
#include <ctime>
#include <sstream>
#include <DbgHelp.h>
#include "dump.h"
#pragma comment(lib,  "dbghelp.lib")

namespace dump
{
	Dump::Dump()
	{
		/* 设置程序崩溃前的回调函数 */
		SetUnhandledExceptionFilter(UnhandleExceptionFilter);
	}
	Dump::~Dump() {}

	long __stdcall Dump::UnhandleExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo)
	{

		auto tp = std::chrono::system_clock::now(); 
		std::time_t curTime = std::chrono::system_clock::to_time_t(tp);  
		std::stringstream fileName;
		fileName  << curTime << ".dmp"; // 崩溃生成的dump文件名为[时间戳].dmp 
		
		/* 创建dump文件 */
		HANDLE hFile = CreateFile(fileName.str().c_str(), 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 = ExceptionInfo; // 指向EXCEPTION_POINTERS结构的指针,该 结构指定异常的计算机独立描述和异常时的处理器上下文。
			exInfo.ClientPointers = FALSE; // 如果在调试过程中则设置为TRUE,否则是FALSE
			
			/* 写Dump文件 */
			BOOL  ret = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &exInfo, NULL, NULL);
			CloseHandle(hFile);
			if (!ret)
			{
				/* 写dump文件出错处理,异常交给windows处理 */
				system("pause");
				return EXCEPTION_CONTINUE_SEARCH;
			}
			else
			{    /* 表示该异常已经被处理 */
				system("pause");
				return EXCEPTION_EXECUTE_HANDLER;
			}
		}
		else
		{
			/* 写dump文件出错处理,异常交给windows处理 */
			system("pause");
			return EXCEPTION_CONTINUE_SEARCH;
		}
	}
}



使用示例

main.cpp

#include "dump.h"

void run_test()
{
	int *a = nullptr;
	*a = 3;  // 崩溃点
}

int main()
{
	auto dmp = dump::Dump();
	run_test();
	return 0;
}

如果开发人员想要精准定位崩溃上下文,则可以开启以下配置:

以 VS2017为例,工程属性中【调试信息格式】选择为【程序数据库】,【生成调试信息】选择为【生成调试信息】。

程序运行后生成dmp文件

使用WinDbg工具加载dmp文件,使用【!analyze -v】命令查看崩溃信息

如下图所示在STATCK_TEXT堆栈信息上可以看到奔溃点为run_test函数

如果在工程属性上增加调试信息,如下图所示在FAULTING_SOURCE_CODE故障源码信息上可以看到具体奔溃点的上下文代码

Linux 程序崩溃位置定位

在程序中嵌入dump文件生成对象,用于捕捉崩溃时刻软件运行状态。

dump.h

#pragma once

int set_dump();

dump.cpp

#include<stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "dump.h"

#define CORE_SIZE   (1024 * 1024 * 500)

int set_dump()
{
	/* 设置进程资源限制 */
	struct rlimit rlmt;
	rlmt.rlim_cur = (rlim_t)CORE_SIZE;
	rlmt.rlim_max  = (rlim_t)CORE_SIZE;
	return setrlimit(RLIMIT_CORE, &rlmt);	
}

使用示例

main.cpp

#include <stdio.h>
#include "dump.h"

void run_test()
{
	int *a = nullptr;
	*a = 3;  // 崩溃点
}

int main()
{
	set_dump();
	run_test();
	return 0;
}

编译选项需要加-g

程序运行后生成core文件

使用gdb工具调试,输入命令【gdb test2 core】,可以查看程序堆栈信息和崩溃语句

 

 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值