From f91471db1eef8387d0f6c8197ea16c3dc516d647 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 29 Oct 2026 17:49:02 +0000 Subject: [PATCH 01/13] feat!(variables): Register mapping DWARF <> x86_64 Co-Authored-By: Dr. Daniel Szokenstein <7881302+szokeasaurusrex@users.noreply.github.com> --- CHANGELOG.md | 1 + examples/addr2line/src/main.rs | 2 +- symbolic-common/src/lib.rs | 2 + symbolic-common/src/register.rs | 232 ++++++++++++++++++ symbolic-debuginfo/src/base/variable.rs | 7 +- symbolic-debuginfo/src/dwarf/mod.rs | 19 +- symbolic-debuginfo/src/elf.rs | 8 +- symbolic-debuginfo/src/function_builder.rs | 12 +- symbolic-debuginfo/src/macho/mod.rs | 9 +- symbolic-debuginfo/src/pe.rs | 8 +- symbolic-debuginfo/src/wasm.rs | 8 +- .../test_objects__elf_functions.snap | 78 +++--- .../test_objects__elf_variables_opt.snap | 50 ++-- .../test_objects__mach_functions.snap | 62 ++--- .../test_objects__pe_dwarf_functions.snap | 48 ++-- ...jects__pe_dwarf_msys2_qglib_functions.snap | 38 +-- symbolic-debuginfo/tests/test_objects.rs | 4 +- symbolic-symcache/src/v9/convert.rs | 15 ++ symbolic-symcache/src/v9/lookup.rs | 12 +- symbolic-symcache/src/writer.rs | 4 +- symbolic-symcache/tests/test_cache.rs | 70 +++--- 21 files changed, 493 insertions(+), 196 deletions(-) create mode 100644 symbolic-common/src/register.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e61ee6cf..10ece18f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ **Breaking Changes** - Change `symbolic_debuginfo::PointerType::pointee` from `TypeRef` to `Option`. ([#1100](https://github.com/getsentry/symbolic/pull/1100)) +- Change `VariableLocation::Register` from `Register { id: u16 }` (raw DWARF register number) to `Register(symbolic_common::Register)`. Only x86-64 registers are supported for now; register locations of other architectures are omitted. `DwarfDebugSession::parse` takes the object's `CpuFamily` as an additional argument. ([#PR](https://github.com/getsentry/symbolic/pull/PR)) **Features** diff --git a/examples/addr2line/src/main.rs b/examples/addr2line/src/main.rs index 7e5515e09..ac502e05c 100644 --- a/examples/addr2line/src/main.rs +++ b/examples/addr2line/src/main.rs @@ -114,7 +114,7 @@ fn resolve( for location in locations { print!(" location: "); match location.location { - VariableLocation::Register { id } => print!("reg:{id}"), + VariableLocation::Register(register) => print!("reg:{register}"), VariableLocation::FrameOffset { offset } => print!("fbreg:{offset}"), } print_range(location.address, Some(location.size), matches); diff --git a/symbolic-common/src/lib.rs b/symbolic-common/src/lib.rs index fbaaf744e..d48c2a4f3 100644 --- a/symbolic-common/src/lib.rs +++ b/symbolic-common/src/lib.rs @@ -26,6 +26,7 @@ mod byteview; mod cell; mod heuristics; mod path; +mod register; mod sourcelinks; mod types; @@ -33,6 +34,7 @@ pub use crate::byteview::*; pub use crate::cell::*; pub use crate::heuristics::*; pub use crate::path::*; +pub use crate::register::*; pub use crate::sourcelinks::*; pub use crate::types::*; diff --git a/symbolic-common/src/register.rs b/symbolic-common/src/register.rs new file mode 100644 index 000000000..8120b665b --- /dev/null +++ b/symbolic-common/src/register.rs @@ -0,0 +1,232 @@ +//! Architecture specific register definitions. +//! +//! Registers are identified by symbolic's own types rather than by the numbering of a particular +//! debug format, so that the same register can be named independently of where it was read from. + +use std::fmt; + +use crate::CpuFamily; + +/// Defines a register enum for an architecture, along with its DWARF register numbers and names. +macro_rules! registers { + ( + $(#[$enum_meta:meta])* + pub enum $enum:ident { + $($variant:ident = { name: $name:literal, dwarf: $dwarf:literal },)* + } + ) => { + $(#[$enum_meta])* + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub enum $enum { + $( + #[doc = concat!("The `", $name, "` register.")] + $variant, + )* + } + + impl $enum { + /// Returns the register with the given DWARF register number. + /// + /// Returns `None` for numbers which are not a register, such as reserved numbers. + pub fn from_dwarf(number: u16) -> Option { + match number { + $($dwarf => Some(Self::$variant),)* + _ => None, + } + } + + /// Returns the DWARF register number of this register. + /// + /// The number of a register is fixed and will not change. + pub fn to_dwarf(self) -> u16 { + match self { + $(Self::$variant => $dwarf,)* + } + } + } + + impl fmt::Display for $enum { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + $(Self::$variant => $name,)* + }) + } + } + }; +} + +registers! { + /// An x86-64 register. + /// + /// The set of registers follows the DWARF register number mapping of the + /// [System V AMD64 psABI][psabi] (section 3.6.2), without the reserved numbers. + /// + /// The registers are `rax` to `rsp` and `r8` to `r31` (general purpose), `rip` (the return + /// address), `xmm0` to `xmm31` (vectors), `st0` to `st7` (x87), `mm0` to `mm7` (MMX), + /// `rflags`, the segment registers, a few system and control registers, `k0` to `k7` (vector + /// masks), and the AMX registers `tmm0` to `tmm7` and `tilecfg`. + /// + /// The variants themselves are independent of the register numbering of any debug format, + /// use [`Amd64Register::from_dwarf`] and [`Amd64Register::to_dwarf`] to convert from and to + /// DWARF register numbers. + /// + /// [psabi]: https://gitlab.com/x86-psabis/x86-64-ABI + pub enum Amd64Register { + Rax = { name: "rax", dwarf: 0 }, + Rdx = { name: "rdx", dwarf: 1 }, + Rcx = { name: "rcx", dwarf: 2 }, + Rbx = { name: "rbx", dwarf: 3 }, + Rsi = { name: "rsi", dwarf: 4 }, + Rdi = { name: "rdi", dwarf: 5 }, + Rbp = { name: "rbp", dwarf: 6 }, + Rsp = { name: "rsp", dwarf: 7 }, + R8 = { name: "r8", dwarf: 8 }, + R9 = { name: "r9", dwarf: 9 }, + R10 = { name: "r10", dwarf: 10 }, + R11 = { name: "r11", dwarf: 11 }, + R12 = { name: "r12", dwarf: 12 }, + R13 = { name: "r13", dwarf: 13 }, + R14 = { name: "r14", dwarf: 14 }, + R15 = { name: "r15", dwarf: 15 }, + Rip = { name: "rip", dwarf: 16 }, + Xmm0 = { name: "xmm0", dwarf: 17 }, + Xmm1 = { name: "xmm1", dwarf: 18 }, + Xmm2 = { name: "xmm2", dwarf: 19 }, + Xmm3 = { name: "xmm3", dwarf: 20 }, + Xmm4 = { name: "xmm4", dwarf: 21 }, + Xmm5 = { name: "xmm5", dwarf: 22 }, + Xmm6 = { name: "xmm6", dwarf: 23 }, + Xmm7 = { name: "xmm7", dwarf: 24 }, + Xmm8 = { name: "xmm8", dwarf: 25 }, + Xmm9 = { name: "xmm9", dwarf: 26 }, + Xmm10 = { name: "xmm10", dwarf: 27 }, + Xmm11 = { name: "xmm11", dwarf: 28 }, + Xmm12 = { name: "xmm12", dwarf: 29 }, + Xmm13 = { name: "xmm13", dwarf: 30 }, + Xmm14 = { name: "xmm14", dwarf: 31 }, + Xmm15 = { name: "xmm15", dwarf: 32 }, + St0 = { name: "st0", dwarf: 33 }, + St1 = { name: "st1", dwarf: 34 }, + St2 = { name: "st2", dwarf: 35 }, + St3 = { name: "st3", dwarf: 36 }, + St4 = { name: "st4", dwarf: 37 }, + St5 = { name: "st5", dwarf: 38 }, + St6 = { name: "st6", dwarf: 39 }, + St7 = { name: "st7", dwarf: 40 }, + Mm0 = { name: "mm0", dwarf: 41 }, + Mm1 = { name: "mm1", dwarf: 42 }, + Mm2 = { name: "mm2", dwarf: 43 }, + Mm3 = { name: "mm3", dwarf: 44 }, + Mm4 = { name: "mm4", dwarf: 45 }, + Mm5 = { name: "mm5", dwarf: 46 }, + Mm6 = { name: "mm6", dwarf: 47 }, + Mm7 = { name: "mm7", dwarf: 48 }, + Rflags = { name: "rflags", dwarf: 49 }, + Es = { name: "es", dwarf: 50 }, + Cs = { name: "cs", dwarf: 51 }, + Ss = { name: "ss", dwarf: 52 }, + Ds = { name: "ds", dwarf: 53 }, + Fs = { name: "fs", dwarf: 54 }, + Gs = { name: "gs", dwarf: 55 }, + FsBase = { name: "fs.base", dwarf: 58 }, + GsBase = { name: "gs.base", dwarf: 59 }, + Tr = { name: "tr", dwarf: 62 }, + Ldtr = { name: "ldtr", dwarf: 63 }, + Mxcsr = { name: "mxcsr", dwarf: 64 }, + Fcw = { name: "fcw", dwarf: 65 }, + Fsw = { name: "fsw", dwarf: 66 }, + Xmm16 = { name: "xmm16", dwarf: 67 }, + Xmm17 = { name: "xmm17", dwarf: 68 }, + Xmm18 = { name: "xmm18", dwarf: 69 }, + Xmm19 = { name: "xmm19", dwarf: 70 }, + Xmm20 = { name: "xmm20", dwarf: 71 }, + Xmm21 = { name: "xmm21", dwarf: 72 }, + Xmm22 = { name: "xmm22", dwarf: 73 }, + Xmm23 = { name: "xmm23", dwarf: 74 }, + Xmm24 = { name: "xmm24", dwarf: 75 }, + Xmm25 = { name: "xmm25", dwarf: 76 }, + Xmm26 = { name: "xmm26", dwarf: 77 }, + Xmm27 = { name: "xmm27", dwarf: 78 }, + Xmm28 = { name: "xmm28", dwarf: 79 }, + Xmm29 = { name: "xmm29", dwarf: 80 }, + Xmm30 = { name: "xmm30", dwarf: 81 }, + Xmm31 = { name: "xmm31", dwarf: 82 }, + K0 = { name: "k0", dwarf: 118 }, + K1 = { name: "k1", dwarf: 119 }, + K2 = { name: "k2", dwarf: 120 }, + K3 = { name: "k3", dwarf: 121 }, + K4 = { name: "k4", dwarf: 122 }, + K5 = { name: "k5", dwarf: 123 }, + K6 = { name: "k6", dwarf: 124 }, + K7 = { name: "k7", dwarf: 125 }, + R16 = { name: "r16", dwarf: 130 }, + R17 = { name: "r17", dwarf: 131 }, + R18 = { name: "r18", dwarf: 132 }, + R19 = { name: "r19", dwarf: 133 }, + R20 = { name: "r20", dwarf: 134 }, + R21 = { name: "r21", dwarf: 135 }, + R22 = { name: "r22", dwarf: 136 }, + R23 = { name: "r23", dwarf: 137 }, + R24 = { name: "r24", dwarf: 138 }, + R25 = { name: "r25", dwarf: 139 }, + R26 = { name: "r26", dwarf: 140 }, + R27 = { name: "r27", dwarf: 141 }, + R28 = { name: "r28", dwarf: 142 }, + R29 = { name: "r29", dwarf: 143 }, + R30 = { name: "r30", dwarf: 144 }, + R31 = { name: "r31", dwarf: 145 }, + Tmm0 = { name: "tmm0", dwarf: 146 }, + Tmm1 = { name: "tmm1", dwarf: 147 }, + Tmm2 = { name: "tmm2", dwarf: 148 }, + Tmm3 = { name: "tmm3", dwarf: 149 }, + Tmm4 = { name: "tmm4", dwarf: 150 }, + Tmm5 = { name: "tmm5", dwarf: 151 }, + Tmm6 = { name: "tmm6", dwarf: 152 }, + Tmm7 = { name: "tmm7", dwarf: 153 }, + Tilecfg = { name: "tilecfg", dwarf: 154 }, + } +} + +/// A register of any supported architecture. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum Register { + /// An x86-64 register. + Amd64(Amd64Register), +} + +impl Register { + /// Returns the register with the given DWARF register number for the given CPU family. + /// + /// Returns `None` if the CPU family has no register mapping, or if the number is not a + /// register of the CPU family. + pub fn from_dwarf(cpu_family: CpuFamily, number: u16) -> Option { + match cpu_family { + CpuFamily::Amd64 => Amd64Register::from_dwarf(number).map(Self::Amd64), + _ => None, + } + } + + /// Returns the DWARF register number of this register. + /// + /// The number of a register is fixed and will not change. + pub fn to_dwarf(self) -> u16 { + match self { + Self::Amd64(register) => register.to_dwarf(), + } + } +} + +impl fmt::Display for Register { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Amd64(register) => register.fmt(f), + } + } +} + +impl From for Register { + fn from(register: Amd64Register) -> Self { + Self::Amd64(register) + } +} diff --git a/symbolic-debuginfo/src/base/variable.rs b/symbolic-debuginfo/src/base/variable.rs index f92128e6b..868e90f18 100644 --- a/symbolic-debuginfo/src/base/variable.rs +++ b/symbolic-debuginfo/src/base/variable.rs @@ -1,5 +1,7 @@ use std::{borrow::Cow, fmt}; +use symbolic_common::Register; + /// A type reference. /// /// Links a variable to a concrete type. @@ -159,10 +161,7 @@ impl fmt::Debug for VariableLocationInfo { #[derive(Debug, Clone)] pub enum VariableLocation { /// The variable can be found in a register. - Register { - /// An architecture dependent id of the register. - id: u16, - }, + Register(Register), /// The variable can be found at an offset relative to the function's frame base. FrameOffset { /// The signed offset from the frame base. diff --git a/symbolic-debuginfo/src/dwarf/mod.rs b/symbolic-debuginfo/src/dwarf/mod.rs index 91f9de5f0..ad5a2a6b5 100644 --- a/symbolic-debuginfo/src/dwarf/mod.rs +++ b/symbolic-debuginfo/src/dwarf/mod.rs @@ -25,7 +25,7 @@ use gimli::{ }; use thiserror::Error; -use symbolic_common::{AsSelf, Language, Name, NameMangling, SelfCell}; +use symbolic_common::{AsSelf, CpuFamily, Language, Name, NameMangling, Register, SelfCell}; use crate::base::*; use crate::function_builder::{ @@ -1471,7 +1471,10 @@ impl<'d, 'a> DwarfUnit<'d, 'a> { } match op { - Operation::Register { register } => Some(VariableLocation::Register { id: register.0 }), + Operation::Register { register } => { + Register::from_dwarf(self.inner.info.cpu_family, register.0) + .map(VariableLocation::Register) + } Operation::FrameOffset { offset } => Some(VariableLocation::FrameOffset { offset }), // Currently more operations are not supported. _ => None, @@ -1765,6 +1768,7 @@ struct DwarfInfo<'data> { symbol_map: SymbolMap<'data>, address_offset: i64, kind: ObjectKind, + cpu_family: CpuFamily, } impl<'d> Deref for DwarfInfo<'d> { @@ -1782,6 +1786,7 @@ impl<'d> DwarfInfo<'d> { symbol_map: SymbolMap<'d>, address_offset: i64, kind: ObjectKind, + cpu_family: CpuFamily, ) -> Result { let mut inner = gimli::read::Dwarf { abbreviations_cache: Default::default(), @@ -1821,6 +1826,7 @@ impl<'d> DwarfInfo<'d> { symbol_map, address_offset, kind, + cpu_family, }) } @@ -1938,13 +1944,20 @@ impl<'data> DwarfDebugSession<'data> { symbol_map: SymbolMap<'data>, address_offset: i64, kind: ObjectKind, + cpu_family: CpuFamily, ) -> Result where D: Dwarf<'data>, { let sections = DwarfSections::from_dwarf(dwarf); let cell = SelfCell::try_new(Box::new(sections), |sections| { - DwarfInfo::parse(unsafe { &*sections }, symbol_map, address_offset, kind) + DwarfInfo::parse( + unsafe { &*sections }, + symbol_map, + address_offset, + kind, + cpu_family, + ) })?; Ok(DwarfDebugSession { diff --git a/symbolic-debuginfo/src/elf.rs b/symbolic-debuginfo/src/elf.rs index dfede1133..7cc7b8309 100644 --- a/symbolic-debuginfo/src/elf.rs +++ b/symbolic-debuginfo/src/elf.rs @@ -562,7 +562,13 @@ impl<'data> ElfObject<'data> { /// [`has_debug_info`](struct.ElfObject.html#method.has_debug_info). pub fn debug_session(&self) -> Result, DwarfError> { let symbols = self.symbol_map(); - DwarfDebugSession::parse(self, symbols, self.load_address() as i64, self.kind()) + DwarfDebugSession::parse( + self, + symbols, + self.load_address() as i64, + self.kind(), + self.arch().cpu_family(), + ) } /// Determines whether this object contains stack unwinding information. diff --git a/symbolic-debuginfo/src/function_builder.rs b/symbolic-debuginfo/src/function_builder.rs index 663791942..5a1bb4d4a 100644 --- a/symbolic-debuginfo/src/function_builder.rs +++ b/symbolic-debuginfo/src/function_builder.rs @@ -520,6 +520,8 @@ fn ensure_proper_nesting( #[cfg(test)] mod tests { + use symbolic_common::{Amd64Register, Register}; + use crate::{VariableKind, VariableLocation, VariableLocationInfo}; use super::*; @@ -680,7 +682,7 @@ mod tests { locations: vec![VariableLocationInfo { address: 0x10, size: 0x40, - location: VariableLocation::Register { id: 0 }, + location: VariableLocation::Register(Register::Amd64(Amd64Register::Rax)), }], }; @@ -740,9 +742,11 @@ mod tests { VariableLocationInfo { address: 0x20, size: 0x10, - location: Register { - id: 0, - }, + location: Register( + Amd64( + Rax, + ), + ), }, ], }, diff --git a/symbolic-debuginfo/src/macho/mod.rs b/symbolic-debuginfo/src/macho/mod.rs index d10fa2185..7dde99e81 100644 --- a/symbolic-debuginfo/src/macho/mod.rs +++ b/symbolic-debuginfo/src/macho/mod.rs @@ -319,8 +319,13 @@ impl<'d> MachObject<'d> { /// [`has_debug_info`](struct.MachObject.html#method.has_debug_info). pub fn debug_session(&self) -> Result, DwarfError> { let symbols = self.symbol_map(); - let mut session = - DwarfDebugSession::parse(self, symbols, self.load_address() as i64, self.kind())?; + let mut session = DwarfDebugSession::parse( + self, + symbols, + self.load_address() as i64, + self.kind(), + self.arch().cpu_family(), + )?; session.load_symbolmap(self.bcsymbolmap.clone()); Ok(session) } diff --git a/symbolic-debuginfo/src/pe.rs b/symbolic-debuginfo/src/pe.rs index 1cfe7dadc..721ba077d 100644 --- a/symbolic-debuginfo/src/pe.rs +++ b/symbolic-debuginfo/src/pe.rs @@ -251,7 +251,13 @@ impl<'data> PeObject<'data> { /// [`has_debug_info`](struct.PeObject.html#method.has_debug_info). pub fn debug_session(&self) -> Result, DwarfError> { let symbols = self.symbol_map(); - DwarfDebugSession::parse(self, symbols, self.load_address() as i64, self.kind()) + DwarfDebugSession::parse( + self, + symbols, + self.load_address() as i64, + self.kind(), + self.arch().cpu_family(), + ) } /// Determines whether this object contains stack unwinding information. diff --git a/symbolic-debuginfo/src/wasm.rs b/symbolic-debuginfo/src/wasm.rs index ddb7197a4..11431e5ba 100644 --- a/symbolic-debuginfo/src/wasm.rs +++ b/symbolic-debuginfo/src/wasm.rs @@ -120,7 +120,13 @@ impl<'data> WasmObject<'data> { pub fn debug_session(&self) -> Result, DwarfError> { let symbols = self.symbol_map(); // WASM is offset by the negative offset to the code section instead of the load address - DwarfDebugSession::parse(self, symbols, -(self.code_offset() as i64), self.kind()) + DwarfDebugSession::parse( + self, + symbols, + -(self.code_offset() as i64), + self.kind(), + self.arch().cpu_family(), + ) } /// Determines whether this object contains stack unwinding information. diff --git a/symbolic-debuginfo/tests/snapshots/test_objects__elf_functions.snap b/symbolic-debuginfo/tests/snapshots/test_objects__elf_functions.snap index 627b60bd4..e9bd7e9d9 100644 --- a/symbolic-debuginfo/tests/snapshots/test_objects__elf_functions.snap +++ b/symbolic-debuginfo/tests/snapshots/test_objects__elf_functions.snap @@ -105,13 +105,13 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" argc (parameter) type: > Primitive: int (SignedInt, 4 bytes) - 0x1c70..0x1d2b: register 5 + 0x1c70..0x1d2b: register rdi argv (parameter) type: > Pointer (8 bytes) > Pointer (8 bytes) > Primitive: char (SignedChar, 1 byte) - 0x1c70..0x1cc3: register 4 + 0x1c70..0x1cc3: register rsi descriptor (local) type: > Unknown @@ -744,33 +744,33 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" this (parameter) type: > Unknown - 0x2520..0x2538: register 5 - 0x2538..0x255a: register 3 - 0x257f..0x2777: register 3 - 0x27c6..0x299d: register 3 - 0x29a2..0x29ab: register 3 + 0x2520..0x2538: register rdi + 0x2538..0x255a: register rbx + 0x257f..0x2777: register rbx + 0x27c6..0x299d: register rbx + 0x29a2..0x29ab: register rbx context (parameter) type: > Pointer (8 bytes) > Unknown - 0x2520..0x2557: register 4 - 0x2557..0x255a: register 6 - 0x257f..0x2595: register 4 - 0x2595..0x2655: register 6 + 0x2520..0x2557: register rsi + 0x2557..0x255a: register rbp + 0x257f..0x2595: register rsi + 0x2595..0x2655: register rbp 0x2655..0x2661: frame base -88 - 0x27c6..0x27dd: register 6 + 0x27c6..0x27dd: register rbp 0x27e2..0x27f6: frame base -88 - 0x2996..0x2998: register 6 + 0x2996..0x2998: register rbp stack (local) type: > Pointer (8 bytes) > Unknown - 0x260d..0x272f: register 15 - 0x272f..0x2735: register 4 - 0x2735..0x2782: register 15 - 0x27e2..0x27f6: register 15 - 0x27f6..0x282b: register 4 - 0x282b..0x2877: register 15 + 0x260d..0x272f: register r15 + 0x272f..0x2735: register rsi + 0x2735..0x2782: register r15 + 0x27e2..0x27f6: register r15 + 0x27f6..0x282b: register rsi + 0x282b..0x2877: register r15 thread_arg (local) type: > Unknown @@ -782,14 +782,14 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" r (local) type: > Unknown - 0x28cd..0x28f1: register 4 + 0x28cd..0x28f1: register rsi 0x28f1..0x28f7: frame base -144 - 0x28f7..0x291d: register 4 - 0x293f..0x294b: register 4 + 0x28f7..0x291d: register rsi + 0x293f..0x294b: register rsi success (local) type: > Primitive: bool (Boolean, 1 byte) - 0x291d..0x293a: register 6 + 0x291d..0x293a: register rbp > 0x2534: _ZNK15google_breakpad16ExceptionHandler14IsOutOfProcessEv (0x4) 0x2534: exception_handler.h:205 (../deps/breakpad/src/client/linux/handler) @@ -1022,24 +1022,24 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" sig (parameter) type: > Primitive: int (SignedInt, 4 bytes) - 0x2bd0..0x2c08: register 5 - 0x2c08..0x2c2f: register 12 - 0x2c34..0x2dbf: register 12 + 0x2bd0..0x2c08: register rdi + 0x2c08..0x2c2f: register r12 + 0x2c34..0x2dbf: register r12 info (parameter) type: > Pointer (8 bytes) > Unknown - 0x2bd0..0x2c08: register 4 - 0x2c08..0x2c0d: register 13 - 0x2c34..0x2d43: register 13 - 0x2d88..0x2dae: register 13 + 0x2bd0..0x2c08: register rsi + 0x2c08..0x2c0d: register r13 + 0x2c34..0x2d43: register r13 + 0x2d88..0x2dae: register r13 uc (parameter) type: > Pointer (8 bytes) > Void - 0x2bd0..0x2c08: register 1 - 0x2c08..0x2c33: register 14 - 0x2c34..0x2dbf: register 14 + 0x2bd0..0x2c08: register rdx + 0x2c08..0x2c33: register r14 + 0x2c34..0x2dbf: register r14 cur_handler (local) type: > Unknown @@ -1047,15 +1047,15 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" handled (local) type: > Primitive: bool (Boolean, 1 byte) - 0x2c7f..0x2c8f: register 0 - 0x2ca8..0x2cb5: register 0 - 0x2d88..0x2d99: register 0 + 0x2c7f..0x2c8f: register rax + 0x2ca8..0x2cb5: register rax + 0x2d88..0x2d99: register rax i (local) type: > Primitive: int (SignedInt, 4 bytes) - 0x2c74..0x2ca8: register 3 - 0x2cab..0x2ce7: register 3 - 0x2d88..0x2d9f: register 3 + 0x2c74..0x2ca8: register rbx + 0x2cab..0x2ce7: register rbx + 0x2d88..0x2d9f: register rbx > 0x2c63: _ZNKSt6vectorIPN15google_breakpad16ExceptionHandlerESaIS2_EE4sizeEv (0x3) 0x2c63: stl_vector.h:655 (/usr/include/c++/5/bits) diff --git a/symbolic-debuginfo/tests/snapshots/test_objects__elf_variables_opt.snap b/symbolic-debuginfo/tests/snapshots/test_objects__elf_variables_opt.snap index f176b0de0..5262ee36f 100644 --- a/symbolic-debuginfo/tests/snapshots/test_objects__elf_variables_opt.snap +++ b/symbolic-debuginfo/tests/snapshots/test_objects__elf_variables_opt.snap @@ -27,8 +27,8 @@ expression: "FunctionsDebug::new(&session, &functions)" result (local) type: > Primitive: int (SignedInt, 4 bytes) - 0x1076..0x109c: register 3 - 0x109c..0x10a5: register 0 + 0x1076..0x109c: register rbx + 0x109c..0x10a5: register rax > 0x1240: stack_home (0xc) 0x1240: variables.c:202 (/fixture) @@ -38,7 +38,7 @@ expression: "FunctionsDebug::new(&session, &functions)" a (parameter) type: > Primitive: int (SignedInt, 4 bytes) - 0x1240..0x124c: register 5 + 0x1240..0x124c: register rdi slot (local) type: > Unknown @@ -51,7 +51,7 @@ expression: "FunctionsDebug::new(&session, &functions)" a (parameter) type: > Primitive: int (SignedInt, 4 bytes) - 0x1230..0x1234: register 5 + 0x1230..0x1234: register rdi > 0x1210: external_call (0x20) 0x1210: variables.c:175 (/fixture) @@ -68,16 +68,16 @@ expression: "FunctionsDebug::new(&session, &functions)" a (parameter) type: > Primitive: int (SignedInt, 4 bytes) - 0x1210..0x1224: register 5 - 0x1224..0x122f: register 6 + 0x1210..0x1224: register rdi + 0x1224..0x122f: register rbp kept (local) type: > Primitive: int (SignedInt, 4 bytes) - 0x1220..0x122c: register 3 + 0x1220..0x122c: register rbx r (local) type: > Primitive: int (SignedInt, 4 bytes) - 0x1225..0x122b: register 0 + 0x1225..0x122b: register rax > 0x1200: across_call (0xd) 0x1200: variables.c:162 (/fixture) @@ -88,15 +88,15 @@ expression: "FunctionsDebug::new(&session, &functions)" a (parameter) type: > Primitive: int (SignedInt, 4 bytes) - 0x1200..0x120d: register 5 + 0x1200..0x120d: register rdi doubled (local) type: > Primitive: int (SignedInt, 4 bytes) - 0x1203..0x120d: register 1 + 0x1203..0x120d: register rdx other (local) type: > Primitive: int (SignedInt, 4 bytes) - 0x120a..0x120c: register 0 + 0x120a..0x120c: register rax > 0x11f0: float_registers (0x10) 0x11f0: variables.c:147 (/fixture) @@ -108,19 +108,19 @@ expression: "FunctionsDebug::new(&session, &functions)" a (parameter) type: > Primitive: float (Float, 4 bytes) - 0x11f0..0x11f4: register 17 + 0x11f0..0x11f4: register xmm0 b (parameter) type: > Primitive: float (Float, 4 bytes) - 0x11f0..0x11f8: register 18 + 0x11f0..0x11f8: register xmm1 sum (local) type: > Primitive: float (Float, 4 bytes) - 0x11f4..0x11ff: register 17 + 0x11f4..0x11ff: register xmm0 scaled (local) type: > Primitive: float (Float, 4 bytes) - 0x11f8..0x11fc: register 18 + 0x11f8..0x11fc: register xmm1 > 0x11e0: registers (0x9) 0x11e0: variables.c:134 (/fixture) @@ -131,19 +131,19 @@ expression: "FunctionsDebug::new(&session, &functions)" a (parameter) type: > Primitive: int (SignedInt, 4 bytes) - 0x11e0..0x11e9: register 5 + 0x11e0..0x11e9: register rdi b (parameter) type: > Primitive: int (SignedInt, 4 bytes) - 0x11e0..0x11e6: register 4 + 0x11e0..0x11e6: register rsi sum (local) type: > Primitive: int (SignedInt, 4 bytes) - 0x11e3..0x11e8: register 0 + 0x11e3..0x11e8: register rax product (local) type: > Primitive: int (SignedInt, 4 bytes) - 0x11e6..0x11e9: register 4 + 0x11e6..0x11e9: register rsi > 0x11d0: inlining (0x1) 0x11d0: variables.c:121 (/fixture) @@ -151,7 +151,7 @@ expression: "FunctionsDebug::new(&session, &functions)" outer (parameter) type: > Primitive: int (SignedInt, 4 bytes) - 0x11d0..0x11d1: register 5 + 0x11d0..0x11d1: register rdi > 0x11c0: aggregates (0x1) 0x11c0: variables.c:106 (/fixture) @@ -163,28 +163,28 @@ expression: "FunctionsDebug::new(&session, &functions)" type: > Pointer (8 bytes) > Primitive: int (SignedInt, 4 bytes) - 0x11b0..0x11b1: register 5 + 0x11b0..0x11b1: register rdi num_ptr (parameter) type: > Pointer (8 bytes) > Pointer (8 bytes) > Primitive: int (SignedInt, 4 bytes) - 0x11b0..0x11b1: register 4 + 0x11b0..0x11b1: register rsi str (parameter) type: > Pointer (8 bytes) > Unknown - 0x11b0..0x11b1: register 1 + 0x11b0..0x11b1: register rdx any (parameter) type: > Pointer (8 bytes) > Void - 0x11b0..0x11b1: register 2 + 0x11b0..0x11b1: register rcx fn (parameter) type: > Pointer (8 bytes) > Unknown - 0x11b0..0x11b1: register 8 + 0x11b0..0x11b1: register r8 > 0x11a0: primitives (0x1) 0x11a0: variables.c:68 (/fixture) diff --git a/symbolic-debuginfo/tests/snapshots/test_objects__mach_functions.snap b/symbolic-debuginfo/tests/snapshots/test_objects__mach_functions.snap index 15c865eb8..cbc688717 100644 --- a/symbolic-debuginfo/tests/snapshots/test_objects__mach_functions.snap +++ b/symbolic-debuginfo/tests/snapshots/test_objects__mach_functions.snap @@ -17,7 +17,7 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0xd40..0xd5a: register 5 + 0xd40..0xd5a: register rdi > 0xd40: _ZN15google_breakpad18MinidumpFileWriterC2Ev (0x19) 0xd40: minidump_file_writer.cc:93 (../deps/breakpad/src/client) @@ -65,9 +65,9 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0xde0..0xde4: register 5 - 0xde4..0xe0b: register 3 - 0xe0c..0xe14: register 3 + 0xde0..0xde4: register rdi + 0xde4..0xe0b: register rbx + 0xe0c..0xe14: register rbx > 0xde4: _ZN15google_breakpad18MinidumpFileWriterD2Ev (0x26) 0xde4: minidump_file_writer.cc:100 (../deps/breakpad/src/client) @@ -99,16 +99,16 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0xe20..0xe27: register 5 - 0xe27..0xe49: register 3 - 0xe4a..0xe69: register 3 + 0xe20..0xe27: register rdi + 0xe27..0xe49: register rbx + 0xe4a..0xe69: register rbx path (parameter) type: > Pointer (8 bytes) > Unknown - 0xe20..0xe24: register 4 - 0xe24..0xe40: register 2 - 0xe4a..0xe5f: register 2 + 0xe20..0xe24: register rsi + 0xe24..0xe40: register rcx + 0xe4a..0xe5f: register rcx > 0xe70: _ZN15google_breakpad18MinidumpFileWriter7SetFileEi (0x2d) 0xe70: minidump_file_writer.cc:116 (../deps/breakpad/src/client) @@ -121,7 +121,7 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0xe70..0xe85: register 5 + 0xe70..0xe85: register rdi > 0xea0: _ZN15google_breakpad18MinidumpFileWriter20CopyStringToMDStringEPKwjPNS_10TypedMDRVAI8MDStringEE (0x147) 0xea0: minidump_file_writer.cc:150 (../deps/breakpad/src/client) @@ -146,22 +146,22 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0xea0..0xed2: register 5 + 0xea0..0xed2: register rdi str (parameter) type: > Pointer (8 bytes) > Unknown - 0xea0..0xeb6: register 4 - 0xeb6..0xf23: register 3 - 0xf76..0xf94: register 3 - 0xfa9..0xfe7: register 3 + 0xea0..0xeb6: register rsi + 0xeb6..0xf23: register rbx + 0xf76..0xf94: register rbx + 0xfa9..0xfe7: register rbx mdstring (parameter) type: > Pointer (8 bytes) > Unknown - 0xea0..0xeb1: register 2 - 0xeb1..0xf41: register 12 - 0xfa9..0xfe7: register 12 + 0xea0..0xeb1: register rcx + 0xeb1..0xf41: register r12 + 0xfa9..0xfe7: register r12 out (local) type: > Unknown @@ -169,7 +169,7 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" out_size (local) type: > Unknown - 0xf23..0xf72: register 3 + 0xf23..0xf72: register rbx > 0xefa: _ZN15google_breakpad10TypedMDRVAI8MDStringE20CopyIndexAfterObjectEjPKvm (0x25) 0xefa: minidump_file_writer-inl.h:83 (../deps/breakpad/src/client) @@ -222,21 +222,21 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0xff0..0x1023: register 5 + 0xff0..0x1023: register rdi str (parameter) type: > Pointer (8 bytes) > Unknown - 0xff0..0x1006: register 4 - 0x1006..0x10ef: register 3 - 0x10f9..0x1137: register 3 + 0xff0..0x1006: register rsi + 0x1006..0x10ef: register rbx + 0x10f9..0x1137: register rbx mdstring (parameter) type: > Pointer (8 bytes) > Unknown - 0xff0..0x1001: register 2 - 0x1001..0x107b: register 14 - 0x10f9..0x1137: register 14 + 0xff0..0x1001: register rcx + 0x1001..0x107b: register r14 + 0x10f9..0x1137: register r14 out (local) type: > Unknown @@ -244,7 +244,7 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" out_size (local) type: > Unknown - 0x106b..0x10b7: register 6 + 0x106b..0x10b7: register rbp > 0x1049: _ZN15google_breakpad10TypedMDRVAI8MDStringE20CopyIndexAfterObjectEjPKvm (0x1e) 0x1049: minidump_file_writer-inl.h:83 (../deps/breakpad/src/client) @@ -283,14 +283,14 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0x1140..0x1145: register 5 + 0x1140..0x1145: register rdi str (parameter) type: > Pointer (8 bytes) > Unknown - 0x1140..0x1145: register 4 + 0x1140..0x1145: register rsi location (parameter) type: > Pointer (8 bytes) > Unknown - 0x1140..0x1145: register 2 + 0x1140..0x1145: register rcx diff --git a/symbolic-debuginfo/tests/snapshots/test_objects__pe_dwarf_functions.snap b/symbolic-debuginfo/tests/snapshots/test_objects__pe_dwarf_functions.snap index 4feafa6c9..842f5280f 100644 --- a/symbolic-debuginfo/tests/snapshots/test_objects__pe_dwarf_functions.snap +++ b/symbolic-debuginfo/tests/snapshots/test_objects__pe_dwarf_functions.snap @@ -11,7 +11,7 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" func (parameter) type: > Unknown - 0x14f0..0x14f8: register 2 + 0x14f0..0x14f8: register rcx > 0x1180: __tmainCRTStartup (0x326) 0x1180: crtexe.c:223 (/mxe/tmp-gcc-x86_64-w64-mingw32.static/gcc-11.3.0.build_/mingw-w64-v10.0.0/mingw-w64-crt/crt) @@ -105,7 +105,7 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0x1291..0x12fd: register 0 + 0x1291..0x12fd: register rax StartupInfo (local) type: > Unknown @@ -113,28 +113,28 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" inDoubleQuote (local) type: > Unknown - 0x1298..0x12a7: register 2 - 0x12ae..0x12c8: register 2 + 0x1298..0x12a7: register rcx + 0x12ae..0x12c8: register rcx lock_free (local) type: > Pointer (8 bytes) > Void - 0x11d3..0x11e8: register 0 - 0x11f1..0x1201: register 0 - 0x13f2..0x1406: register 0 + 0x11d3..0x11e8: register rax + 0x11f1..0x1201: register rax + 0x13f2..0x1406: register rax fiberid (local) type: > Pointer (8 bytes) > Void - 0x11c8..0x11fd: register 4 - 0x13f2..0x13ff: register 4 + 0x11c8..0x11fd: register rsi + 0x13f2..0x13ff: register rsi nested (local) type: > Primitive: int (SignedInt, 4 bytes) - 0x11ff..0x1315: register 6 - 0x13e3..0x13f2: register 6 - 0x1404..0x144f: register 6 - 0x147b..0x149e: register 6 + 0x11ff..0x1315: register rbp + 0x13e3..0x13f2: register rbp + 0x1404..0x144f: register rbp + 0x147b..0x149e: register rbp > 0x11b4: NtCurrentTeb (0x10) 0x11b4: winnt.h:9094 (/mxe/usr/x86_64-w64-mingw32.static/include) @@ -182,7 +182,7 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" ret (local) type: > Primitive: int (SignedInt, 4 bytes) - 0x14e6..0x14ed: register 0 + 0x14e6..0x14ed: register rax > 0x14b0: WinMainCRTStartup (0x1d) 0x14b0: crtexe.c:170 (/mxe/tmp-gcc-x86_64-w64-mingw32.static/gcc-11.3.0.build_/mingw-w64-v10.0.0/mingw-w64-crt/crt) @@ -194,7 +194,7 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" ret (local) type: > Primitive: int (SignedInt, 4 bytes) - 0x14c6..0x14cd: register 0 + 0x14c6..0x14cd: register rax > 0x1130: pre_cpp_init (0x49) 0x1130: crtexe.c:155 (/mxe/tmp-gcc-x86_64-w64-mingw32.static/gcc-11.3.0.build_/mingw-w64-v10.0.0/mingw-w64-crt/crt) @@ -254,21 +254,21 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0x1000..0x1001: register 2 + 0x1000..0x1001: register rcx function (parameter) type: > Pointer (8 bytes) > Unknown - 0x1000..0x1001: register 1 + 0x1000..0x1001: register rdx file (parameter) type: > Pointer (8 bytes) > Unknown - 0x1000..0x1001: register 8 + 0x1000..0x1001: register r8 line (parameter) type: > Primitive: unsigned int (UnsignedInt, 4 bytes) - 0x1000..0x1001: register 9 + 0x1000..0x1001: register r9 pReserved (parameter) type: > Unknown @@ -283,13 +283,13 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" argc (parameter) type: > Primitive: int (SignedInt, 4 bytes) - 0x1572..0x157a: register 2 + 0x1572..0x157a: register rcx argv (parameter) type: > Pointer (8 bytes) > Pointer (8 bytes) > Primitive: char (SignedChar, 1 byte) - 0x1572..0x157a: register 1 + 0x1572..0x157a: register rdx > 0x1530: printf (0x42) 0x1530: stdio.h:369 (/mxe/usr/x86_64-w64-mingw32.static/include) @@ -303,12 +303,12 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0x1530..0x1557: register 2 - 0x1557..0x1570: register 3 + 0x1530..0x1557: register rcx + 0x1557..0x1570: register rbx __retval (local) type: > Primitive: int (SignedInt, 4 bytes) - 0x156b..0x1572: register 0 + 0x156b..0x1572: register rax __local_argv (local) type: > Pointer (8 bytes) diff --git a/symbolic-debuginfo/tests/snapshots/test_objects__pe_dwarf_msys2_qglib_functions.snap b/symbolic-debuginfo/tests/snapshots/test_objects__pe_dwarf_msys2_qglib_functions.snap index eea29627c..95a0c700b 100644 --- a/symbolic-debuginfo/tests/snapshots/test_objects__pe_dwarf_msys2_qglib_functions.snap +++ b/symbolic-debuginfo/tests/snapshots/test_objects__pe_dwarf_msys2_qglib_functions.snap @@ -117,23 +117,23 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" hDllHandle (parameter) type: > Unknown - 0x11e0..0x11f6: register 2 - 0x11f6..0x12b8: register 5 + 0x11e0..0x11f6: register rcx + 0x11f6..0x12b8: register rdi dwReason (parameter) type: > Unknown - 0x11e0..0x11f6: register 1 - 0x11f6..0x12c9: register 3 + 0x11e0..0x11f6: register rdx + 0x11f6..0x12c9: register rbx lpreserved (parameter) type: > Unknown - 0x11e0..0x11f6: register 8 - 0x11f6..0x12bf: register 4 + 0x11e0..0x11f6: register r8 + 0x11f6..0x12bf: register rsi retcode (local) type: > Unknown - 0x121d..0x1223: register 0 - 0x1259..0x1288: register 14 + 0x121d..0x1223: register rax + 0x1259..0x1288: register r14 > 0x123c: _CRT_INIT (0x5) 0x123c: mingw-w64/mingw-w64-crt/crt/crtdll.c:129 (D:/W/B/src) @@ -183,8 +183,8 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" func (parameter) type: > Unknown - 0x1350..0x135a: register 2 - 0x135a..0x135f: register 1 + 0x1350..0x135a: register rcx + 0x135a..0x135f: register rdx > 0x1360: _Z13lcNetInfoGlibv (0x60) 0x1360: qtbase-everywhere-src-6.10.1/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp:17 (D:/W/B/src) @@ -339,8 +339,8 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0x13e4..0x13f8: register 2 - 0x13f8..0x14cc: register 4 + 0x13e4..0x13f8: register rcx + 0x13f8..0x14cc: register rsi > 0x13f0: _ZN26QNetworkInformationBackendC2Ev (0x15) 0x13f0: qtbase-everywhere-src-6.10.1/src/network/kernel/qnetworkinformation_p.h:47 (D:/W/B/src) @@ -365,13 +365,13 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0x14d4..0x14fd: register 2 - 0x14fd..0x15f2: register 4 - 0x15fb..0x1601: register 4 + 0x14d4..0x14fd: register rcx + 0x14fd..0x15f2: register rsi + 0x15fb..0x1601: register rsi connectivityState (local) type: > Unknown - 0x1505..0x15ac: register 5 + 0x1505..0x15ac: register rdi > 0x1505: _ZN12_GLOBAL__N_136reachabilityFromGNetworkConnectivityE20GNetworkConnectivity (0x16) 0x1505: qtbase-everywhere-src-6.10.1/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp:22 (D:/W/B/src) @@ -464,9 +464,9 @@ expression: "FunctionsDebug::new(&session, &functions[..10])" type: > Pointer (8 bytes) > Unknown - 0x1614..0x1637: register 2 - 0x1637..0x167f: register 4 - 0x1687..0x16a7: register 4 + 0x1614..0x1637: register rcx + 0x1637..0x167f: register rsi + 0x1687..0x16a7: register rsi > 0x1645: _ZN26QNetworkInformationBackend10setMeteredEb (0x42) 0x1645: qtbase-everywhere-src-6.10.1/src/network/kernel/qnetworkinformation_p.h:116 (D:/W/B/src) diff --git a/symbolic-debuginfo/tests/test_objects.rs b/symbolic-debuginfo/tests/test_objects.rs index f72b690e2..ccab4c2db 100644 --- a/symbolic-debuginfo/tests/test_objects.rs +++ b/symbolic-debuginfo/tests/test_objects.rs @@ -122,9 +122,9 @@ impl fmt::Debug for FunctionsDebug<'_, '_> { for location in &variable.locations { match location.location { - VariableLocation::Register { id } => writeln!( + VariableLocation::Register(register) => writeln!( f, - "{:indent$} {:#x}..{:#x}: register {id}", + "{:indent$} {:#x}..{:#x}: register {register}", "", location.address, location.address.saturating_add(location.size), diff --git a/symbolic-symcache/src/v9/convert.rs b/symbolic-symcache/src/v9/convert.rs index 945be2263..d33ff5ef1 100644 --- a/symbolic-symcache/src/v9/convert.rs +++ b/symbolic-symcache/src/v9/convert.rs @@ -1,3 +1,4 @@ +use symbolic_common::{CpuFamily, Register}; use symbolic_debuginfo::{PrimitiveTypeEncoding, VariableKind}; /// Converts a `u8` back into a [`PrimitiveTypeEncoding`]. @@ -59,3 +60,17 @@ pub fn variable_kind_to_u8(kind: VariableKind) -> u8 { VariableKind::Local => 1, } } + +/// Converts a [`Register`] into a `u16` to be stored in [`RegisterLocation::id`]. +/// +/// [`RegisterLocation::id`]: crate::v9::raw::RegisterLocation::id +pub fn register_to_u16(register: Register) -> u16 { + register.to_dwarf() +} + +/// Converts a `u16` back into a [`Register`] of the given CPU family. +/// +/// The inverse of [`register_to_u16`]. Invalid inputs are returned as `None`. +pub fn u16_to_register(cpu_family: CpuFamily, id: u16) -> Option { + Register::from_dwarf(cpu_family, id) +} diff --git a/symbolic-symcache/src/v9/lookup.rs b/symbolic-symcache/src/v9/lookup.rs index 91378ecb8..a69bc713a 100644 --- a/symbolic-symcache/src/v9/lookup.rs +++ b/symbolic-symcache/src/v9/lookup.rs @@ -2,7 +2,7 @@ use std::cell::Cell; use std::cmp::Ordering; use std::collections::HashSet; -use symbolic_common::Language; +use symbolic_common::{Arch, CpuFamily, Language}; use crate::v9::{SymCache, convert, raw}; use crate::{ @@ -368,6 +368,7 @@ impl<'data, 'cache> Variable<'data, 'cache> { VariableLocations { locations: locations.iter(), + cpu_family: Arch::from_u32(self.cache.header.arch).cpu_family(), addr: self.addr, } } @@ -376,6 +377,7 @@ impl<'data, 'cache> Variable<'data, 'cache> { #[derive(Debug, Clone)] pub struct VariableLocations<'data> { locations: std::slice::Iter<'data, raw::VariableLocationInfo>, + cpu_family: CpuFamily, addr: u32, } @@ -392,7 +394,13 @@ impl<'data> Iterator for VariableLocations<'data> { if self.addr < location.start + location.size { let vl = match location.location() { Some(raw::location::Enum::register(reg)) => { - VariableLocation::Register { id: reg.id } + match convert::u16_to_register(self.cpu_family, reg.id) { + Some(register) => VariableLocation::Register(register), + None => { + debug_assert!(false, "invalid variable register"); + continue; + } + } } Some(raw::location::Enum::frame_offset(fo)) => VariableLocation::FrameOffset { offset: fo.offset.into(), diff --git a/symbolic-symcache/src/writer.rs b/symbolic-symcache/src/writer.rs index 93f8156e4..2c9a9b152 100644 --- a/symbolic-symcache/src/writer.rs +++ b/symbolic-symcache/src/writer.rs @@ -523,8 +523,8 @@ impl<'a> SymCacheConverter<'a> { } let raw_loc: v9::raw::location::Enum = match location.location { - di::VariableLocation::Register { id } => v9::raw::RegisterLocation { - id, + di::VariableLocation::Register(register) => v9::raw::RegisterLocation { + id: v9::convert::register_to_u16(register), _reserved: [0; _], } .into(), diff --git a/symbolic-symcache/tests/test_cache.rs b/symbolic-symcache/tests/test_cache.rs index 8c2d022dd..c94de5126 100644 --- a/symbolic-symcache/tests/test_cache.rs +++ b/symbolic-symcache/tests/test_cache.rs @@ -57,8 +57,8 @@ impl fmt::Debug for VariablesDebug<'_, '_> { let end = location.address + location.size; match location.location { - VariableLocation::Register { id } => { - write!(f, "{:#x}..{end:#x} register {id}", location.address)?; + VariableLocation::Register(register) => { + write!(f, "{:#x}..{end:#x} register {register}", location.address)?; } VariableLocation::FrameOffset { offset } => { write!(f, "{:#x}..{end:#x} frame {offset}", location.address)?; @@ -185,40 +185,40 @@ fn test_lookup_variables_linux() -> Result<(), Error> { let symcache = SymCache::parse(&buffer)?; let source_location = symcache.lookup(0xfe50).last().unwrap(); - insta::assert_debug_snapshot!(VariablesDebug(&symcache, source_location.variables()), @r#" - this (parameter, ): 0xfe50..0xfe86 register 5 - str (parameter, *): 0xfe50..0xfe86 register 4 - length (parameter, unsigned int): 0xfe50..0xfe86 register 1 - mdstring (parameter, *): 0xfe50..0xfe86 register 2 + insta::assert_debug_snapshot!(VariablesDebug(&symcache, source_location.variables()), @r" + this (parameter, ): 0xfe50..0xfe86 register rdi + str (parameter, *): 0xfe50..0xfe86 register rsi + length (parameter, unsigned int): 0xfe50..0xfe86 register rdx + mdstring (parameter, *): 0xfe50..0xfe86 register rcx result (local, bool): out (local, ): 0xfe50..0xff4c frame -80 out_idx (local, int): out_count (local, int): - "#); + "); let source_location = symcache.lookup(0xfe90).last().unwrap(); - insta::assert_debug_snapshot!(VariablesDebug(&symcache, source_location.variables()), @r#" + insta::assert_debug_snapshot!(VariablesDebug(&symcache, source_location.variables()), @r" this (parameter, ): - str (parameter, *): 0xfe86..0xff02 register 6 - length (parameter, unsigned int): 0xfe86..0xff02 register 3 - mdstring (parameter, *): 0xfe86..0xff02 register 13 + str (parameter, *): 0xfe86..0xff02 register rbp + length (parameter, unsigned int): 0xfe86..0xff02 register rbx + mdstring (parameter, *): 0xfe86..0xff02 register r13 result (local, bool): out (local, ): 0xfe50..0xff4c frame -80 - out_idx (local, int): 0xfe86..0xfed9 register 12 + out_idx (local, int): 0xfe86..0xfed9 register r12 out_count (local, int): - "#); + "); let source_location = symcache.lookup(0xfecb).last().unwrap(); - insta::assert_debug_snapshot!(VariablesDebug(&symcache, source_location.variables()), @r#" + insta::assert_debug_snapshot!(VariablesDebug(&symcache, source_location.variables()), @r" this (parameter, ): - str (parameter, *): 0xfe86..0xff02 register 6 - length (parameter, unsigned int): 0xfe86..0xff02 register 3 - mdstring (parameter, *): 0xfe86..0xff02 register 13 + str (parameter, *): 0xfe86..0xff02 register rbp + length (parameter, unsigned int): 0xfe86..0xff02 register rbx + mdstring (parameter, *): 0xfe86..0xff02 register r13 result (local, bool): out (local, ): 0xfe50..0xff4c frame -80 - out_idx (local, int): 0xfe86..0xfed9 register 12 - out_count (local, int): 0xfecb..0xfeee register 15 - "#); + out_idx (local, int): 0xfe86..0xfed9 register r12 + out_count (local, int): 0xfecb..0xfeee register r15 + "); Ok(()) } @@ -254,31 +254,31 @@ fn test_lookup_variables_macos() -> Result<(), Error> { let symcache = SymCache::parse(&buffer)?; let source_location = symcache.lookup(0xea0).last().unwrap(); - insta::assert_debug_snapshot!(VariablesDebug(&symcache, source_location.variables()), @r#" - this (parameter, *): 0xea0..0xed2 register 5 - str (parameter, *): 0xea0..0xeb6 register 4 - mdstring (parameter, *): 0xea0..0xeb1 register 2 + insta::assert_debug_snapshot!(VariablesDebug(&symcache, source_location.variables()), @r" + this (parameter, *): 0xea0..0xed2 register rdi + str (parameter, *): 0xea0..0xeb6 register rsi + mdstring (parameter, *): 0xea0..0xeb1 register rcx out (local, ): 0xea0..0xfe7 frame 16 out_size (local, ): - "#); + "); let source_location = symcache.lookup(0xeb2).last().unwrap(); - insta::assert_debug_snapshot!(VariablesDebug(&symcache, source_location.variables()), @r#" - this (parameter, *): 0xea0..0xed2 register 5 - str (parameter, *): 0xea0..0xeb6 register 4 - mdstring (parameter, *): 0xeb1..0xf41 register 12 + insta::assert_debug_snapshot!(VariablesDebug(&symcache, source_location.variables()), @r" + this (parameter, *): 0xea0..0xed2 register rdi + str (parameter, *): 0xea0..0xeb6 register rsi + mdstring (parameter, *): 0xeb1..0xf41 register r12 out (local, ): 0xea0..0xfe7 frame 16 out_size (local, ): - "#); + "); let source_location = symcache.lookup(0xed2).last().unwrap(); - insta::assert_debug_snapshot!(VariablesDebug(&symcache, source_location.variables()), @r#" + insta::assert_debug_snapshot!(VariablesDebug(&symcache, source_location.variables()), @r" this (parameter, *): - str (parameter, *): 0xeb6..0xf23 register 3 - mdstring (parameter, *): 0xeb1..0xf41 register 12 + str (parameter, *): 0xeb6..0xf23 register rbx + mdstring (parameter, *): 0xeb1..0xf41 register r12 out (local, ): 0xea0..0xfe7 frame 16 out_size (local, ): - "#); + "); Ok(()) } From ee863d09d9d4806b683bd9e5fac464be5f5682c0 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 29 Oct 2026 17:56:10 +0000 Subject: [PATCH 02/13] meta: add changelog PR link Co-Authored-By: Dr. Daniel Szokenstein <7881302+szokeasaurusrex@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10ece18f7..57c95dc52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Breaking Changes** - Change `symbolic_debuginfo::PointerType::pointee` from `TypeRef` to `Option`. ([#1100](https://github.com/getsentry/symbolic/pull/1100)) -- Change `VariableLocation::Register` from `Register { id: u16 }` (raw DWARF register number) to `Register(symbolic_common::Register)`. Only x86-64 registers are supported for now; register locations of other architectures are omitted. `DwarfDebugSession::parse` takes the object's `CpuFamily` as an additional argument. ([#PR](https://github.com/getsentry/symbolic/pull/PR)) +- Change `VariableLocation::Register` from `Register { id: u16 }` (raw DWARF register number) to `Register(symbolic_common::Register)`. Only x86-64 registers are supported for now; register locations of other architectures are omitted. `DwarfDebugSession::parse` takes the object's `CpuFamily` as an additional argument. ([#1117](https://github.com/getsentry/symbolic/pull/1117)) **Features** From 80d5e52786d29e18e46edd64e95d8ae4c3b2c9da Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 09:06:25 +0000 Subject: [PATCH 03/13] ref(variables): Address review feedback --- CHANGELOG.md | 2 +- examples/addr2line/src/main.rs | 2 +- symbolic-common/src/register.rs | 11 ++--------- symbolic-debuginfo/src/base/variable.rs | 5 ++++- symbolic-debuginfo/src/dwarf/mod.rs | 2 +- symbolic-debuginfo/src/function_builder.rs | 10 ++++++---- symbolic-debuginfo/tests/test_objects.rs | 2 +- symbolic-symcache/src/v9/lookup.rs | 12 +++++------- symbolic-symcache/src/writer.rs | 2 +- symbolic-symcache/tests/test_cache.rs | 2 +- 10 files changed, 23 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57c95dc52..c6096b601 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Breaking Changes** - Change `symbolic_debuginfo::PointerType::pointee` from `TypeRef` to `Option`. ([#1100](https://github.com/getsentry/symbolic/pull/1100)) -- Change `VariableLocation::Register` from `Register { id: u16 }` (raw DWARF register number) to `Register(symbolic_common::Register)`. Only x86-64 registers are supported for now; register locations of other architectures are omitted. `DwarfDebugSession::parse` takes the object's `CpuFamily` as an additional argument. ([#1117](https://github.com/getsentry/symbolic/pull/1117)) +- Change `VariableLocation::Register` from `Register { id: u16 }` (raw DWARF register number) to `Register { register: symbolic_common::Register }`. Only x86-64 registers are supported for now; register locations of other architectures are omitted. `DwarfDebugSession::parse` takes the object's `CpuFamily` as an additional argument. ([#1117](https://github.com/getsentry/symbolic/pull/1117)) **Features** diff --git a/examples/addr2line/src/main.rs b/examples/addr2line/src/main.rs index ac502e05c..d067e9021 100644 --- a/examples/addr2line/src/main.rs +++ b/examples/addr2line/src/main.rs @@ -114,7 +114,7 @@ fn resolve( for location in locations { print!(" location: "); match location.location { - VariableLocation::Register(register) => print!("reg:{register}"), + VariableLocation::Register { register } => print!("reg:{register}"), VariableLocation::FrameOffset { offset } => print!("fbreg:{offset}"), } print_range(location.address, Some(location.size), matches); diff --git a/symbolic-common/src/register.rs b/symbolic-common/src/register.rs index 8120b665b..e4c26ff78 100644 --- a/symbolic-common/src/register.rs +++ b/symbolic-common/src/register.rs @@ -1,7 +1,4 @@ //! Architecture specific register definitions. -//! -//! Registers are identified by symbolic's own types rather than by the numbering of a particular -//! debug format, so that the same register can be named independently of where it was read from. use std::fmt; @@ -28,7 +25,7 @@ macro_rules! registers { /// Returns the register with the given DWARF register number. /// /// Returns `None` for numbers which are not a register, such as reserved numbers. - pub fn from_dwarf(number: u16) -> Option { + fn from_dwarf(number: u16) -> Option { match number { $($dwarf => Some(Self::$variant),)* _ => None, @@ -38,7 +35,7 @@ macro_rules! registers { /// Returns the DWARF register number of this register. /// /// The number of a register is fixed and will not change. - pub fn to_dwarf(self) -> u16 { + fn to_dwarf(self) -> u16 { match self { $(Self::$variant => $dwarf,)* } @@ -66,10 +63,6 @@ registers! { /// `rflags`, the segment registers, a few system and control registers, `k0` to `k7` (vector /// masks), and the AMX registers `tmm0` to `tmm7` and `tilecfg`. /// - /// The variants themselves are independent of the register numbering of any debug format, - /// use [`Amd64Register::from_dwarf`] and [`Amd64Register::to_dwarf`] to convert from and to - /// DWARF register numbers. - /// /// [psabi]: https://gitlab.com/x86-psabis/x86-64-ABI pub enum Amd64Register { Rax = { name: "rax", dwarf: 0 }, diff --git a/symbolic-debuginfo/src/base/variable.rs b/symbolic-debuginfo/src/base/variable.rs index 868e90f18..8b91f4100 100644 --- a/symbolic-debuginfo/src/base/variable.rs +++ b/symbolic-debuginfo/src/base/variable.rs @@ -161,7 +161,10 @@ impl fmt::Debug for VariableLocationInfo { #[derive(Debug, Clone)] pub enum VariableLocation { /// The variable can be found in a register. - Register(Register), + Register { + /// The register. + register: Register, + }, /// The variable can be found at an offset relative to the function's frame base. FrameOffset { /// The signed offset from the frame base. diff --git a/symbolic-debuginfo/src/dwarf/mod.rs b/symbolic-debuginfo/src/dwarf/mod.rs index ad5a2a6b5..16d2755f7 100644 --- a/symbolic-debuginfo/src/dwarf/mod.rs +++ b/symbolic-debuginfo/src/dwarf/mod.rs @@ -1473,7 +1473,7 @@ impl<'d, 'a> DwarfUnit<'d, 'a> { match op { Operation::Register { register } => { Register::from_dwarf(self.inner.info.cpu_family, register.0) - .map(VariableLocation::Register) + .map(|register| VariableLocation::Register { register }) } Operation::FrameOffset { offset } => Some(VariableLocation::FrameOffset { offset }), // Currently more operations are not supported. diff --git a/symbolic-debuginfo/src/function_builder.rs b/symbolic-debuginfo/src/function_builder.rs index 5a1bb4d4a..d50cbb4a7 100644 --- a/symbolic-debuginfo/src/function_builder.rs +++ b/symbolic-debuginfo/src/function_builder.rs @@ -682,7 +682,9 @@ mod tests { locations: vec![VariableLocationInfo { address: 0x10, size: 0x40, - location: VariableLocation::Register(Register::Amd64(Amd64Register::Rax)), + location: VariableLocation::Register { + register: Register::Amd64(Amd64Register::Rax), + }, }], }; @@ -742,11 +744,11 @@ mod tests { VariableLocationInfo { address: 0x20, size: 0x10, - location: Register( - Amd64( + location: Register { + register: Amd64( Rax, ), - ), + }, }, ], }, diff --git a/symbolic-debuginfo/tests/test_objects.rs b/symbolic-debuginfo/tests/test_objects.rs index ccab4c2db..0c329b59c 100644 --- a/symbolic-debuginfo/tests/test_objects.rs +++ b/symbolic-debuginfo/tests/test_objects.rs @@ -122,7 +122,7 @@ impl fmt::Debug for FunctionsDebug<'_, '_> { for location in &variable.locations { match location.location { - VariableLocation::Register(register) => writeln!( + VariableLocation::Register { register } => writeln!( f, "{:indent$} {:#x}..{:#x}: register {register}", "", diff --git a/symbolic-symcache/src/v9/lookup.rs b/symbolic-symcache/src/v9/lookup.rs index a69bc713a..e41addd54 100644 --- a/symbolic-symcache/src/v9/lookup.rs +++ b/symbolic-symcache/src/v9/lookup.rs @@ -394,13 +394,11 @@ impl<'data> Iterator for VariableLocations<'data> { if self.addr < location.start + location.size { let vl = match location.location() { Some(raw::location::Enum::register(reg)) => { - match convert::u16_to_register(self.cpu_family, reg.id) { - Some(register) => VariableLocation::Register(register), - None => { - debug_assert!(false, "invalid variable register"); - continue; - } - } + let Some(register) = convert::u16_to_register(self.cpu_family, reg.id) + else { + continue; + }; + VariableLocation::Register { register } } Some(raw::location::Enum::frame_offset(fo)) => VariableLocation::FrameOffset { offset: fo.offset.into(), diff --git a/symbolic-symcache/src/writer.rs b/symbolic-symcache/src/writer.rs index 2c9a9b152..de7109d87 100644 --- a/symbolic-symcache/src/writer.rs +++ b/symbolic-symcache/src/writer.rs @@ -523,7 +523,7 @@ impl<'a> SymCacheConverter<'a> { } let raw_loc: v9::raw::location::Enum = match location.location { - di::VariableLocation::Register(register) => v9::raw::RegisterLocation { + di::VariableLocation::Register { register } => v9::raw::RegisterLocation { id: v9::convert::register_to_u16(register), _reserved: [0; _], } diff --git a/symbolic-symcache/tests/test_cache.rs b/symbolic-symcache/tests/test_cache.rs index c94de5126..6ed084a39 100644 --- a/symbolic-symcache/tests/test_cache.rs +++ b/symbolic-symcache/tests/test_cache.rs @@ -57,7 +57,7 @@ impl fmt::Debug for VariablesDebug<'_, '_> { let end = location.address + location.size; match location.location { - VariableLocation::Register(register) => { + VariableLocation::Register { register } => { write!(f, "{:#x}..{end:#x} register {register}", location.address)?; } VariableLocation::FrameOffset { offset } => { From 20e09fa8a40c27bc038c65844fa820e63454066c Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 09:15:29 +0000 Subject: [PATCH 04/13] docs(common): Note that DWARF register numbers are architecture dependent --- symbolic-common/src/register.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/symbolic-common/src/register.rs b/symbolic-common/src/register.rs index e4c26ff78..e24092b89 100644 --- a/symbolic-common/src/register.rs +++ b/symbolic-common/src/register.rs @@ -202,7 +202,9 @@ impl Register { /// Returns the DWARF register number of this register. /// - /// The number of a register is fixed and will not change. + /// DWARF register numbers are architecture dependent, so interpreting the number requires + /// knowing the register's CPU family, as in [`Register::from_dwarf`]. The number of a + /// register is fixed and will not change. pub fn to_dwarf(self) -> u16 { match self { Self::Amd64(register) => register.to_dwarf(), From 99ed5312daccc44f34855ae80f11dc8de0c51657 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 09:34:02 +0000 Subject: [PATCH 05/13] meta: Simplify changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6096b601..4b71fbdb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,10 @@ **Breaking Changes** - Change `symbolic_debuginfo::PointerType::pointee` from `TypeRef` to `Option`. ([#1100](https://github.com/getsentry/symbolic/pull/1100)) -- Change `VariableLocation::Register` from `Register { id: u16 }` (raw DWARF register number) to `Register { register: symbolic_common::Register }`. Only x86-64 registers are supported for now; register locations of other architectures are omitted. `DwarfDebugSession::parse` takes the object's `CpuFamily` as an additional argument. ([#1117](https://github.com/getsentry/symbolic/pull/1117)) **Features** +- Represent variable register locations as named registers instead of raw DWARF register numbers. ([#1117](https://github.com/getsentry/symbolic/pull/1117)) - Resolve `void` pointers in variable types as `PointerType` with `pointee` set to `None`. ([#1100](https://github.com/getsentry/symbolic/pull/1100)) - Distinguish `void` pointers from pointers to unknown types in symcaches. ([#1101](https://github.com/getsentry/symbolic/pull/1101)) - WASM: expose `ObjectFile.data()`, which returns a copy of the object's own bytes. For an archive with more than one object, such as a fat Mach-O, each object's bytes form a standalone debug information file that can be parsed or uploaded on its own. ([#1132](https://github.com/getsentry/symbolic/pull/1132)) From 526f57b471957b7103f04737d7d6d4f323ad07de Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Fri, 30 Oct 2026 20:29:19 +0100 Subject: [PATCH 06/13] reduce derives --- symbolic-common/src/register.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/symbolic-common/src/register.rs b/symbolic-common/src/register.rs index e24092b89..9f154f1f0 100644 --- a/symbolic-common/src/register.rs +++ b/symbolic-common/src/register.rs @@ -13,7 +13,6 @@ macro_rules! registers { } ) => { $(#[$enum_meta])* - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum $enum { $( #[doc = concat!("The `", $name, "` register.")] @@ -64,6 +63,7 @@ registers! { /// masks), and the AMX registers `tmm0` to `tmm7` and `tilecfg`. /// /// [psabi]: https://gitlab.com/x86-psabis/x86-64-ABI + #[derive(Debug, Clone, Copy)] pub enum Amd64Register { Rax = { name: "rax", dwarf: 0 }, Rdx = { name: "rdx", dwarf: 1 }, @@ -181,7 +181,7 @@ registers! { } /// A register of any supported architecture. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy)] #[non_exhaustive] pub enum Register { /// An x86-64 register. From 88eb255c508cf5a3eb07ae917af5dc35710bb542 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Tue, 3 Nov 2026 17:42:43 +0100 Subject: [PATCH 07/13] add FromStr implementation --- Cargo.lock | 2 ++ symbolic-common/Cargo.toml | 2 ++ symbolic-common/src/register.rs | 39 +++++++++++++++++++++++++++---- symbolic-common/tests/register.rs | 14 +++++++++++ 4 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 symbolic-common/tests/register.rs diff --git a/Cargo.lock b/Cargo.lock index 34e6c773f..c2efe0868 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2520,11 +2520,13 @@ version = "14.0.0-alpha.5" dependencies = [ "debugid", "memmap2", + "minidump", "serde", "similar-asserts", "stable_deref_trait", "symbolic-testutils", "tempfile", + "thiserror", "uuid", ] diff --git a/symbolic-common/Cargo.toml b/symbolic-common/Cargo.toml index 88d5b426f..84bb24dcf 100644 --- a/symbolic-common/Cargo.toml +++ b/symbolic-common/Cargo.toml @@ -25,11 +25,13 @@ debugid = { workspace = true } stable_deref_trait = { workspace = true } serde = { workspace = true, optional = true } uuid = { workspace = true } +thiserror = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] memmap2 = { workspace = true } [dev-dependencies] +minidump = { workspace = true } symbolic-testutils = { path = "../symbolic-testutils" } tempfile = { workspace = true } similar-asserts = { workspace = true } diff --git a/symbolic-common/src/register.rs b/symbolic-common/src/register.rs index 9f154f1f0..fc78859e1 100644 --- a/symbolic-common/src/register.rs +++ b/symbolic-common/src/register.rs @@ -1,9 +1,18 @@ //! Architecture specific register definitions. -use std::fmt; +use std::fmt::{Display, Formatter, Result as FmtResult}; +use std::str::FromStr; + +use thiserror::Error; use crate::CpuFamily; +/// An error returned when parsing a register name fails. +#[derive(Debug, Error)] +#[error("invalid register")] +#[non_exhaustive] +pub struct InvalidRegisterError; + /// Defines a register enum for an architecture, along with its DWARF register numbers and names. macro_rules! registers { ( @@ -41,13 +50,24 @@ macro_rules! registers { } } - impl fmt::Display for $enum { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + impl Display for $enum { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.write_str(match self { $(Self::$variant => $name,)* }) } } + + impl FromStr for $enum { + type Err = InvalidRegisterError; + + fn from_str(name: &str) -> Result { + match name { + $($name => Ok(Self::$variant),)* + _ => Err(InvalidRegisterError), + } + } + } }; } @@ -62,6 +82,15 @@ registers! { /// `rflags`, the segment registers, a few system and control registers, `k0` to `k7` (vector /// masks), and the AMX registers `tmm0` to `tmm7` and `tilecfg`. /// + /// We can parse the registers from their canonical names via the [`FromStr`] implementation, + /// like so: + /// + /// ```rust + /// # use symbolic_common::Amd64Register; + /// let rax = "rax".parse::().expect("\"rax\" is a valid Amd64 register"); + /// assert!(matches!(rax, Amd64Register::Rax)); + /// ``` + /// /// [psabi]: https://gitlab.com/x86-psabis/x86-64-ABI #[derive(Debug, Clone, Copy)] pub enum Amd64Register { @@ -212,8 +241,8 @@ impl Register { } } -impl fmt::Display for Register { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl Display for Register { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { match self { Self::Amd64(register) => register.fmt(f), } diff --git a/symbolic-common/tests/register.rs b/symbolic-common/tests/register.rs new file mode 100644 index 000000000..2c986abf7 --- /dev/null +++ b/symbolic-common/tests/register.rs @@ -0,0 +1,14 @@ +//! Tests for register types. + +use minidump::CpuContext as _; +use minidump::format::CONTEXT_AMD64; +use symbolic_common::Amd64Register; + +#[test] +fn parses_minidump_amd_64_registers() { + for ®ister in CONTEXT_AMD64::REGISTERS { + register.parse::().unwrap_or_else(|e| { + panic!("Failed to parse minidump register {register:?} to Amd64Register: {e}") + }); + } +} From 8b67a3d83926bfb0f0ab904721200f09954320fb Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Tue, 3 Nov 2026 17:45:12 +0100 Subject: [PATCH 08/13] make registers module public, don't re-export --- symbolic-common/src/lib.rs | 4 ++-- symbolic-common/src/register.rs | 12 ++++++------ symbolic-common/tests/register.rs | 2 +- symbolic-debuginfo/src/base/variable.rs | 2 +- symbolic-debuginfo/src/dwarf/mod.rs | 3 ++- symbolic-debuginfo/src/function_builder.rs | 2 +- symbolic-symcache/src/v9/convert.rs | 3 ++- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/symbolic-common/src/lib.rs b/symbolic-common/src/lib.rs index d48c2a4f3..5005b91a9 100644 --- a/symbolic-common/src/lib.rs +++ b/symbolic-common/src/lib.rs @@ -26,15 +26,15 @@ mod byteview; mod cell; mod heuristics; mod path; -mod register; mod sourcelinks; mod types; +pub mod register; + pub use crate::byteview::*; pub use crate::cell::*; pub use crate::heuristics::*; pub use crate::path::*; -pub use crate::register::*; pub use crate::sourcelinks::*; pub use crate::types::*; diff --git a/symbolic-common/src/register.rs b/symbolic-common/src/register.rs index fc78859e1..a65eb51dd 100644 --- a/symbolic-common/src/register.rs +++ b/symbolic-common/src/register.rs @@ -7,12 +7,6 @@ use thiserror::Error; use crate::CpuFamily; -/// An error returned when parsing a register name fails. -#[derive(Debug, Error)] -#[error("invalid register")] -#[non_exhaustive] -pub struct InvalidRegisterError; - /// Defines a register enum for an architecture, along with its DWARF register numbers and names. macro_rules! registers { ( @@ -254,3 +248,9 @@ impl From for Register { Self::Amd64(register) } } + +/// An error returned when parsing a register name fails. +#[derive(Debug, Error)] +#[error("invalid register")] +#[non_exhaustive] +pub struct InvalidRegisterError; diff --git a/symbolic-common/tests/register.rs b/symbolic-common/tests/register.rs index 2c986abf7..f3e86b8cd 100644 --- a/symbolic-common/tests/register.rs +++ b/symbolic-common/tests/register.rs @@ -2,7 +2,7 @@ use minidump::CpuContext as _; use minidump::format::CONTEXT_AMD64; -use symbolic_common::Amd64Register; +use symbolic_common::register::Amd64Register; #[test] fn parses_minidump_amd_64_registers() { diff --git a/symbolic-debuginfo/src/base/variable.rs b/symbolic-debuginfo/src/base/variable.rs index 8b91f4100..9c7d0d287 100644 --- a/symbolic-debuginfo/src/base/variable.rs +++ b/symbolic-debuginfo/src/base/variable.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, fmt}; -use symbolic_common::Register; +use symbolic_common::register::Register; /// A type reference. /// diff --git a/symbolic-debuginfo/src/dwarf/mod.rs b/symbolic-debuginfo/src/dwarf/mod.rs index 16d2755f7..2b884a3f0 100644 --- a/symbolic-debuginfo/src/dwarf/mod.rs +++ b/symbolic-debuginfo/src/dwarf/mod.rs @@ -25,7 +25,8 @@ use gimli::{ }; use thiserror::Error; -use symbolic_common::{AsSelf, CpuFamily, Language, Name, NameMangling, Register, SelfCell}; +use symbolic_common::register::Register; +use symbolic_common::{AsSelf, CpuFamily, Language, Name, NameMangling, SelfCell}; use crate::base::*; use crate::function_builder::{ diff --git a/symbolic-debuginfo/src/function_builder.rs b/symbolic-debuginfo/src/function_builder.rs index d50cbb4a7..bd1e091ec 100644 --- a/symbolic-debuginfo/src/function_builder.rs +++ b/symbolic-debuginfo/src/function_builder.rs @@ -520,7 +520,7 @@ fn ensure_proper_nesting( #[cfg(test)] mod tests { - use symbolic_common::{Amd64Register, Register}; + use symbolic_common::register::{Amd64Register, Register}; use crate::{VariableKind, VariableLocation, VariableLocationInfo}; diff --git a/symbolic-symcache/src/v9/convert.rs b/symbolic-symcache/src/v9/convert.rs index d33ff5ef1..eb4cc4922 100644 --- a/symbolic-symcache/src/v9/convert.rs +++ b/symbolic-symcache/src/v9/convert.rs @@ -1,4 +1,5 @@ -use symbolic_common::{CpuFamily, Register}; +use symbolic_common::CpuFamily; +use symbolic_common::register::Register; use symbolic_debuginfo::{PrimitiveTypeEncoding, VariableKind}; /// Converts a `u8` back into a [`PrimitiveTypeEncoding`]. From 729799071c32bc9004e8d859c4fe2c7701685024 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 4 Nov 2026 15:18:42 +0100 Subject: [PATCH 09/13] Improvements to make registers usable from symbolicator --- symbolic-common/src/register.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/symbolic-common/src/register.rs b/symbolic-common/src/register.rs index a65eb51dd..55a0c8f96 100644 --- a/symbolic-common/src/register.rs +++ b/symbolic-common/src/register.rs @@ -16,6 +16,7 @@ macro_rules! registers { } ) => { $(#[$enum_meta])* + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum $enum { $( #[doc = concat!("The `", $name, "` register.")] @@ -77,12 +78,12 @@ registers! { /// masks), and the AMX registers `tmm0` to `tmm7` and `tilecfg`. /// /// We can parse the registers from their canonical names via the [`FromStr`] implementation, - /// like so: + /// as shown below. /// /// ```rust /// # use symbolic_common::Amd64Register; /// let rax = "rax".parse::().expect("\"rax\" is a valid Amd64 register"); - /// assert!(matches!(rax, Amd64Register::Rax)); + /// assert_eq!(rax, Amd64Register::Rax); /// ``` /// /// [psabi]: https://gitlab.com/x86-psabis/x86-64-ABI @@ -204,7 +205,7 @@ registers! { } /// A register of any supported architecture. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[non_exhaustive] pub enum Register { /// An x86-64 register. @@ -233,6 +234,14 @@ impl Register { Self::Amd64(register) => register.to_dwarf(), } } + + /// Return a typed register for the given register name and CPU family, if known and available. + pub fn try_from_name(cpu_family: CpuFamily, name: &str) -> Result { + match cpu_family { + CpuFamily::Amd64 => Ok(Self::Amd64(name.parse()?)), + _ => Err(RegisterFromNameError::UnsupportedArchitecture), + } + } } impl Display for Register { @@ -254,3 +263,15 @@ impl From for Register { #[error("invalid register")] #[non_exhaustive] pub struct InvalidRegisterError; + +/// An error returned by [`Register::try_from_name`]. +#[derive(Debug, Error)] +pub enum RegisterFromNameError { + /// The register name could not be parsed for the given architecture. + #[error("could not parse register for architecture: {0}")] + InvalidRegister(#[from] InvalidRegisterError), + + /// We do not support parsing register names for the given CPU family. + #[error("architecture not supported for parsing registers")] + UnsupportedArchitecture, +} From 4ed44933063b4ee0ceb2e6a54d2d2dbea8dfc049 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 4 Nov 2026 15:29:33 +0100 Subject: [PATCH 10/13] fix: fix compile errors --- symbolic-common/src/register.rs | 3 +-- symbolic-debuginfo/src/function_builder.rs | 8 ++++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/symbolic-common/src/register.rs b/symbolic-common/src/register.rs index 55a0c8f96..6f12cd002 100644 --- a/symbolic-common/src/register.rs +++ b/symbolic-common/src/register.rs @@ -81,13 +81,12 @@ registers! { /// as shown below. /// /// ```rust - /// # use symbolic_common::Amd64Register; + /// # use symbolic_common::register::Amd64Register; /// let rax = "rax".parse::().expect("\"rax\" is a valid Amd64 register"); /// assert_eq!(rax, Amd64Register::Rax); /// ``` /// /// [psabi]: https://gitlab.com/x86-psabis/x86-64-ABI - #[derive(Debug, Clone, Copy)] pub enum Amd64Register { Rax = { name: "rax", dwarf: 0 }, Rdx = { name: "rdx", dwarf: 1 }, diff --git a/symbolic-debuginfo/src/function_builder.rs b/symbolic-debuginfo/src/function_builder.rs index bd1e091ec..e993b148c 100644 --- a/symbolic-debuginfo/src/function_builder.rs +++ b/symbolic-debuginfo/src/function_builder.rs @@ -547,7 +547,9 @@ mod tests { locations: vec![VariableLocationInfo { address: 0x10, size: 0x30, - location: VariableLocation::Register { id: 0 }, + location: VariableLocation::Register { + register: Register::Amd64(Amd64Register::Rax), + }, }], }); builder.add_inlinee(FunctionBuilderInlinee { @@ -626,7 +628,9 @@ mod tests { address: 0x10, size: 0x30, location: Register { - id: 0, + register: Amd64( + Rax, + ), }, }, ], From f88420a847fcb89000f24ee4c7c4af729c25cdeb Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 4 Nov 2026 16:00:56 +0100 Subject: [PATCH 11/13] fix changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b71fbdb8..f9ed6fe3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## Unreleased + +**Features** +- Represent variable register locations as named registers instead of raw DWARF register numbers. ([#1117](https://github.com/getsentry/symbolic/pull/1117)) + ## 14.0.0-alpha.5 **Breaking Changes** @@ -8,7 +13,6 @@ **Features** -- Represent variable register locations as named registers instead of raw DWARF register numbers. ([#1117](https://github.com/getsentry/symbolic/pull/1117)) - Resolve `void` pointers in variable types as `PointerType` with `pointee` set to `None`. ([#1100](https://github.com/getsentry/symbolic/pull/1100)) - Distinguish `void` pointers from pointers to unknown types in symcaches. ([#1101](https://github.com/getsentry/symbolic/pull/1101)) - WASM: expose `ObjectFile.data()`, which returns a copy of the object's own bytes. For an archive with more than one object, such as a fat Mach-O, each object's bytes form a standalone debug information file that can be parsed or uploaded on its own. ([#1132](https://github.com/getsentry/symbolic/pull/1132)) From a639c6af8c333a25bc694e5ea574ff73d459fd25 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 4 Nov 2026 17:39:07 +0100 Subject: [PATCH 12/13] ref: Generate `Registers` with macro --- symbolic-common/src/register.rs | 120 ++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 46 deletions(-) diff --git a/symbolic-common/src/register.rs b/symbolic-common/src/register.rs index 6f12cd002..6f7b07c78 100644 --- a/symbolic-common/src/register.rs +++ b/symbolic-common/src/register.rs @@ -8,7 +8,7 @@ use thiserror::Error; use crate::CpuFamily; /// Defines a register enum for an architecture, along with its DWARF register numbers and names. -macro_rules! registers { +macro_rules! define_arch_registers { ( $(#[$enum_meta:meta])* pub enum $enum:ident { @@ -66,7 +66,7 @@ macro_rules! registers { }; } -registers! { +define_arch_registers! { /// An x86-64 register. /// /// The set of registers follows the DWARF register number mapping of the @@ -203,58 +203,86 @@ registers! { } } -/// A register of any supported architecture. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[non_exhaustive] -pub enum Register { - /// An x86-64 register. - Amd64(Amd64Register), -} - -impl Register { - /// Returns the register with the given DWARF register number for the given CPU family. - /// - /// Returns `None` if the CPU family has no register mapping, or if the number is not a - /// register of the CPU family. - pub fn from_dwarf(cpu_family: CpuFamily, number: u16) -> Option { - match cpu_family { - CpuFamily::Amd64 => Amd64Register::from_dwarf(number).map(Self::Amd64), - _ => None, +/// Defines the architecture-independent register type and conversions from a shared CPU-family mapping. +macro_rules! define_register_wrapper { + ( + $( + $(#[$meta:meta])* + $variant:ident($register:ident) => [$($family:path),+ $(,)?] + ),+ $(,)? + ) => { + /// A register of any supported architecture. + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + #[non_exhaustive] + pub enum Register { + $( + $(#[$meta])* + $variant($register), + )+ } - } - /// Returns the DWARF register number of this register. - /// - /// DWARF register numbers are architecture dependent, so interpreting the number requires - /// knowing the register's CPU family, as in [`Register::from_dwarf`]. The number of a - /// register is fixed and will not change. - pub fn to_dwarf(self) -> u16 { - match self { - Self::Amd64(register) => register.to_dwarf(), - } - } + impl Register { + /// Returns the register with the given DWARF register number for the given CPU family. + /// + /// Returns `None` if the CPU family has no register mapping, or if the number is not a + /// register of the CPU family. + pub fn from_dwarf(cpu_family: CpuFamily, number: u16) -> Option { + match cpu_family { + $( + $($family)|+ => { + $register::from_dwarf(number).map(Self::$variant) + } + )+ + _ => None, + } + } + + /// Returns the DWARF register number of this register. + /// + /// DWARF register numbers are architecture dependent, so interpreting the number requires + /// knowing the register's CPU family, as in [`Register::from_dwarf`]. The number of a + /// register is fixed and will not change. + pub fn to_dwarf(self) -> u16 { + match self { + $(Self::$variant(register) => register.to_dwarf(),)+ + } + } - /// Return a typed register for the given register name and CPU family, if known and available. - pub fn try_from_name(cpu_family: CpuFamily, name: &str) -> Result { - match cpu_family { - CpuFamily::Amd64 => Ok(Self::Amd64(name.parse()?)), - _ => Err(RegisterFromNameError::UnsupportedArchitecture), + /// Return a typed register for the given register name and CPU family, if known and available. + pub fn try_from_name( + cpu_family: CpuFamily, + name: &str, + ) -> Result { + match cpu_family { + $( + $($family)|+ => Ok(Self::$variant(name.parse()?)), + )+ + _ => Err(RegisterFromNameError::UnsupportedArchitecture), + } + } } - } -} -impl Display for Register { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - match self { - Self::Amd64(register) => register.fmt(f), + impl Display for Register { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + $(Self::$variant(register) => register.fmt(f),)+ + } + } } - } + + $( + impl From<$register> for Register { + fn from(register: $register) -> Self { + Self::$variant(register) + } + } + )+ + }; } -impl From for Register { - fn from(register: Amd64Register) -> Self { - Self::Amd64(register) - } +define_register_wrapper! { + /// An x86-64 register. + Amd64(Amd64Register) => [CpuFamily::Amd64], } /// An error returned when parsing a register name fails. From e7b125f7c134dbecd9341cd31328bb583053d990 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Wed, 4 Nov 2026 19:14:12 +0100 Subject: [PATCH 13/13] remove error type --- symbolic-common/src/register.rs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/symbolic-common/src/register.rs b/symbolic-common/src/register.rs index 6f7b07c78..219a9581b 100644 --- a/symbolic-common/src/register.rs +++ b/symbolic-common/src/register.rs @@ -252,12 +252,12 @@ macro_rules! define_register_wrapper { pub fn try_from_name( cpu_family: CpuFamily, name: &str, - ) -> Result { + ) -> Option { match cpu_family { $( - $($family)|+ => Ok(Self::$variant(name.parse()?)), + $($family)|+ => Some(Self::$variant(name.parse().ok()?)), )+ - _ => Err(RegisterFromNameError::UnsupportedArchitecture), + _ => None, } } } @@ -290,15 +290,3 @@ define_register_wrapper! { #[error("invalid register")] #[non_exhaustive] pub struct InvalidRegisterError; - -/// An error returned by [`Register::try_from_name`]. -#[derive(Debug, Error)] -pub enum RegisterFromNameError { - /// The register name could not be parsed for the given architecture. - #[error("could not parse register for architecture: {0}")] - InvalidRegister(#[from] InvalidRegisterError), - - /// We do not support parsing register names for the given CPU family. - #[error("architecture not supported for parsing registers")] - UnsupportedArchitecture, -}