debug:win和linux都通过,linx下Release暂时没有有效内容

This commit is contained in:
taynpg 2025-04-16 15:25:35 +08:00
commit b4de9d6c1c
11 changed files with 5246 additions and 0 deletions

17
.clang-format Normal file
View File

@ -0,0 +1,17 @@
BasedOnStyle: LLVM
IndentWidth: 4
PointerAlignment: Left
AccessModifierOffset: -4
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: true
AfterClass: true
Cpp11BracedListStyle: true
ReflowComments: true
SpacesBeforeTrailingComments: 3
TabWidth: 4
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ColumnLimit: 120
AllowShortBlocksOnASingleLine: Never
AllowShortFunctionsOnASingleLine: None
AllowShortEnumsOnASingleLine: false

45
.gitignore vendored Normal file
View File

@ -0,0 +1,45 @@
# Prerequisites
*.d
.idea
cmake-build-*
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
!lebo_motor.lib
!lebo_motor.dll
!liblebo_motor.so
# Executables
*.exe
*.out
*.app
build
*.user
compile_commands.json
.vs
out
.cache
CMakeLists.txt.*

103
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,103 @@
{
"files.autoSave": "onFocusChange",
"editor.fontSize": 14,
"editor.fontFamily": "'Monaspace Krypton Light', 'Monaspace Krypton Light', 'Monaspace Krypton Light'",
"terminal.integrated.fontFamily": "Monaspace Krypton Light",
"cmake.configureOnOpen": true,
"cmake.debugConfig": {
"console": "integratedTerminal",
"setupCommands": [
{
"description": "-gdb-set charset utf-8",
"text": "-gdb-set charset UTF-8"
},
{
"description": "Enable gdb pretty-printing",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
//"visualizerFile": "${workspaceRoot}/.vscode/qt6.natvis",
"args": [
]
},
// "cmake.configureSettings": {
// "CMAKE_TOOLCHAIN_FILE": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
// },
"cmake.options.statusBarVisibility": "visible",
"cmake.generator": "Ninja",
"C_Cpp.default.compileCommands": "${workspaceRoot}/build/compile_commands.json",
"C_Cpp.default.cppStandard": "c++17",
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"editor.inlayHints.enabled": "off",
"editor.unicodeHighlight.allowedLocales": {
"ja": true,
"zh-hant": true,
"zh-hans": true
},
"files.associations": {
"ostream": "cpp",
"algorithm": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"cmath": "cpp",
"condition_variable": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"exception": "cpp",
"fstream": "cpp",
"functional": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"iterator": "cpp",
"limits": "cpp",
"list": "cpp",
"map": "cpp",
"memory": "cpp",
"mutex": "cpp",
"new": "cpp",
"ratio": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"string": "cpp",
"system_error": "cpp",
"thread": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"unordered_map": "cpp",
"utility": "cpp",
"vector": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocinfo": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xmemory0": "cpp",
"xstddef": "cpp",
"xstring": "cpp",
"xtr1common": "cpp",
"xtree": "cpp",
"xutility": "cpp",
"filesystem": "cpp",
"locale": "cpp",
"string_view": "cpp",
"xthread": "cpp",
"xlocbuf": "cpp",
"xlocmes": "cpp"
}
}

19
CMakeLists.txt Normal file
View File

@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.16)
project(crashelper LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if (MSVC)
add_compile_options(/source-charset:utf-8)
endif()
set(CMAKE_DEBUG_POSTFIX "d")
message(STATUS "System: ${CMAKE_SYSTEM_NAME}")
message(STATUS "Compiler CXX ID: ${CMAKE_CXX_COMPILER_ID}")
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}/)
add_subdirectory(crashelper)
add_subdirectory(test)

50
README.md Normal file
View File

@ -0,0 +1,50 @@
# crashelper
## 1. 介绍
crashelper是一个用于帮助开发人员快速定位crash的辅助工具,`Windows`下暂时仅支持`MSVC`编译器。
用到了仅头文件项目 `=>` [backward-cpp](https://github.com/bombela/backward-cpp),`crashelper`已包含`backward-cpp`项目中的头文件。
`crashelper``backward-cpp`源码加了部分接口用于配置具体的日志保存路径,不能直接拿原项目头文件`backward.hpp`进行更新替换。
# 2. 设计思路
## 2.1. Debug模式
### 2.1.1 Windows
在Windows下的此模式,`crashelper`会仅保存崩溃时的调用栈信息,并将日志信息保存到设定的目录下。
### 2.1.2 Linux
在Linux下的此模式,`crashelper`会仅保存崩溃时的调用栈信息,并将日志信息保存到设定的目录下。
`Linux`下依赖`binutils`库。
```shell
# Ubuntu/Debian
sudo apt-get install binutils-dev
# REHL/CentOS/Fedora
sudo yum install binutils-devel
# openSUSE/SUSE
sudo zypper install binutils-devel
# Arch Linux/Manjaro
sudo pacman -S binutils-devel/binutils-libs
# Alpine
sudo apk add binutils-dev
```
二进制的下载链接:[pkgs.org](https://pkgs.org/)
其中`binutils`部分:
### 2.1.3 MacOS
待补充。
## 2.2. Release模式
### 2.2.1 Windows
在Windows下的此模式,程序编译结果会额外产生`pdb`调试符号文件(此为额外的产生,不影响可执行程序的`Release`性,即不会影响代码优化和运行时性能),请妥善保存好此`pdb`文件,用于后续配合`dump`文件分析异常。程序运行时,`crashelper`会保存崩溃时的`dump`文件到设定的目录下。

27
crashelper/CMakeLists.txt Normal file
View File

@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.16)
project(crashelper LANGUAGES CXX)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
message(FATAL_ERROR "Unsupported MinGW Currently.")
endif()
set(CRASHELPER_SOURCES
src/crashelper.cxx
)
include_directories(include)
add_library(crashelper STATIC ${CRASHELPER_SOURCES})
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(crashelper PUBLIC pthread dl bfd)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_link_libraries(crashelper PRIVATE DbgHelp)
target_compile_options(crashelper PUBLIC $<$<OR:$<STREQUAL:$<CXX_COMPILER_ID>,MSVC>,$<STREQUAL:$<C_COMPILER_ID>,MSVC>>:/Zi>)
target_link_options(crashelper PUBLIC $<$<OR:$<STREQUAL:$<CXX_COMPILER_ID>,MSVC>,$<STREQUAL:$<C_COMPILER_ID>,MSVC>>:/DEBUG>)
else()
message(FATAL_ERROR "Unsupported OS: ${CMAKE_SYSTEM_NAME}. This project only supports Linux, macOS, and Windows.")
endif()
target_include_directories(crashelper PUBLIC include)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,61 @@
#ifndef CRASHELPER_H
#define CRASHELPER_H
#if defined(_WIN32) || defined(_WIN64)
#define WIN_OS
#include <windows.h>
#if defined(min)
#undef min
#endif
#elif defined(__APPLE__) && defined(__MACH__)
#define MAC_OS
#elif defined(__linux__)
#define LINUX_OS
#define BACKWARD_HAS_BFD 1
#else
#error "Unsupported OS"
#endif
#include "backward.hpp"
#include <string>
#ifdef USE_BOOST
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#else
#include <filesystem>
namespace fs = std::filesystem;
#endif
namespace backward {
///
/// @brief 设置dump文件的保存目录,不设置默认当前目录。
/// @param path 若不存在则创建,创建失败返回false
///
bool SetDumpFileSavePath(const std::string& path);
///
/// @brief 设置dump日志文件的保存目录,不设置默认当前目录。
/// @param path 若不存在则创建,创建失败返回false
///
bool SetDumpLogSavePath(const std::string& path);
std::string GetCurFullLogPath();
#if defined(WIN_OS)
void UseExceptionHandler(EXCEPTION_POINTERS* exception);
#endif
} // namespace backward
#ifdef WIN_OS
#define CRASHELPER_MARK_ENTRY() \
backward::SignalHandling sh; \
sh.register_crash_use_handler([](EXCEPTION_POINTERS* exception) { UseExceptionHandler(exception); }); \
sh.register_crash_path([]() -> std::string { return GetCurFullLogPath(); })
#elif defined(MAC_OS)
#elif defined(LINUX_OS)
#define CRASHELPER_MARK_ENTRY() \
backward::SignalHandling sh; \
sh.register_crash_path([]() -> std::string { return GetCurFullLogPath(); })
#endif
#endif // CRASHELPER_H

View File

@ -0,0 +1,178 @@
#include "crashelper.h"
#include <fstream>
#include <string>
namespace backward {
class crashHelper
{
public:
static crashHelper& getInstance()
{
static crashHelper instance;
return instance;
}
public:
static bool createDir(const std::string& path);
static std::string getCurrentTime();
static std::string getBinName();
static std::string toFull(const std::string& path);
public:
std::string dumpSavePath_;
std::string dumpLogSavePath_;
private:
crashHelper() = default;
~crashHelper() = default;
};
bool crashHelper::createDir(const std::string& path)
{
std::error_code ec;
fs::path dir(path);
if (fs::exists(dir, ec)) {
if (!fs::is_directory(dir, ec)) {
return false;
}
return true;
}
bool created = fs::create_directories(dir, ec);
if (ec || !created) {
return false;
}
return true;
}
std::string crashHelper::getCurrentTime()
{
auto now = std::chrono::system_clock::now();
auto now_time_t = std::chrono::system_clock::to_time_t(now);
auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
// 转换为本地时间(或 UTC 时间)
std::tm now_tm = *std::localtime(&now_time_t); // 本地时间
// std::tm now_tm = *std::gmtime(&now_time_t); // UTC 时间
std::ostringstream oss;
oss << std::put_time(&now_tm, "%Y%m%d-%H%M%S") << "-" << std::setfill('0') << std::setw(3) << now_ms.count();
return oss.str();
}
std::string crashHelper::getBinName()
{
fs::path exe_path;
#ifdef WIN_OS
char path[MAX_PATH] = {0};
GetModuleFileName(nullptr, path, MAX_PATH);
exe_path = fs::path(path);
#elif defined(MAC_OS)
char path[4096];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0) {
exe_path = fs::canonical(fs::path(path));
}
#elif defined(LINUX_OS)
char path[4096];
ssize_t count = readlink("/proc/self/exe", path, sizeof(path));
if (count != -1) {
path[count] = '\0';
exe_path = fs::path(path);
}
#endif
if (!exe_path.empty()) {
return exe_path.stem().string(); // stem() 移除扩展名
}
return "";
}
std::string crashHelper::toFull(const std::string& path)
{
fs::path base;
if (fs::path(path).is_relative()) {
base = fs::current_path();
base.append(path);
} else {
base = fs::path(path);
}
auto r = fs::absolute(base);
return r.string();
}
bool SetDumpFileSavePath(const std::string& path)
{
auto& h = crashHelper::getInstance();
if (!h.createDir(path)) {
return false;
}
h.dumpSavePath_ = path;
return true;
}
bool SetDumpLogSavePath(const std::string& path)
{
auto& h = crashHelper::getInstance();
if (!h.createDir(path)) {
return false;
}
h.dumpLogSavePath_ = path;
return true;
}
std::string GetCurFullLogPath()
{
auto gf = []() {
auto& h = crashHelper::getInstance();
auto dumpName = h.getCurrentTime() + "-" + h.getBinName() + ".log";
auto lp = crashHelper::toFull(h.dumpLogSavePath_);
auto full = fs::path(lp).append(dumpName).string();
return full;
};
#if defined(WIN_OS)
#if !defined(NDEBUG) || defined(_DEBUG) || defined(DEBUG)
return gf();
#else
return "";
#endif
#else
return gf();
#endif
}
#if defined(WIN_OS)
void UseExceptionHandler(EXCEPTION_POINTERS* exception)
{
auto& h = crashHelper::getInstance();
#if !defined(NDEBUG) || defined(_DEBUG) || defined(DEBUG)
#else
// Release 模式, 输出 dump 结果到文件
auto dumpBase = h.getCurrentTime() + "-" + h.getBinName();
auto dumpName = h.getCurrentTime() + "-" + h.getBinName() + ".windump";
auto dumpFailedLog = h.getCurrentTime() + "-" + h.getBinName() + ".dumpfailed.log";
auto lp = crashHelper::toFull(h.dumpSavePath_);
auto full = fs::path(lp).append(dumpName).string();
auto full_failed = fs::path(lp).append(dumpFailedLog).string();
HANDLE hFile = CreateFile(full.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
std::ofstream fs(full_failed);
fs << "Create dump file failed.\n";
fs << "File: " << full << "\n";
fs << "Error code: " << GetLastError() << "\n";
return;
};
MINIDUMP_EXCEPTION_INFORMATION info;
info.ThreadId = GetCurrentThreadId();
info.ExceptionPointers = exception;
info.ClientPointers = TRUE;
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &info, NULL, NULL);
CloseHandle(hFile);
#endif
}
#endif
} // namespace backward

5
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.16)
project(crashelper-test LANGUAGES CXX)
add_executable(crashelper-test main.cxx)
target_link_libraries(crashelper-test crashelper)

31
test/main.cxx Normal file
View File

@ -0,0 +1,31 @@
#include <crashelper.h>
#include <iostream>
#include <thread>
using namespace backward;
void th_sim()
{
std::this_thread::sleep_for(std::chrono::seconds(2));
// throw "Erro Auto";
int* p = nullptr;
*p = 33;
}
int main()
{
#ifdef _WIN32
SetDumpFileSavePath("D:\\dump");
SetDumpLogSavePath("D:\\dump");
#else
SetDumpFileSavePath("~/dump");
SetDumpLogSavePath("~/dump");
#endif
CRASHELPER_MARK_ENTRY();
std::thread t(th_sim);
std::cout << "Done" << std::endl;
t.join();
return 0;
}