code wiki / (root) / nx_dwarf_abbrev.nx

nx_dwarf_abbrev.nx source

↩ module page · 221 lines · 8118 B

1// nx_dwarf_abbrev.nx -- DWARF .debug_abbrev section builder. 2// 3// DWARF DIE entries don't carry their own attribute schemas; they 4// reference an entry in .debug_abbrev that says "this DIE is tag T, 5// has children Y/N, and its attributes appear in the order 6// (name1, form1), (name2, form2), ...". Sharing one abbrev entry 7// across many DIEs makes .debug_info compact. 8// 9// One abbrev declaration encodes: 10// abbrev_code -- uleb128, the integer DIEs reference 11// tag -- uleb128 (DW_TAG_*) 12// has_children -- 1 byte: 0x00 = no, 0x01 = yes 13// sequence of (name, form) uleb128 pairs, terminated by (0, 0) 14// 15// The whole .debug_abbrev section is a concatenation of such 16// declarations, terminated by an abbrev_code of 0. 17// 18// We use nx_intern over (tag, has_children, attr_list_hash) to 19// dedup -- two DIEs with the same shape get the same abbrev code. 20// 21// Common DW_TAG_* / DW_AT_* / DW_FORM_* constants exposed for use 22// by the upcoming nx_dwarf_info.nx (DIE forest builder). 23 24// nx_safety_envelope: 25// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 26// sil_target: SIL1 27// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 28// verdict: NOT_YET_EVALUATED 29 30import "syscalls.nx" 31 32// ---- selected DW_TAG_* (per DWARF v5 spec Section 7.5.4) --------- 33 34const NX_DW_TAG_compile_unit: i64 = 0x11 35const NX_DW_TAG_subprogram: i64 = 0x2E 36const NX_DW_TAG_variable: i64 = 0x34 37const NX_DW_TAG_formal_parameter: i64 = 0x05 38const NX_DW_TAG_lexical_block: i64 = 0x0B 39const NX_DW_TAG_base_type: i64 = 0x24 40const NX_DW_TAG_pointer_type: i64 = 0x0F 41const NX_DW_TAG_array_type: i64 = 0x01 42const NX_DW_TAG_structure_type: i64 = 0x13 43const NX_DW_TAG_member: i64 = 0x0D 44const NX_DW_TAG_enumeration_type: i64 = 0x04 45const NX_DW_TAG_enumerator: i64 = 0x28 46 47// ---- selected DW_AT_* --------------------------------------------- 48 49const NX_DW_AT_name: i64 = 0x03 50const NX_DW_AT_byte_size: i64 = 0x0B 51const NX_DW_AT_low_pc: i64 = 0x11 52const NX_DW_AT_high_pc: i64 = 0x12 53const NX_DW_AT_language: i64 = 0x13 54const NX_DW_AT_comp_dir: i64 = 0x1B 55const NX_DW_AT_producer: i64 = 0x25 56const NX_DW_AT_prototyped: i64 = 0x27 57const NX_DW_AT_stmt_list: i64 = 0x10 58const NX_DW_AT_type: i64 = 0x49 59const NX_DW_AT_encoding: i64 = 0x3E 60const NX_DW_AT_external: i64 = 0x3F 61const NX_DW_AT_decl_file: i64 = 0x3A 62const NX_DW_AT_decl_line: i64 = 0x3B 63 64// ---- selected DW_FORM_* ------------------------------------------- 65 66const NX_DW_FORM_addr: i64 = 0x01 67const NX_DW_FORM_data1: i64 = 0x0B 68const NX_DW_FORM_data2: i64 = 0x05 69const NX_DW_FORM_data4: i64 = 0x06 70const NX_DW_FORM_data8: i64 = 0x07 71const NX_DW_FORM_string: i64 = 0x08 72const NX_DW_FORM_strp: i64 = 0x0E 73const NX_DW_FORM_ref4: i64 = 0x13 74const NX_DW_FORM_ref8: i64 = 0x14 75const NX_DW_FORM_sec_offset: i64 = 0x17 76const NX_DW_FORM_flag: i64 = 0x0C 77const NX_DW_FORM_flag_present: i64 = 0x19 78const NX_DW_FORM_udata: i64 = 0x0F 79const NX_DW_FORM_sdata: i64 = 0x0D 80 81// ---- abbreviation builder ----------------------------------------- 82 83struct NxDwAbbrev { 84 buf: *u8, 85 cap: i64, 86 used: i64, 87 next_code: i64, // monotonically increasing abbrev_code 88 cur_open: i64, // 1 if a declaration is being built 89} 90 91const NX_DW_ABBREV_BYTES: i64 = 40 92 93func nx_dwabbrev_new(cap: i64) -> *NxDwAbbrev { 94 let raw: *u8 = sys_mmap(NX_DW_ABBREV_BYTES) 95 let a: *NxDwAbbrev = raw as *NxDwAbbrev 96 a.buf = sys_mmap(cap) 97 a.cap = cap 98 a.used = 0 99 a.next_code = 1 // codes are 1-based; 0 = sentinel 100 a.cur_open = 0 101 return a 102} 103 104// ---- byte append + uleb128 --------------------------------------- 105 106func nx_dwabbrev_byte(a: *NxDwAbbrev, v: i64) -> i64 { 107 if a.used >= a.cap { return -1 } 108 a.buf[a.used] = v & 0xFF 109 a.used = a.used + 1 110 return 0 111} 112 113func nx_dwabbrev_uleb(a: *NxDwAbbrev, v: i64) -> i64 { 114 var x: i64 = v 115 var go: i64 = 1 116 while go == 1 { 117 var b: i64 = x & 0x7F 118 x = x >> 7 119 if x != 0 { b = b | 0x80 } 120 if nx_dwabbrev_byte(a, b) < 0 { return -1 } 121 if x == 0 { go = 0 } 122 } 123 return 0 124} 125 126// ---- declaration API --------------------------------------------- 127 128// Begin a new abbreviation declaration. Returns the abbrev_code 129// the caller should reference from .debug_info DIEs. 130// 131// has_children: 0 (no) or 1 (yes). 132func nx_dwabbrev_begin(a: *NxDwAbbrev, tag: i64, has_children: i64) -> i64 { 133 let code: i64 = a.next_code 134 a.next_code = a.next_code + 1 135 nx_dwabbrev_uleb(a, code) 136 nx_dwabbrev_uleb(a, tag) 137 nx_dwabbrev_byte(a, has_children & 0x1) 138 a.cur_open = 1 139 return code 140} 141 142// Add an (attribute name, form) pair to the open declaration. 143func nx_dwabbrev_attr(a: *NxDwAbbrev, name: i64, form: i64) -> i64 { 144 if a.cur_open != 1 { return -1 } 145 nx_dwabbrev_uleb(a, name) 146 nx_dwabbrev_uleb(a, form) 147 return 0 148} 149 150// End the open declaration with the (0, 0) terminator pair. 151func nx_dwabbrev_end(a: *NxDwAbbrev) -> i64 { 152 if a.cur_open != 1 { return -1 } 153 nx_dwabbrev_byte(a, 0) 154 nx_dwabbrev_byte(a, 0) 155 a.cur_open = 0 156 return 0 157} 158 159// Finalize the section by appending the trailing 0 abbrev_code. 160// Caller does this before emitting the section bytes. 161func nx_dwabbrev_finish(a: *NxDwAbbrev) -> i64 { 162 if a.cur_open == 1 { nx_dwabbrev_end(a) } 163 nx_dwabbrev_byte(a, 0) 164 return 0 165} 166 167func nx_dwabbrev_size(a: *NxDwAbbrev) -> i64 { return a.used } 168func nx_dwabbrev_bytes(a: *NxDwAbbrev) -> *u8 { return a.buf } 169 170// ---- self-test --------------------------------------------------- 171 172func main() -> i64 { 173 let a: *NxDwAbbrev = nx_dwabbrev_new(256) 174 175 // Abbrev #1: a compile_unit DIE with name + producer + low_pc + 176 // high_pc + stmt_list (5 attributes), HAS children (subprograms). 177 let cu_code: i64 = nx_dwabbrev_begin(a, NX_DW_TAG_compile_unit, 1) 178 if cu_code != 1 { return __syscall(93, 10, 0, 0, 0, 0, 0) } 179 nx_dwabbrev_attr(a, NX_DW_AT_name, NX_DW_FORM_strp) 180 nx_dwabbrev_attr(a, NX_DW_AT_producer, NX_DW_FORM_strp) 181 nx_dwabbrev_attr(a, NX_DW_AT_low_pc, NX_DW_FORM_addr) 182 nx_dwabbrev_attr(a, NX_DW_AT_high_pc, NX_DW_FORM_data8) 183 nx_dwabbrev_attr(a, NX_DW_AT_stmt_list, NX_DW_FORM_sec_offset) 184 nx_dwabbrev_end(a) 185 186 // Abbrev #2: a subprogram DIE -- name + low_pc + high_pc + type 187 // + external, no children. 188 let sub_code: i64 = nx_dwabbrev_begin(a, NX_DW_TAG_subprogram, 0) 189 if sub_code != 2 { return __syscall(93, 20, 0, 0, 0, 0, 0) } 190 nx_dwabbrev_attr(a, NX_DW_AT_name, NX_DW_FORM_strp) 191 nx_dwabbrev_attr(a, NX_DW_AT_low_pc, NX_DW_FORM_addr) 192 nx_dwabbrev_attr(a, NX_DW_AT_high_pc, NX_DW_FORM_data8) 193 nx_dwabbrev_attr(a, NX_DW_AT_type, NX_DW_FORM_ref4) 194 nx_dwabbrev_attr(a, NX_DW_AT_external, NX_DW_FORM_flag_present) 195 nx_dwabbrev_end(a) 196 197 // Abbrev #3: a base_type DIE (e.g. int) -- name + byte_size + 198 // encoding, no children. 199 let bt_code: i64 = nx_dwabbrev_begin(a, NX_DW_TAG_base_type, 0) 200 if bt_code != 3 { return __syscall(93, 30, 0, 0, 0, 0, 0) } 201 nx_dwabbrev_attr(a, NX_DW_AT_name, NX_DW_FORM_strp) 202 nx_dwabbrev_attr(a, NX_DW_AT_byte_size, NX_DW_FORM_data1) 203 nx_dwabbrev_attr(a, NX_DW_AT_encoding, NX_DW_FORM_data1) 204 nx_dwabbrev_end(a) 205 206 // Finalize: trailing 0. 207 nx_dwabbrev_finish(a) 208 209 // Sanity check: section non-empty + last byte = 0. 210 if nx_dwabbrev_size(a) <= 0 { return __syscall(93, 40, 0, 0, 0, 0, 0) } 211 if a.buf[a.used - 1] != 0 { return __syscall(93, 41, 0, 0, 0, 0, 0) } 212 213 // First byte should be the abbrev_code 1 (uleb128 = 0x01). 214 if a.buf[0] != 1 { return __syscall(93, 50, 0, 0, 0, 0, 0) } 215 // Second byte: tag = NX_DW_TAG_compile_unit = 0x11. 216 if a.buf[1] != 0x11 { return __syscall(93, 51, 0, 0, 0, 0, 0) } 217 // Third byte: has_children = 1. 218 if a.buf[2] != 1 { return __syscall(93, 52, 0, 0, 0, 0, 0) } 219 220 return 0 221}