debug:win和linux都通过,linx下Release暂时没有有效内容
This commit is contained in:
commit
b4de9d6c1c
17
.clang-format
Normal file
17
.clang-format
Normal 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
45
.gitignore
vendored
Normal 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
103
.vscode/settings.json
vendored
Normal 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
19
CMakeLists.txt
Normal 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
50
README.md
Normal 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
27
crashelper/CMakeLists.txt
Normal 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)
|
4710
crashelper/include/backward.hpp
Normal file
4710
crashelper/include/backward.hpp
Normal file
File diff suppressed because it is too large
Load Diff
61
crashelper/include/crashelper.h
Normal file
61
crashelper/include/crashelper.h
Normal 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
|
178
crashelper/src/crashelper.cxx
Normal file
178
crashelper/src/crashelper.cxx
Normal 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
5
test/CMakeLists.txt
Normal 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
31
test/main.cxx
Normal 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user