后端【免费下载链接】glogC implementation of the Google logging module项目地址https://gitcode.com/gh_mirrors/glog6/glog点击查看免费下载导读本指南围绕 glogGoogle logging module在 64 位 Linux 系统上的栈回溯stack unwinding能力展开核心解答崩溃时 glog 如何把调用栈打印出来以及该选哪种 unwinder。读完本文你将掌握glibc 内建 unwinder 与InstallFailureSignalHandler()组合时的死锁成因、为什么官方强烈推荐libunwind、静态链接场景下的编译注意事项-Wl,--eh-frame-hdr以及 frame pointer 方案的启用前提——并附带仓库源码级的实现细节作为佐证。注意本页描述可能并非最新原文档docs/unwinder.md顶部即有提示实际操作时请以当前仓库的 CMake 配置与源码为准。为什么 64 位 Linux 上 glog 需要单独关心栈回溯glog 在程序因SIGSEGV等信号崩溃时可以通过InstallFailureSignalHandler()安装信号处理器输出一段包含程序计数器PC与完整调用栈的崩溃信息failures.md 中展示了典型的崩溃输出格式。这段栈信息正是由底层的 stack unwinder栈回溯器产生的。而问题恰恰出在这里glibc 内建的 stack unwinder 在 64 位系统上与 glog 存在兼容性缺陷。如果信号在malloc执行中途触发这在崩溃场景下相当常见此时线程可能已经持有部分与malloc相关的锁glibc 内建 unwinder 在回溯过程中可能递归调用malloc而它需要的锁恰好被当前线程自己持有于是形成self-deadlock自死锁导致程序卡死在崩溃处理流程中。这一点在仓库源码中也有印证src/stacktrace_generic-inl.h 的注释明确写道Portable implementation - just use glibc以及Note: The glibc implementation may cause a call to malloc. This can cause a deadlock in HeapProfiler.可见 glibc 方案在 malloc 相关场景下的隐患是项目作者已知并记录在案的。死锁风险的边界条件需要澄清的是并非所有用户都会踩坑只有同时满足64 位系统使用InstallFailureSignalHandler()时才存在该风险如果程序不安装失败信号处理器即不需要 glog 帮你打印崩溃栈那么 glibc 内建 unwinder 是够用的即便安装了信号处理器死锁也只是罕见可能性但一旦发生崩溃现场无法正常输出问题排查会非常被动。推荐方案libunwind鉴于上述死锁风险原文档给出的结论非常明确如果你在 64 位系统上且需要InstallFailureSignalHandler()强烈建议在配置、编译 glog 之前就安装好libunwind。并且文档提醒即使系统里已有libunwind也建议使用其快照snapshot版本以获取最新功能。libunwind 的实现原理源码视角libunwind方案在仓库中的实现位于 src/stacktrace_libunwind-inl.h其核心调用链为unw_getcontext(uc)获取当前 CPU 上下文unw_init_local(cursor, uc)初始化回溯游标循环调用unw_get_reg(cursor, UNW_REG_IP, ...)读取指令指针IP并用unw_step(cursor)逐帧向上推进直到max_depth或栈顶。值得注意的是实现里用static __thread bool g_tl_entered线程局部变量做了一层递归保护因为libunwind内部可能通过mmap或其内部基于 mmap 的分配器间接触发新的栈回溯请求若不拦截会陷入无限递归或死锁检测到重入时直接返回 0。这从侧面说明栈回溯在信号处理场景里是高危地带任何一步都可能引发连锁问题。静态链接 libunwind 的注意事项原文档特别警告如果从快照 URL 安装libunwind并将二进制与 glog静态链接例如gcc -static -lgcc_eh ...可能会遇到麻烦。原因在于libunwind与libgcc都实现了同一套 C 异常处理 API但在某些平台上两者实现方式不同——ia64 上大概率没问题但x86-64 上可能出问题。同时静态链接时必须给链接器加上-Wl,--eh-frame-hdr选项否则libunwind无法找到编译器生成的、栈回溯所需的.eh_frame段信息。glog 如何探测与链接 libunwindCMake 视角当前仓库的 CMake 构建系统完整支持这一流程cmake/FindUnwind.cmake 负责探测find_path查找unwind.h/libunwind.h头文件find_library查找unwind库并尝试从libunwind-common.h中解析版本号UNW_VERSION_MAJOR/MINOR/EXTRA最终通过find_package_handle_standard_args输出Unwind_FOUND与导入目标unwind::unwindCMakeLists.txt 中find_package (Unwind)之后会进一步做符号级验证分别检查_Unwind_Backtrace/_Unwind_GetIP对应 libgcc 的unwind驱动与unw_get_reg/unw_getcontext/unw_init_local/unw_step对应libunwind驱动是否存在——注意注释特别提到LLVM unwind 的 ARM 工具链不一定提供_Unwind_Backtrace会导致头文件检查通过但链接失败所以仓库特意增加了check_cxx_symbol_exists链接级检查最终结果写入HAVE_UNWIND/HAVE_LIBUNWIND宏见 src/config.h.cmake.in并在 CMakeLists.txt 中将unwind::unwind私有链接到glog。这些宏最终决定了 src/stacktrace.h 中选择哪个具体实现优先HAVE_LIBUNWINDstacktrace_libunwind-inl.h其次HAVE_UNWINDstacktrace_unwind-inl.h即基于 libgcc 的 ABI unwinder。CMake 中显式控制 unwinder除了自动探测glog 的 CMake 还提供了手动开关WITH_UNWINDCMakeLists.txt可选值取值含义libunwind默认使用 libunwind 驱动需HAVE_LIBUNWINDunwind使用 libgcc 提供的 ABI unwinder需HAVE_UNWINDnone禁用 Unwind 探测CMAKE_DISABLE_FIND_PACKAGE_Unwind ON见 CMakeLists.txt配置示例cmake -DWITH_UNWINDlibunwind -B build cmake --build build备选方案一glibc 内建 Stack Unwinder如果不希望或无法安装libunwindglibc 内建 unwinder 仍可用前提是接受其死锁风险不使用InstallFailureSignalHandler()或不介意罕见死锁可能。其选择逻辑也很直白原文档 源码双重印证如果配置时不指定任何选项且系统上未检测到libunwindconfigure 脚本/CMake 会默认选中 glibc unwinder。对应源码实现即 src/stacktrace_generic-inl.h内部使用backtrace()execinfo.h需要HAVE_EXECINFO_BACKTRACE宏见 src/config.h.cmake.in用固定 64 帧的栈缓冲void* stack[64]然后按skip_count跳过本帧将结果拷贝到调用者缓冲区超出max_depth的部分截断。该实现非常简单但正如其文件头注释所警告的backtrace()可能触发malloc调用这正是 64 位 信号处理器场景下死锁的根源。备选方案二Frame Pointer 基于栈指针的回溯器第三种方案是基于帧指针frame pointer即 x86/x86-64 的%rbp/%ebp的回溯器。它的原理是每个栈帧头部保存着前一个栈帧的指针顺着这条链表逐帧上溯即可还原整个调用栈。启用条件所有代码都必须带帧指针原文档强调了一个容易被忽略的前提——frame pointer 方案要求你的应用、glog 库以及 libc 等系统库全部都以帧指针方式编译而x86-64 上默认并不开启-fomit-frame-pointer是 x86-64 ABI 的常见默认尤其是在开启优化时。只要任意一环没有帧指针回溯就会中途失败或产生错误地址。源码视角x86 实现细节仓库中的实现是 src/stacktrace_x86-inl.h在 x86-64 上通过内联汇编mov %%rbp, %0读取帧指针注释解释了为何用volatile防止编译器重排到函数序言之前循环中读取sp[1]即返回地址写入结果数组再用NextStackFrametrue(sp)沿帧指针链推进严格模式下STRICT_UNWINDING见 src/stacktrace_x86-inl.h还会做多项健全性检查新帧地址必须严格大于旧帧、帧间隔超过 100KB 判定为无效、地址未按指针大小对齐则中止、必要时用msync验证新帧内存可读以防野指针导致二次崩溃。另外HAVE_UNWINDlibgcc方案 src/stacktrace_unwind-inl.h 通过_Unwind_Backtrace(GetOneFrame, ...)逐帧回调获取 IP并在静态初始化期强制跑一次_Unwind_Backtracenop_backtrace确保与 malloc 相关的初始化已完成后再正式使用这也是规避 malloc 死锁的一类防御手段。信号处理器中的实际调用链无论最终选中哪个 unwinder崩溃场景下 glog 的调用路径是统一的。以 src/signalhandler.cc 为例#ifdef HAVE_STACKTRACE // Get the stack traces. void* stack[32]; // 1 to exclude this function. const int depth GetStackTrace(stack, ARRAYSIZE(stack), 1); ... for (int i 0; i depth; i) { DumpStackFrameInfo( , stack[i]); } #endif即在HAVE_STACKTRACE由 src/stacktrace.h 根据所选实现定义成立时信号处理器调用GetStackTrace(stack, 32, 1)抓取最多 32 帧、跳过本函数然后逐帧输出。GetStackTrace的公共签名定义在 src/stacktrace.h实际实现由 src/stacktrace.cc 根据STACKTRACE_H宏#include对应的-inl.h文件编译进来——这就是按配置选择实现的落点。而支持栈回溯的目标平台官方在 docs/failures.md 中列明为x86、x86_64、PowerPC 架构、libunwind以及 Windows 上的 Debug Help Librarydbghelp。选择建议与决策速查场景推荐 unwinder说明64 位 Linux 需要InstallFailureSignalHandler()libunwind避免 glibc unwinder 的 malloc 递归死锁官方强烈推荐64 位 Linux 静态链接libunwind-Wl,--eh-frame-hdr注意 libunwind 与 libgcc 异常处理 API 在 x86-64 的潜在冲突不装信号处理器 / 接受罕见死锁glibc 内建未检测到 libunwind 时的默认选择全链路应用、glog、libc均启用帧指针frame pointerx86-64 默认不满足条件需自行关闭-fomit-frame-pointer一句话总结能装 libunwind 就装 libunwind它是 glog 在 64 位 Linux 上兼顾崩溃栈输出可用性与避免死锁的最稳妥路径无法安装时再按需降级到 glibc 内建或 frame pointer 方案并各自接受其已知限制。延伸阅读崩溃信号处理器与输出定制docs/failures.md含InstallFailureWriter、InstallFailureFunction的用法栈回溯公共接口src/stacktrace.h各平台实现libunwind 版 src/stacktrace_libunwind-inl.h、libgcc 版 src/stacktrace_unwind-inl.h、glibc 版 src/stacktrace_generic-inl.h、x86 帧指针版 src/stacktrace_x86-inl.h构建期探测与链接 cmake/FindUnwind.cmake 与 CMakeLists.txt构建配置宏定义src/config.h.cmake.in赞分享后端【免费下载链接】glogC implementation of the Google logging module项目地址https://gitcode.com/gh_mirrors/glog6/glog点击查看免费下载相关推荐glog unwinder机制深度解析stacktrace_libunwind-inl.h实现原理与实战glog unwinder机制深度解析stacktrace_libunwind inl.h实现原理与实战 引言为何stacktrace捕获如此重要 在C后端radare2 宏Macros完全指南从 Hello World 到 x86-64 栈回溯自动化radare2 宏Macros完全指南从 Hello World 到 x86 64 栈回溯自动化 本文以 doc/macros.md https://li逆向工程网络安全三步搭好 Sunshine 自托管游戏串流:免费低延迟私人云游戏平台三步搭好 Sunshine 自托管游戏串流:免费低延迟私人云游戏平台 Sunshine 是一个自托管游戏串流服务器,把你自己的 PC 变成 Moonlight音视频后端上一篇一键获取九大网盘直链把百度网盘、阿里云盘文件交给 IDM 与 Aria2下一篇Processing.js核心组件详解PMatrix、PVector与PShape的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
