aboutsummaryrefslogtreecommitdiff
path: root/lib/std/debug
AgeCommit message (Collapse)Author
2025-10-07std.debug.cpu_context: map a bunch of known registers as unsupported instead ↵Alex Rønne Petersen
of invalid
2025-10-07std.debug.cpu_context: remove support for s390x float registersAlex Rønne Petersen
Let's for the moment assume that compilers haven't lost the plot. Fingers crossed.
2025-10-07std.debug.Dwarf: use 66 as the (fake) MIPS PC registerAlex Rønne Petersen
32-63 conflict with the floating point registers. 64 and 65 are used for the ac0 hi/lo registers.
2025-10-07std.debug.Dwarf: use 67 as the (fake) PowerPC PC registerAlex Rønne Petersen
It's free real estate, as it turns out.
2025-10-07std.debug.Dwarf: use 65 as the (fake) RISC-V PC registerAlex Rønne Petersen
32-63 conflict with the floating point registers. 64 is the Alternate Frame Return Column.
2025-10-07std.debug.Dwarf: use 64 as the (fake) LoongArch PC registerAlex Rønne Petersen
32-63 conflict with the floating point registers.
2025-10-07std.debug: add unwind support for powerpc*-linuxAlex Rønne Petersen
2025-10-07std.debug: add unwind support for mips*-linuxAlex Rønne Petersen
2025-10-07std.debug.cpu_context: check for architecture, i.e. register size, not bitnessAlex Rønne Petersen
We care about the hardware here, not the ABI.
2025-10-07std.debug.Dwarf.SelfUnwinder: add an s390x check missed in ↵Alex Rønne Petersen
95bdb0c1c65c128923ffac3f4be6b4619eb4a54b
2025-10-07std.debug.Dwarf.SelfUnwinder: skip caching rules for unsupported registersAlex Rønne Petersen
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-05std.debug: add unwind support for hexagon-linuxAlex Rønne Petersen
2025-10-05std.debug.SelfInfo.Elf: disable unwinding on mips n32 and x86 x32Alex Rønne Petersen
The DWARF code can't handle these yet. ref https://github.com/ziglang/zig/issues/25447
2025-10-03std.debug: Add unwind support for serenityLinus Groh
2025-10-03std.debug.Dwarf.SelfUnwinder: default some s390x registers to the same-value ↵Alex Rønne Petersen
rule
2025-10-03std.debug: add s390x-linux unwind supportAlex Rønne Petersen
2025-10-02std.debug.Dwarf.Unwind: deal with invalid def_cfa_reg by GNU toolchainsAlex Rønne Petersen
2025-10-01std.debug: add riscv32-linux and riscv64-linux unwind supportAlex Rønne Petersen
2025-10-01std.debug: add loongarch64-linux unwind supportAlex Rønne Petersen
2025-10-01std.debug: some adjustments to target handlingAlex Rønne Petersen
* driverkit handling missing in a few places. * x86-solaris is a dead target. * aarch64_be does not exist on Darwin, FreeBSD, Windows.
2025-10-01std.debug.SelfInfo: rename Darwin to MachOAlex Rønne Petersen
2025-09-30std.debug.SelfInfo: remove shared logicmlugg
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-30Dwarf.Unwind: fix typomlugg
2025-09-30typomlugg
2025-09-30Dwarf.Unwind: handle macOS deviation from standardmlugg
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-30std.debug: significantly speed up capturing stack tracesmlugg
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-30std.debug.SelfInfo: mark ARM unwinding as unsupportedmlugg
We need to parse the `.ARM.exidx` section to be able to reliably unwind the stack on ARM.
2025-09-30typomlugg
2025-09-30std: clarify cpu_context register order rationalemlugg
2025-09-30std.debug: don't assume return address register is defined if not specifiedmlugg
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-30std.debug.SelfInfo: thread safetymlugg
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-30ElfModule: fix assertion failuremlugg
2025-09-30std: don't get CPU context when using CBE targeting MSVCmlugg
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-30std.debug: go back to storing return addresses instead of call addressesmlugg
...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-30std: work around crash parsing LLVM PDBmlugg
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-30std.debug: fix typomlugg
2025-09-30update to new std.debug changesmlugg
2025-09-30std.debug: miscellaneous fixesmlugg
Mostly on macOS, since Loris showed me a not-great stack trace, and I spent 8 hours trying to make it better. The dyld shared cache is designed in a way which makes this really hard to do right, and documentation is non-existent, but this *seems* to work pretty well. I'll leave the ruling on whether I did a good job to CI and our users.
2025-09-30std: rework/remove ucontext_tmlugg
Our usage of `ucontext_t` in the standard library was kind of problematic. We unnecessarily mimiced libc-specific structures, and our `getcontext` implementation was overkill for our use case of stack tracing. This commit introduces a new namespace, `std.debug.cpu_context`, which contains "context" types for various architectures (currently x86, x86_64, ARM, and AARCH64) containing the general-purpose CPU registers; the ones needed in practice for stack unwinding. Each implementation has a function `current` which populates the structure using inline assembly. The structure is user-overrideable, though that should only be necessary if the standard library does not have an implementation for the *architecture*: that is to say, none of this is OS-dependent. Of course, in POSIX signal handlers, we get a `ucontext_t` from the kernel. The function `std.debug.cpu_context.fromPosixSignalContext` converts this to a `std.debug.cpu_context.Native` with a big ol' target switch. This functionality is not exposed from `std.c` or `std.posix`, and neither are `ucontext_t`, `mcontext_t`, or `getcontext`. The rationale is that these types and functions do not conform to a specific ABI, and in fact tend to get updated over time based on CPU features and extensions; in addition, different libcs use different structures which are "partially compatible" with the kernel structure. Overall, it's a mess, but all we need is the kernel context, so we can just define a kernel-compatible structure as long as we don't claim C compatibility by putting it in `std.c` or `std.posix`. This change resulted in a few nice `std.debug` simplifications, but nothing too noteworthy. However, the main benefit of this change is that DWARF unwinding---sometimes necessary for collecting stack traces reliably---now requires far less target-specific integration. Also fix a bug I noticed in `PageAllocator` (I found this due to a bug in my distro's QEMU distribution; thanks, broken QEMU patch!) and I think a couple of minor bugs in `std.debug`. Resolves: #23801 Resolves: #23802
2025-09-30std.debug.Pdb: fix leakmlugg
2025-09-30fix compile errors and minor bugsmlugg
2025-09-30SelfInfo: remove x86-windows unwinding pathmlugg
Turns out that RtlCaptureStackBackTrace is actually just doing FP (ebp) unwinding under the hood, making this logic completely redundant with our own FP-walking implementation; see added comment for details.
2025-09-30tests: split up and enhance stack trace testsmlugg
Previously, the `test-stack-traces` step was essentially just testing error traces, and even there we didn't have much coverage. This commit solves that by splitting the "stack trace" tests into two separate harnesses: the "stack trace" tests are for actual stack traces (i.e. involving stack unwinding), while the "error trace" tests are specifically for error return traces. The "stack trace" tests will test different configurations of: * `-lc` * `-fPIE` * `-fomit-frame-pointer` * `-fllvm` * unwind tables (currently disabled) * strip debug info (currently disabled) The main goal there is to test *stack unwinding* under different conditions. Meanwhile, the "error trace" tests will test different configurations of `-O` and `-fllvm`; the main goal here, aside from checking that error traces themselves do not miscompile, is to check whether debug info is still working even in optimized builds. Of course, aggressive optimizations *can* thwart debug info no matter what, so as before, there is a way to disable cases for specific targets / optimize modes. The program which converts stack traces into a more validatable format by removing things like addresses (previously `check-stack-trace.zig`, now `convert-stack-trace.zig`) has been rewritten and simplified. Also, thanks to various fixes in this branch, several workarounds have become unnecessary: for instance, we don't need to ignore the function name printed in stack traces in release modes, because `std.debug.Dwarf` now uses the correct DIE for inlined functions! Neither `test-stack-traces` nor `test-error-traces` does general foreign architecture testing, because it seems that (at least for now) external executors often aren't particularly good at handling stack tracing correctly (looking at you, Wine). Generally, they just test the native target (this matches the old behavior of `test-stack-traces`). However, there is one exception: when on an x86_64 or aarch64 host, we will also test the 32-bit version (x86 or arm) if the OS supports it, because such executables can be trivially tested without an external executor. Oh, also, I wrote a bunch of stack trace tests. Previously there was, erm, *one* test in `test-stack-traces` which wasn't for error traces. Now there are a good few!
2025-09-30std.debug.Dwarf: fix names of inlined functionsmlugg
2025-09-30std: fix 32-bit build and some unsafe castsmlugg
2025-09-30fix bad mergemlugg
The API of `std.debug.Pdb` changed.
2025-09-30Dwarf: use 'gpa' terminologymlugg
2025-09-30std: replace debug.Dwarf.ElfModule with debug.ElfFilemlugg
This abstraction isn't really tied to DWARF at all! Really, we're just loading some information from an ELF file which is useful for debugging. That *includes* DWARF, but it also includes other information. For instance, the other change here: Now, if DWARF information is missing, `debug.SelfInfo.ElfModule` will name symbols by finding a matching symtab entry. We actually already do this on Mach-O, so it makes obvious sense to do the same on ELF! This change is what motivated the restructuring to begin with. The symtab work is derived from #22077. Co-authored-by: geemili <opensource@geemili.xyz>
2025-09-30small reasonable changemlugg
2025-09-30std.debug: handle ThreadContext slightly bettermlugg
It's now user-overrideable, and uses `noreturn` types to neatly stop analysis.