commit b741e2c5b1dfa6bffa2e0a4a4723e602d8919208
parent 85b11149946e7dc2f7f1a039aa3e4c389be4c962
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Fri, 29 May 2026 13:36:15 -0700
x64/rv64: emit named parameters and locals in .debug_info
Both backends set frame_slot_debug_loc = NULL, so the shared producer's
nd_local_debug_loc returned 0 and api_debug_emit_source_locals skipped every
parameter and local: x64/rv64 -g objects had DW_TAG_formal_parameter DIEs
with only DW_AT_type (no name, no location) and zero DW_TAG_variable DIEs, so
gdb/lldb could not print arguments or locals by name. Only aa64 implemented
the hook (doc/DBG_TODO.md:153 tracked bringing x64/rv64 to parity).
Implement x64_frame_slot_debug_loc and rv_frame_slot_debug_loc as mirrors of
aa_frame_slot_debug_loc, reporting the frame-pointer-relative slot offset
(x64: -off off RBP; rv64: rv_s0_off_slot off s0) — the same convention aa64
uses and that the hosted dbg snapshot consumes (frame base seeded to the FP
register).
Verified: x64/rv64 -g now emit named params a/b and locals x/y with
DW_OP_fbreg locations, byte-identical to aa64 (only DW_AT_high_pc differs,
reflecting per-arch code size). test-debug + test-dbg green.
Diffstat:
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/src/arch/rv64/native.c b/src/arch/rv64/native.c
@@ -1190,6 +1190,22 @@ static NativeFrameSlot rv_frame_slot(NativeTarget* t,
return native_frame_slot_alloc(&rv_of(t)->frame, d);
}
+static int rv_frame_slot_debug_loc(NativeTarget* t, NativeFrameSlot slot,
+ CGDebugLoc* out) {
+ RvNativeTarget* a = rv_of(t);
+ RvNativeSlot* s;
+ if (!out) return 0;
+ memset(out, 0, sizeof *out);
+ if (slot == NATIVE_FRAME_SLOT_NONE || slot > a->frame.nslots) return 0;
+ s = rv_slot_get(a, slot);
+ out->kind = CG_DEBUG_LOC_FRAME;
+ /* rv64 slots are addressed s0/fp-relative (rv_s0_off_slot); the hosted dbg
+ * snapshot seeds the frame base with s0, matching aa64's FP-relative
+ * convention. */
+ out->v.frame_ofs = rv_s0_off_slot(s);
+ return 1;
+}
+
static void rv_func_begin_common(NativeTarget* t, const CGFuncDesc* fd) {
RvNativeTarget* a = rv_of(t);
MCEmitter* mc = t->mc;
@@ -3216,7 +3232,7 @@ NativeTarget* rv64_native_target_new(Compiler* c, ObjBuilder* obj,
t->store_zero_reg = RV_ZERO;
t->func_end = rv_func_end;
t->frame_slot = rv_frame_slot;
- t->frame_slot_debug_loc = NULL;
+ t->frame_slot_debug_loc = rv_frame_slot_debug_loc;
t->bind_param = rv_bind_native_param;
t->label_new = rv_label_new;
t->label_place = rv_label_place;
diff --git a/src/arch/x64/native.c b/src/arch/x64/native.c
@@ -1369,6 +1369,22 @@ static NativeFrameSlot x64_frame_slot(NativeTarget* t,
return native_frame_slot_alloc(&x64_of(t)->frame, d);
}
+static int x64_frame_slot_debug_loc(NativeTarget* t, NativeFrameSlot slot,
+ CGDebugLoc* out) {
+ X64NativeTarget* a = x64_of(t);
+ X64NativeSlot* s;
+ if (!out) return 0;
+ memset(out, 0, sizeof *out);
+ if (slot == NATIVE_FRAME_SLOT_NONE || slot > a->frame.nslots) return 0;
+ s = x64_slot_get(a, slot);
+ out->kind = CG_DEBUG_LOC_FRAME;
+ /* x64 slots live at RBP - off (exactly how the memory-operand path addresses
+ * them). The hosted dbg snapshot seeds the frame base with RBP, so report
+ * the RBP-relative offset — mirroring aa64's FP-relative convention. */
+ out->v.frame_ofs = -(i32)s->off;
+ return 1;
+}
+
/* xmm save area base (rbp-relative). XMM saves are 16-aligned. */
static u32 x64_xmm_base(const X64NativeTarget* a, u32 cs_fp) {
if (cs_fp == 0) return a->frame.cum_off;
@@ -3747,7 +3763,7 @@ NativeTarget* x64_native_target_new(Compiler* c, ObjBuilder* obj,
t->has_store_zero_reg = 0;
t->func_end = x64_func_end;
t->frame_slot = x64_frame_slot;
- t->frame_slot_debug_loc = NULL;
+ t->frame_slot_debug_loc = x64_frame_slot_debug_loc;
t->bind_param = x64_bind_native_param;
t->label_new = x64_label_new;
t->label_place = x64_label_place;