From b891125913228468b3fb33f07c3a1b4b3807644e Mon Sep 17 00:00:00 2001 From: roblabla Date: Tue, 21 Nov 2023 12:24:24 +0100 Subject: [PATCH] Fix panic in backtrace symbolication on win7 Since https://github.com/rust-lang/backtrace-rs/pull/569 was merged, symbolication of backtraces would panic on Windows 7, due to using symbols that do not exist in the version of dbghelp.dll that ships there (Windows 7 ships with dbghelp.dll version 6.1, but the symbols were only added in version 6.2). This commit checks for the presence of the newer symbols, and if they are not found, falls back to the old resolution method. --- src/dbghelp.rs | 16 ++++++++++++++-- src/symbolize/dbghelp.rs | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/dbghelp.rs b/src/dbghelp.rs index 30033fc8..e456dd45 100644 --- a/src/dbghelp.rs +++ b/src/dbghelp.rs @@ -34,8 +34,8 @@ use core::ptr; mod dbghelp { use crate::windows::*; pub use winapi::um::dbghelp::{ - StackWalk64, StackWalkEx, SymFunctionTableAccess64, SymGetModuleBase64, SymGetOptions, - SymInitializeW, SymSetOptions, + StackWalk64, StackWalkEx, SymFromAddrW, SymFunctionTableAccess64, SymGetLineFromAddrW64, + SymGetModuleBase64, SymGetOptions, SymInitializeW, SymSetOptions, }; extern "system" { @@ -233,6 +233,18 @@ dbghelp! { CurContext: LPDWORD, CurFrameIndex: LPDWORD ) -> BOOL; + fn SymFromAddrW( + hProcess: HANDLE, + Address: DWORD64, + Displacement: PDWORD64, + Symbol: PSYMBOL_INFOW + ) -> BOOL; + fn SymGetLineFromAddrW64( + hProcess: HANDLE, + dwAddr: DWORD64, + pdwDisplacement: PDWORD, + Line: PIMAGEHLP_LINEW64 + ) -> BOOL; } } diff --git a/src/symbolize/dbghelp.rs b/src/symbolize/dbghelp.rs index 0ca58c83..8c47d58e 100644 --- a/src/symbolize/dbghelp.rs +++ b/src/symbolize/dbghelp.rs @@ -78,14 +78,45 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) Err(()) => return, // oh well... }; + let resolve_inner = if (*dbghelp.dbghelp()).SymAddrIncludeInlineTrace().is_some() { + // We are on a version of dbghelp 6.2+, which contains the more modern + // Inline APIs. + resolve_with_inline + } else { + // We are on an older version of dbghelp which doesn't contain the Inline + // APIs. + resolve_legacy + }; match what { - ResolveWhat::Address(_) => resolve_with_inline(&dbghelp, what.address_or_ip(), None, cb), + ResolveWhat::Address(_) => resolve_inner(&dbghelp, what.address_or_ip(), None, cb), ResolveWhat::Frame(frame) => { - resolve_with_inline(&dbghelp, frame.ip(), frame.inner.inline_context(), cb) + resolve_inner(&dbghelp, frame.ip(), frame.inner.inline_context(), cb) } } } +/// Resolve the address using the legacy dbghelp API. +/// +/// This should work all the way down to Windows XP. The inline context is +/// ignored, since this concept was only introduced in dbghelp 6.2+. +unsafe fn resolve_legacy( + dbghelp: &dbghelp::Init, + addr: *mut c_void, + _inline_context: Option, + cb: &mut dyn FnMut(&super::Symbol), +) { + let addr = super::adjust_ip(addr) as DWORD64; + do_resolve( + |info| dbghelp.SymFromAddrW()(GetCurrentProcess(), addr, &mut 0, info), + |line| dbghelp.SymGetLineFromAddrW64()(GetCurrentProcess(), addr, &mut 0, line), + cb, + ) +} + +/// Resolve the address using the modern dbghelp APIs. +/// +/// Note that calling this function requires having dbghelp 6.2+ loaded - and +/// will panic otherwise. unsafe fn resolve_with_inline( dbghelp: &dbghelp::Init, addr: *mut c_void,