stacktraces
nimony/lib/std/stacktraces.nim
Stack traces for the native (arkham + nifasm) backend.
The walk itself is four lines, because arkham's frames are regular: the prologue lowers SP once and SP is constant until the epilogue (nativenif/src/arkham/design.md). So "where is my return address" is a per-PROC constant, and nifasm writes those constants — with each proc's code range and name — into a table at the end of .text (nativenif/src/nifasm/tracetable.nim). Given that table, unwinding is repeated address lookup; no DWARF interpreter, no frame pointer, and nothing that allocates before it has something to say.
Two machine facts are all this needs from the back end, and each is one instruction:
traceTable()— a RIP-relativeleaat the table. Referencing it is also
what makes nifasm emit the table at all, so a program that never asks for a stack trace carries none of this.
stackPointer()inside a{.naked.}proc — with no prologue, SP on entry
still points at the return address the call pushed, which is the CALLER's frame. A proc with a prologue can only describe its own.
const maxStackTraceFrames: int64A hard bound on the walk. A stack trace is usually wanted while the program is already misbehaving, and a corrupt frame chain must produce a short trace rather than an endless one. A truncated trace ends with a
...line.const stackTracesAvailable: boolWhether
getStackTracecan answer. False on the C backend — its frames are the C compiler's, described by its unwind tables, and reading those is a different implementation rather than a missing branch of this one.proc getStackTrace(skip: int64): stringNo stack trace on this target — see
stackTracesAvailable.