195 Commits

Author SHA1 Message Date
Alex Rønne Petersen
0b55393a2f
std.debug: add CPU context and DWARF mappings for ve 2025-10-18 00:36:52 +02:00
Alex Rønne Petersen
a36dab2f90
std.debug.Dwarf: add SPARC register number mappings 2025-10-15 13:59:17 +02:00
Alex Rønne Petersen
b2732645b7
std.debug.cpu_context: add sparc*-linux context conversion support
It's not really a ucontext_t at all. Lovely stuff.
2025-10-15 13:59:17 +02:00
Alex Rønne Petersen
b8dd40fde8
std.debug.cpu_context.Sparc: flush register windows in current()
It's better to do this here than in StackIterator.init() so that
std.debug.cpu_context.Native.current() isn't a footgun on SPARC.
2025-10-15 13:59:17 +02:00
Alex Rønne Petersen
12b1d57df1
std.debug.cpu_context: add Sparc context 2025-10-15 13:59:17 +02:00
Alex Rønne Petersen
f21a78b5a3
std.debug.SelfInfo.Elf: don't support DWARF unwinding for Hexagon and PowerPC
As for SPARC, FP-based unwinding is superior on these.
2025-10-15 13:59:17 +02:00
Alex Rønne Petersen
ea694bfdb7 std.debug.cpu_context: consider arm and aarch64 reserved register ranges unsupported
If these ever get allocated, it's most likely going to be for things that don't
matter to us anyway, so completely abandoning DWARF unwinding just because we
see these doesn't seem justified. We will still do so if we're actually asked to
read from such a register, which is the only actually problematic case; see
c23a5ccd19 for more details.
2025-10-12 12:59:06 +02:00
Alex Rønne Petersen
9aeabad519 std.debug.Dwarf.SelfUnwinder: assume same-value rule by default for all columns
This fixes leaf function unwinding, presumably among other things.
2025-10-10 15:12:27 +02:00
Alex Rønne Petersen
f33d3a5166
std.debug: greatly expand target support for segfault handling/unwinding
I made a couple of decisions for this based on the fact that we don't expose the
signal_ucontext_t type outside of the file:

* Adding all the floating point and vector state to every ucontext_t and
  mcontext_t variant was way, way too much work, especially when we don't even
  use the stuff. So I deleted all that and kept only the bare minimum needed to
  reach into general-purpose registers.
* There is no particularly compelling reason to stick to the naming and struct
  nesting used in the system headers. So we can actually unify the access
  patterns for almost all of these variants by taking some liberties here; as a
  result, fromPosixSignalContext() is now much nicer to read and extend.
2025-10-10 04:43:15 +02:00
Alex Rønne Petersen
2aea7a42b0
Merge pull request #25493 from alexrp/std-debug-mips-ppc
`std.debug`: MIPS and PowerPC unwind support + some other stuff
2025-10-08 06:29:28 +02:00
Alex Rønne Petersen
a54906b46e
std.debug.cpu_context: make arch-specific implementations private 2025-10-07 19:18:46 +02:00
Alex Rønne Petersen
a06db282c7
std.debug.SelfInfo.MachO: don't restore vector registers during unwinding
We know that these are unsupported and irrelevant for unwinding, so don't fail
the unwind attempt trying to read/write them for no ultimate purpose.
2025-10-07 17:13:58 +02:00
Alex Rønne Petersen
e4f0c62b5d
std.debug.Dwarf.expression: fix a test that assumes sp != fp
This does not hold on PowerPC.
2025-10-07 17:03:48 +02:00
Alex Rønne Petersen
7fdd5704ed
std.debug.cpu_context: map a bunch of known registers as unsupported instead of invalid 2025-10-07 16:47:57 +02:00
Alex Rønne Petersen
de3b22db4d
std.debug.cpu_context: remove support for s390x float registers
Let's for the moment assume that compilers haven't lost the plot.

Fingers crossed.
2025-10-07 16:47:57 +02:00
Alex Rønne Petersen
9cd37a0696
std.debug.Dwarf: use 66 as the (fake) MIPS PC register
32-63 conflict with the floating point registers. 64 and 65 are used for the
ac0 hi/lo registers.
2025-10-07 16:47:57 +02:00
Alex Rønne Petersen
f6403ed5ea
std.debug.Dwarf: use 67 as the (fake) PowerPC PC register
It's free real estate, as it turns out.
2025-10-07 16:47:57 +02:00
Alex Rønne Petersen
feba8a83a7
std.debug.Dwarf: use 65 as the (fake) RISC-V PC register
32-63 conflict with the floating point registers. 64 is the Alternate Frame
Return Column.
2025-10-07 16:47:57 +02:00
Alex Rønne Petersen
9a6fad2706
std.debug.Dwarf: use 64 as the (fake) LoongArch PC register
32-63 conflict with the floating point registers.
2025-10-07 16:47:57 +02:00
Alex Rønne Petersen
aa74eb505a
std.debug: add unwind support for powerpc*-linux 2025-10-07 16:47:57 +02:00
Alex Rønne Petersen
ca73d697b9
std.debug: add unwind support for mips*-linux 2025-10-07 16:47:57 +02:00
Alex Rønne Petersen
a5a9ffb90b
std.debug.cpu_context: check for architecture, i.e. register size, not bitness
We care about the hardware here, not the ABI.
2025-10-07 16:47:57 +02:00
Alex Rønne Petersen
081d6d12a1
std.debug.Dwarf.SelfUnwinder: add an s390x check missed in 95bdb0c1c65c128923ffac3f4be6b4619eb4a54b 2025-10-07 16:47:57 +02:00
Alex Rønne Petersen
c23a5ccd19
std.debug.Dwarf.SelfUnwinder: skip caching rules for unsupported registers
For unwinding purposes, we don't care about unsupported registers. Yet because
we added these rules to the cache entry, we'd later try to evaluate them and
thus fail the unwind attempt for no good reason. They'd also take up cache rule
slots that would be better spent on actually relevant registers.

Note that any attempt to read unsupported registers during unwinding will still
fail the unwind attempt as expected.
2025-10-07 09:28:43 +02:00
Alex Rønne Petersen
a5ff376b8f
std.debug: add unwind support for hexagon-linux 2025-10-05 20:09:26 +02:00
Alex Rønne Petersen
30f5258fe6 std.debug.SelfInfo.Elf: disable unwinding on mips n32 and x86 x32
The DWARF code can't handle these yet.

ref https://github.com/ziglang/zig/issues/25447
2025-10-05 07:18:50 +02:00
Linus Groh
b0f280f4a4 std.debug: Add unwind support for serenity 2025-10-03 22:59:40 +01:00
Alex Rønne Petersen
95bdb0c1c6
std.debug.Dwarf.SelfUnwinder: default some s390x registers to the same-value rule 2025-10-03 03:45:52 +02:00
Alex Rønne Petersen
8263f55ab2
std.debug: add s390x-linux unwind support 2025-10-03 03:29:20 +02:00
Alex Rønne Petersen
a4f95b1e61
std.debug.Dwarf.Unwind: deal with invalid def_cfa_reg by GNU toolchains 2025-10-02 15:27:35 +02:00
Alex Rønne Petersen
97de46dc16
std.debug: add riscv32-linux and riscv64-linux unwind support 2025-10-01 23:47:47 +02:00
Alex Rønne Petersen
8520e9312e
std.debug: add loongarch64-linux unwind support 2025-10-01 23:47:47 +02:00
Alex Rønne Petersen
b46867848e
std.debug: some adjustments to target handling
* driverkit handling missing in a few places.
* x86-solaris is a dead target.
* aarch64_be does not exist on Darwin, FreeBSD, Windows.
2025-10-01 23:47:47 +02:00
Alex Rønne Petersen
771410cbf2
std.debug.SelfInfo: rename Darwin to MachO 2025-10-01 23:47:47 +02:00
mlugg
1120546f72
std.debug.SelfInfo: remove shared logic
There were only a few dozen lines of common logic, and they frankly
introduced more complexity than they eliminated. Instead, let's accept
that the implementations of `SelfInfo` are all pretty different and want
to track different state. This probably fixes some synchronization and
memory bugs by simplifying a bunch of stuff. It also improves the DWARF
unwind cache, making it around twice as fast in a debug build with the
self-hosted x86_64 backend, because we no longer have to redundantly go
through the hashmap lookup logic to find the module. Unwinding on
Windows will also see a slight performance boost from this change,
because `RtlVirtualUnwind` does not need to know the module whatsoever,
so the old `SelfInfo` implementation was doing redundant work. Lastly,
this makes it even easier to implement `SelfInfo` on freestanding
targets; there is no longer a need to emulate a real module system,
since the user controls the whole implementation!

There are various other small refactors here in the `SelfInfo`
implementations as well as in the DWARF unwinding logic. This change
turned out to make a lot of stuff simpler!
2025-09-30 14:18:26 +01:00
mlugg
12ceb896fa
Dwarf.Unwind: fix typo 2025-09-30 13:44:56 +01:00
mlugg
a90eb50c80
typo 2025-09-30 13:44:56 +01:00
mlugg
8950831d3c
Dwarf.Unwind: handle macOS deviation from standard
Apparently the `__eh_frame` in Mach-O binaries doesn't include the
terminator entry, but in all other respects it acts like `.eh_frame`
rather than `.debug_frame`. I have no idea.
2025-09-30 13:44:56 +01:00
mlugg
156cd8f678
std.debug: significantly speed up capturing stack traces
By my estimation, these changes speed up DWARF unwinding when using the
self-hosted x86_64 backend by around 7x. There are two very significant
enhancements: we no longer iterate frames which don't fit in the stack
trace buffer, and we cache register rules (in a fixed buffer) to avoid
re-parsing and evaluating CFI instructions in most cases. Alongside this
are a bunch of smaller enhancements, such as pre-caching the result of
evaluating the CIE's initial instructions, avoiding re-parsing of CIEs,
and big simplifications to the `Dwarf.Unwind.VirtualMachine` logic.
2025-09-30 13:44:56 +01:00
mlugg
dbda011ae6
std.debug.SelfInfo: mark ARM unwinding as unsupported
We need to parse the `.ARM.exidx` section to be able to reliably unwind
the stack on ARM.
2025-09-30 13:44:56 +01:00
mlugg
950a9d2a10
typo 2025-09-30 13:44:56 +01:00
mlugg
f7e0ff8a5f
std: clarify cpu_context register order rationale 2025-09-30 13:44:56 +01:00
mlugg
c41bf99684
std.debug: don't assume return address register is defined if not specified
This logic was causing some occasional infinite looping on ARM, where
the `.debug_frame` section is often incomplete since the `.exidx`
section is used for unwind information. But the information we're
getting from the compiler is totally *valid*: it's leaving the rule as
the default, which is (as with most architectures) equivalent to
`.undefined`!
2025-09-30 13:44:55 +01:00
mlugg
099a950410
std.debug.SelfInfo: thread safety
This has been a TODO for ages, but in the past it didn't really matter
because stack traces are typically printed to stderr for which a mutex
is held so in practice there was a mutex guarding usage of `SelfInfo`.

However, now that `SelfInfo` is also used for simply capturing traces,
thread safety is needed. Instead of just a single mutex, though, there
are a couple of different mutexes involved; this helps make critical
sections smaller, particularly when unwinding the stack as `unwindFrame`
doesn't typically need to hold any lock at all.
2025-09-30 13:44:55 +01:00
mlugg
9c1821d3bf
ElfModule: fix assertion failure 2025-09-30 13:44:55 +01:00
mlugg
084e92879a
std: don't get CPU context when using CBE targeting MSVC
Calling `current` here causes compilation failures as the C backend
currently does not emit valid MSVC inline assembly. This change means
that when building for MSVC with the self-hosted C backend, only FP
unwinding can be used.
2025-09-30 13:44:55 +01:00
mlugg
2ab650b481
std.debug: go back to storing return addresses instead of call addresses
...and just deal with signal handlers by adding 1 to create a fake
"return address". The system I tried out where the addresses returned by
`StackIterator` were pre-subtracted didn't play nicely with error
traces, which in hindsight, makes perfect sense. This definition also
removes some ugly off-by-one issues in matching `first_address`, so I do
think this is a better approach.
2025-09-30 13:44:55 +01:00
mlugg
9434bab313
std: work around crash parsing LLVM PDB
This crash exists on master, and seems to have existed since 2019; I
think it's just very rare and depends on the exact binary generated. In
theory, a stream block should always be a "data" block rather than a FPM
block; the FPMs use blocks `1, 4097, 8193, ...` and `2, 4097, 8194, ...`
respectively. However, I have observed LLVM emitting an otherwise valid
PDB which maps FPM blocks into streams. This is not a bug in
`std.debug.Pdb`, because `llvm-pdbutil` agrees with our stream indices.
I think this is arguably an LLVM bug; however, we don't really lose
anything from just weakening this check. To be fair, MSF doesn't have an
explicit specification, and LLVM's documentation (which is the closest
thing we have) does not explicitly state that FPM blocks cannot be
mapped into streams, so perhaps this is actually valid.

In the rare case that LLVM emits this, previously, stack traces would
have been completely useless; now, stack traces will work okay.
2025-09-30 13:44:55 +01:00
mlugg
23d6381e8b
std.debug: fix typo 2025-09-30 13:44:55 +01:00
mlugg
0c24b8ec66
update to new std.debug changes 2025-09-30 13:44:55 +01:00