From a0b99fccc423d59fab5c58d6d2bccb698141ffd0 Mon Sep 17 00:00:00 2001 From: Adam Brouwers-Harries Date: Wed, 26 Apr 2023 16:57:41 +0300 Subject: [PATCH] Add support for original mangled names to FrameDebugInfo, and extend demangle_any to return the kind of mangling in addition to the name --- samply-symbols/src/breakpad/symbol_map.rs | 14 ++++++++---- samply-symbols/src/demangle.rs | 26 +++++++++++++++++------ samply-symbols/src/dwarf.rs | 9 ++++---- samply-symbols/src/jitdump.rs | 1 + samply-symbols/src/shared.rs | 2 ++ samply-symbols/src/symbol_map_object.rs | 2 +- samply-symbols/src/windows.rs | 3 ++- 7 files changed, 40 insertions(+), 17 deletions(-) diff --git a/samply-symbols/src/breakpad/symbol_map.rs b/samply-symbols/src/breakpad/symbol_map.rs index 4e59e201..5a5fe7a8 100644 --- a/samply-symbols/src/breakpad/symbol_map.rs +++ b/samply-symbols/src/breakpad/symbol_map.rs @@ -300,6 +300,7 @@ impl<'a, T: FileContents> SymbolMapTrait for BreakpadSymbolMapInner<'a, T> { function: name, file_path: file.map(SourceFilePath::from_breakpad_path), line_number: Some(inlinee.call_line), + mangled_name: None, }); let inline_origin = inline_origins .get_str(inlinee.origin_id) @@ -319,6 +320,7 @@ impl<'a, T: FileContents> SymbolMapTrait for BreakpadSymbolMapInner<'a, T> { function: name, file_path: file.map(SourceFilePath::from_breakpad_path), line_number, + mangled_name: None, }); frames.reverse(); @@ -452,7 +454,8 @@ mod test { FrameDebugInfo { function: Some("WriteRelease64(long long*, long long)".into()), file_path: Some(SourceFilePath::new("/builds/worker/workspace/obj-build/browser/app/d:/agent/_work/2/s/src/externalapis/windows/10/sdk/inc/winnt.h".into(), None)), - line_number: Some(7729) + line_number: Some(7729), + mangled_name: None, } ); assert_eq!( @@ -460,7 +463,8 @@ mod test { FrameDebugInfo { function: Some("WritePointerRelease(void**, void*)".into()), file_path: Some(SourceFilePath::new("/builds/worker/workspace/obj-build/browser/app/d:/agent/_work/2/s/src/externalapis/windows/10/sdk/inc/winnt.h".into(), None)), - line_number: Some(8358) + line_number: Some(8358), + mangled_name: None, } ); assert_eq!( @@ -468,7 +472,8 @@ mod test { FrameDebugInfo { function: Some("DloadUnlock()".into()), file_path: Some(SourceFilePath::new("/builds/worker/workspace/obj-build/browser/app/d:/agent/_work/2/s/src/vctools/delayimp/dloadsup.h".into(), None)), - line_number: Some(345) + line_number: Some(345), + mangled_name: None, } ); assert_eq!( @@ -476,7 +481,8 @@ mod test { FrameDebugInfo { function: Some("DloadAcquireSectionWriteAccess()".into()), file_path: Some(SourceFilePath::new("/builds/worker/workspace/obj-build/browser/app/d:/agent/_work/2/s/src/vctools/delayimp/dloadsup.h".into(), None)), - line_number: Some(665) + line_number: Some(665), + mangled_name: None, } ); } diff --git a/samply-symbols/src/demangle.rs b/samply-symbols/src/demangle.rs index 5d35d9b6..99d9d367 100644 --- a/samply-symbols/src/demangle.rs +++ b/samply-symbols/src/demangle.rs @@ -1,7 +1,18 @@ use super::demangle_ocaml; use msvc_demangler::DemangleFlags; -pub fn demangle_any(name: &str) -> String { +/// MangleKind represents the possible name mangling that we may meet when trying to demangle a name. +/// In some situations, it is quite useful to know *how* a name was mangled, even after we have decoded it. +#[derive(Debug, PartialEq)] +pub enum MangleKind { + MSVC, + Rust, + OCaml, + Itanium, + Unknown +} + +pub fn demangle_any(name: &str) -> (MangleKind, String) { if name.starts_with('?') { let flags = DemangleFlags::NO_ACCESS_SPECIFIERS | DemangleFlags::NO_FUNCTION_RETURNS @@ -11,29 +22,30 @@ pub fn demangle_any(name: &str) -> String { | DemangleFlags::NO_CLASS_TYPE | DemangleFlags::SPACE_AFTER_COMMA | DemangleFlags::HUG_TYPE; - return msvc_demangler::demangle(name, flags).unwrap_or_else(|_| name.to_string()); + return (MangleKind::MSVC, msvc_demangler::demangle(name, flags).unwrap_or_else(|_| name.to_string())); } if let Ok(demangled_symbol) = rustc_demangle::try_demangle(name) { - return format!("{demangled_symbol:#}"); + return (MangleKind::Rust, format!("{demangled_symbol:#}")); } if name.starts_with('_') { let options = cpp_demangle::DemangleOptions::default().no_return_type(); if let Ok(symbol) = cpp_demangle::Symbol::new(name) { if let Ok(demangled_string) = symbol.demangle(&options) { - return demangled_string; + return (MangleKind::Itanium, demangled_string); } } } if let Some(symbol) = demangle_ocaml::demangle(name) { - return symbol; + return (MangleKind::OCaml, symbol); } if name.starts_with('_') { - return name.split_at(1).1.to_owned(); + return (MangleKind::Itanium, name.split_at(1).1.to_owned()); } - name.to_owned() + (MangleKind::Unknown, name.to_owned()) } + diff --git a/samply-symbols/src/dwarf.rs b/samply-symbols/src/dwarf.rs index f2ffb91f..e0439f7e 100644 --- a/samply-symbols/src/dwarf.rs +++ b/samply-symbols/src/dwarf.rs @@ -33,15 +33,15 @@ pub fn convert_stack_frame( frame: addr2line::Frame, path_mapper: &mut PathMapper<()>, ) -> FrameDebugInfo { - let function = match frame.function { + let (function, mangled_name) = match frame.function { Some(function_name) => { if let Ok(name) = function_name.raw_name() { - Some(demangle::demangle_any(&name)) + (Some(demangle::demangle_any(&name).1), Some(name.to_string())) } else { - None + (None, None) } } - None => None, + None => (None, None), }; let file_path = frame.location.as_ref().and_then(|l| l.file).map(|file| { let mapped_path = path_mapper.map_path(file); @@ -52,6 +52,7 @@ pub fn convert_stack_frame( function, file_path, line_number: frame.location.and_then(|l| l.line), + mangled_name, } } diff --git a/samply-symbols/src/jitdump.rs b/samply-symbols/src/jitdump.rs index 1cf6a80e..7afedac3 100644 --- a/samply-symbols/src/jitdump.rs +++ b/samply-symbols/src/jitdump.rs @@ -304,6 +304,7 @@ impl<'a, T: FileContents> JitDumpSymbolMapInner<'a, T> { function: Some(name.clone()), file_path: Some(SourceFilePath::new(file_path, None)), line_number: Some(entry.line), + mangled_name: None, }; FramesLookupResult::Available(vec![frame]) } diff --git a/samply-symbols/src/shared.rs b/samply-symbols/src/shared.rs index b65aede2..3a2345d2 100644 --- a/samply-symbols/src/shared.rs +++ b/samply-symbols/src/shared.rs @@ -425,6 +425,8 @@ pub struct FrameDebugInfo { pub file_path: Option, /// The line number for this frame, if known. pub line_number: Option, + /// The mangled name of this frame, if known. + pub mangled_name: Option, } /// A trait which abstracts away the token that's passed to the [`FileAndPathHelper::load_file`] diff --git a/samply-symbols/src/symbol_map_object.rs b/samply-symbols/src/symbol_map_object.rs index 6e23cfd9..523cfd68 100644 --- a/samply-symbols/src/symbol_map_object.rs +++ b/samply-symbols/src/symbol_map_object.rs @@ -495,7 +495,7 @@ where } }; - let name = demangle::demangle_any(&name); + let name = demangle::demangle_any(&name).1; Some(AddressInfo { symbol: SymbolInfo { address: *start_addr, diff --git a/samply-symbols/src/windows.rs b/samply-symbols/src/windows.rs index 4702729a..fd22ec2b 100644 --- a/samply-symbols/src/windows.rs +++ b/samply-symbols/src/windows.rs @@ -234,7 +234,7 @@ impl<'object> SymbolMapTrait for PdbSymbolMapInner<'object> { let function_frames = self.context.find_frames(address).ok()??; let symbol_address = function_frames.start_rva; let symbol_name = match &function_frames.frames.last().unwrap().function { - Some(name) => demangle::demangle_any(name), + Some(name) => demangle::demangle_any(name).1, None => "unknown".to_string(), }; let function_size = function_frames @@ -259,6 +259,7 @@ impl<'object> SymbolMapTrait for PdbSymbolMapInner<'object> { function: frame.function, file_path: frame.file.map(&mut map_path), line_number: frame.line, + mangled_name: None, }) .collect(); FramesLookupResult::Available(frames)