nx_dwarf_loc.nx
buildroot/runtime/nx_dwarf_loc.nx
about
nx_dwarf_loc.nx -- DWARF location expressions (DW_OP_*).
Closes the gap in the DWARF emit pipeline: nx_dwarf_info today
can describe what a variable IS (DIE for the type) but cannot
say WHERE it lives (frame offset, register, etc.). Without
location expressions, gdb shows "<optimized out>" for everything.
A DWARF location expression is a stack-machine bytecode evaluated
by the debugger's expression interpreter. The bytecode includes:
- Push/Pop constants and registers
- Arithmetic (plus, minus, mul, div, etc.)
- Dereferences (deref, deref_size)
- Composite-piece markers (for split-storage values)
Common cases this module emits:
- Frame-relative local: DW_OP_fbreg <sleb128 offset>
- In a specific register: DW_OP_regN (N = 0..31) or
DW_OP_regx <uleb128 reg>
- Constant address: DW_OP_addr <8-byte vaddr>
- Composite (e.g. struct split across regs): DW_OP_piece
Reference: DWARF v5 spec, section 2.5 (location expressions),
table 7.9 (operation encodings).
Pairs with nx_dwarf_info -- the loc-expr bytes go inside a
DW_AT_location attribute (DW_FORM_exprloc).
dependencies 1 imports · 0 importers
imports: syscalls.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| 85 | struct NxDwLoc |
consts
| 37 | const NX_DW_OP_addr: i64 = 0x03 |
| 38 | const NX_DW_OP_deref: i64 = 0x06 |
| 39 | const NX_DW_OP_const1u: i64 = 0x08 |
| 40 | const NX_DW_OP_const1s: i64 = 0x09 |
| 41 | const NX_DW_OP_const2u: i64 = 0x0A |
| 42 | const NX_DW_OP_const4u: i64 = 0x0C |
| 43 | const NX_DW_OP_const8u: i64 = 0x0E |
| 44 | const NX_DW_OP_constu: i64 = 0x10 |
| 45 | const NX_DW_OP_consts: i64 = 0x11 |
| 46 | const NX_DW_OP_dup: i64 = 0x12 |
| 47 | const NX_DW_OP_drop: i64 = 0x13 |
| 48 | const NX_DW_OP_over: i64 = 0x14 |
| 49 | const NX_DW_OP_pick: i64 = 0x15 |
| 50 | const NX_DW_OP_swap: i64 = 0x16 |
| 51 | const NX_DW_OP_rot: i64 = 0x17 |
| 52 | const NX_DW_OP_xderef: i64 = 0x18 |
| 53 | const NX_DW_OP_abs: i64 = 0x19 |
| 54 | const NX_DW_OP_and: i64 = 0x1A |
| 55 | const NX_DW_OP_div: i64 = 0x1B |
| 56 | const NX_DW_OP_minus: i64 = 0x1C |
| 57 | const NX_DW_OP_mod: i64 = 0x1D |
| 58 | const NX_DW_OP_mul: i64 = 0x1E |
| 59 | const NX_DW_OP_neg: i64 = 0x1F |
| 60 | const NX_DW_OP_not: i64 = 0x20 |
| 61 | const NX_DW_OP_or: i64 = 0x21 |
| 62 | const NX_DW_OP_plus: i64 = 0x22 |
| 63 | const NX_DW_OP_plus_uconst: i64 = 0x23 |
| 64 | const NX_DW_OP_shl: i64 = 0x24 |
| 65 | const NX_DW_OP_shr: i64 = 0x25 |
| 66 | const NX_DW_OP_shra: i64 = 0x26 |
| 67 | const NX_DW_OP_xor: i64 = 0x27 |
| 68 | const NX_DW_OP_eq: i64 = 0x29 |
| 69 | const NX_DW_OP_ge: i64 = 0x2A |
| 70 | const NX_DW_OP_gt: i64 = 0x2B |
| 71 | const NX_DW_OP_le: i64 = 0x2C |
| 72 | const NX_DW_OP_lt: i64 = 0x2D |
| 73 | const NX_DW_OP_ne: i64 = 0x2E |
| 74 | const NX_DW_OP_lit0: i64 = 0x30 // lit0..lit31 = 0x30..0x4F |
| 75 | const NX_DW_OP_reg0: i64 = 0x50 // reg0..reg31 = 0x50..0x6F |
| 76 | const NX_DW_OP_breg0: i64 = 0x70 // breg0..breg31 = 0x70..0x8F |
| 77 | const NX_DW_OP_regx: i64 = 0x90 |
| 78 | const NX_DW_OP_fbreg: i64 = 0x91 |
| 79 | const NX_DW_OP_bregx: i64 = 0x92 |
| 80 | const NX_DW_OP_piece: i64 = 0x93 |
| 81 | const NX_DW_OP_deref_size: i64 = 0x94 |
| 82 | const NX_DW_OP_call_frame_cfa: i64 = 0x9C |
| 91 | const NX_DWLOC_BYTES: i64 = 24 |
functions
| 93 | func nx_dwloc_new(cap: i64) -> *NxDwLoc called by 1: main |
| 102 | func nx_dwloc_byte(l: *NxDwLoc, b: i64) -> i64 |
| 111 | func nx_dwloc_uleb128(l: *NxDwLoc, v: i64) -> i64 |
| 127 | func nx_dwloc_sleb128(l: *NxDwLoc, v: i64) -> i64 |
| 157 | func nx_dwloc_addr(l: *NxDwLoc, vaddr: i64) -> i64 |
| 169 | func nx_dwloc_reg(l: *NxDwLoc, r: i64) -> i64 |
| 179 | func nx_dwloc_breg(l: *NxDwLoc, r: i64, off: i64) -> i64 |
| 190 | func nx_dwloc_fbreg(l: *NxDwLoc, off: i64) -> i64 |
| 196 | func nx_dwloc_piece(l: *NxDwLoc, n_bytes: i64) -> i64 |
| 203 | func main() -> i64 |