mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-08-06 23:58:49 +00:00
Compare commits
2
Commits
c3cf05950e
...
gdb-atoms
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67d54debfa | ||
|
|
3c25306070 |
+126
-1
@@ -389,12 +389,99 @@ local function read_form_value(buf, str_buf, pos, form)
|
||||
-- The constant is declared in the abbrev; no value bytes in the DIE.
|
||||
return nil, pos
|
||||
elseif form == M.DW_FORM.ref_sig8 then
|
||||
return M.read_u32_le(buf, pos), pos + 8
|
||||
-- DW_FORM_ref_sig8 (DWARF5 §7.4.2): an 8-byte value identifying a type
|
||||
-- by signature. The low 4 bytes (LE) are the type signature (content hash);
|
||||
-- the high 4 bytes (LE) are a CU-relative offset into the matching type unit.
|
||||
-- Consumers use the low 4 to look up the type unit (see M.find_type_unit_by_signature)
|
||||
-- then the high 4 to resolve the specific type within it.
|
||||
-- Return the low 4 as the primary value to preserve the (value, next_pos) shape;
|
||||
-- the high 4 is exposed via M.read_ref_sig8 (which returns both halves).
|
||||
local _, _, next_pos = M.read_ref_sig8(buf, pos)
|
||||
return M.read_u32_le(buf, pos), next_pos
|
||||
else
|
||||
return nil, pos
|
||||
end
|
||||
end
|
||||
|
||||
--- Read a `DW_FORM_ref_sig8` value at 0-based offset `pos` from `buf`.
|
||||
--- Returns the low 4 bytes (LE) as `low`, the high 4 bytes (LE) as `high`, and
|
||||
--- the cursor position after the 8-byte value as `next_pos`.
|
||||
--- Callers that need the full type-unit + type-offset pair
|
||||
--- (e.g. to resolve a type identifier embedded as a signature)
|
||||
--- should use this directly rather than going through `read_form_value`,
|
||||
--- which only exposes the low 4 bytes to preserve its existing (value, next_pos) return shape.
|
||||
--- @param buf string
|
||||
--- @param pos integer -- zero-based wire offset
|
||||
--- @return integer -- low 4 bytes (LE), the type signature
|
||||
--- @return integer -- high 4 bytes (LE), the offset within the matching type unit
|
||||
--- @return integer -- cursor after the 8-byte value
|
||||
function M.read_ref_sig8(buf, pos)
|
||||
return M.read_u32_le(buf, pos), M.read_u32_le(buf, pos + 4), pos + 8
|
||||
end
|
||||
|
||||
-- DWARF5 §7.5.6 (Type Entries).
|
||||
-- Walk all units in `info` and return the 0-based offset of the first unit
|
||||
-- whose `DW_AT_type_signature` (8-byte value at the end of the unit header) equals `target_sig`.
|
||||
-- The signature is interpreted as two 32-bit halves (low/high) per the read_ref_sig8 contract;
|
||||
-- we match both halves (i.e. the 8-byte value as a whole). Returns nil if no matching unit exists.
|
||||
--
|
||||
-- Unit header layout (from pos 0):
|
||||
-- unit_length(4) + version(2) + unit_type(1) + address_size(1) + debug_abbrev_offset(4)
|
||||
-- -- followed by type_unit_specific fields:
|
||||
-- type_signature(8) + type_offset(4)
|
||||
-- The type_signature is at byte offset 8 of the body (right after debug_abbrev_offset).
|
||||
-- @param info string -- the .debug_info section bytes
|
||||
-- @param target_sig_lo integer -- low 4 bytes (LE) of the desired signature
|
||||
-- @param target_sig_hi integer -- high 4 bytes (LE) of the desired signature
|
||||
-- @return integer|nil, integer|nil -- unit offset, type_offset within the unit
|
||||
function M.find_type_unit_by_signature(info, target_sig_lo, target_sig_hi)
|
||||
local pos = 0
|
||||
local section_len = #info
|
||||
while pos + 4 < section_len do
|
||||
local unit_length = M.read_u32_le(info, pos)
|
||||
if unit_length == 0xFFFFFFFF then
|
||||
return nil, nil -- DWARF64 not supported
|
||||
end
|
||||
-- unit_length is the body size, NOT including the 4-byte unit_length field itself.
|
||||
local body_start = pos + 4
|
||||
local body_end = body_start + unit_length
|
||||
if body_end > section_len then
|
||||
return nil, nil -- malformed
|
||||
end
|
||||
-- Per DWARF5 §7.5.6, the type_unit (DW_UT_type = 0x02) body layout is:
|
||||
-- 0: version (2)
|
||||
-- 2: unit_type (1) -- DW_UT_type = 0x02
|
||||
-- 3: address_size (1)
|
||||
-- 4: debug_abbrev_offset (4)
|
||||
-- 8: type_signature (8)
|
||||
-- 16: type_offset (4)
|
||||
-- 20: <children>
|
||||
if body_end - body_start >= 20 then
|
||||
-- read_ref_sig8 / write_u32_le / etc. are 1-indexed (string:byte);
|
||||
-- pos / body_start / body_end are 0-based wire offsets, so the
|
||||
-- 1-indexed byte at 0-based wire offset X is string:byte(X + 1).
|
||||
-- Per DWARF5 §7.5.6, the type_unit body is laid out as:
|
||||
-- byte 0-1: version (2)
|
||||
-- byte 2: unit_type (1) -- DW_UT_type = 0x02
|
||||
-- byte 3: address_size (1)
|
||||
-- byte 4-7: debug_abbrev_offset (4)
|
||||
-- byte 8-15: type_signature (8)
|
||||
-- byte 16-19: type_offset (4)
|
||||
local unit_type = info:byte(body_start + 2 + 1) -- 0-based +2 = unit_type in 1-indexed
|
||||
if unit_type == 0x02 then -- DW_UT_type
|
||||
local sig_lo, sig_hi, _ = M.read_ref_sig8(info, body_start + 8) -- 0-based +8 = type_signature in 1-indexed
|
||||
if sig_lo == target_sig_lo and sig_hi == target_sig_hi then
|
||||
local type_offset = M.read_u32_le(info, body_start + 16) -- 0-based +16 = type_offset in 1-indexed
|
||||
return pos, type_offset
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Advance to the next unit (the 4-byte unit_length + the body).
|
||||
pos = body_end
|
||||
end
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
--- Return a 4-byte little-endian byte string for `value`.
|
||||
--- Caller concatenates with `..` if composing multi-word blobs.
|
||||
--- **Byte weights** written as `0x100` etc. (see `M.read_u32_le` for rationale).
|
||||
@@ -665,6 +752,44 @@ function M.sleb128(n)
|
||||
return table.concat(bytes)
|
||||
end
|
||||
|
||||
--- ULEB128 byte-length: number of bytes the encoder M.uleb128 would produce for `n`.
|
||||
--- Used by callers that need to size a buffer before encoding (e.g. compute_loclists_offsets
|
||||
--- needs the encoded length of an `uleb128(4)` for a `DW_OP_piece + uleb128(U4_BYTE_SIZE)` tail).
|
||||
--- @param n integer -- non-negative
|
||||
--- @return integer -- 1..5 for n in [0, 2^32)
|
||||
function M.uleb128_size(n)
|
||||
assert(n >= 0, "uleb128_size requires non-negative input")
|
||||
if n == 0 then return 1 end
|
||||
local bytes = 1
|
||||
while n >= 0x80 do
|
||||
n = (n - (n % (LEB_DATA_MASK + 1))) / (LEB_DATA_MASK + 1) -- arithmetic shift right by 7
|
||||
bytes = bytes + 1
|
||||
end
|
||||
return bytes
|
||||
end
|
||||
|
||||
--- SLEB128 byte-length: number of bytes the encoder M.sleb128 would produce for `n`.
|
||||
--- Used by callers that need to size a buffer before encoding.
|
||||
--- (e.g. compute_loclists_offsets needs the encoded length of an `sleb128(field.offset)` in a tape piece).
|
||||
--- Handles the signed DWARF5 termination: positive terminator if (n == 0) and bit 6 of last byte is unset;
|
||||
--- negative terminator if (n == -1) and bit 6 of last byte is set.
|
||||
--- @param n integer -- any integer (negative allowed)
|
||||
--- @return integer
|
||||
function M.sleb128_size(n)
|
||||
local more = true
|
||||
local bytes = 0
|
||||
local v = n
|
||||
while more do
|
||||
local b = v % (LEB_DATA_MASK + 1) -- extract low 7 bits
|
||||
v = (v - b) / (LEB_DATA_MASK + 1) -- arithmetic shift right by 7
|
||||
if v == 0 and b < SLEB_SIGN_BIT then more = false end -- positive terminator
|
||||
if v == -1 and b >= SLEB_SIGN_BIT then more = false end -- negative terminator
|
||||
if more then b = b + LEB_CONT_BIT end
|
||||
bytes = bytes + 1
|
||||
end
|
||||
return bytes
|
||||
end
|
||||
|
||||
-- ════════════════════════════════════════════════════════════════════════════
|
||||
-- I/O helpers: atoms source-map + native directory glob
|
||||
-- ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
@@ -108,6 +108,11 @@ local ABBREV_INLINED_SUBROUTINE = 0x6C -- 108: DW_TAG_inlined_subroutine with
|
||||
-- Bind_args uses DW_FORM_sec_offset → .debug_loclists for PC-ranged liveness
|
||||
-- (each field transitions from tape memory to GPR at load_pc + 8 = MIPS I load-delay slot boundary).
|
||||
local ABBREV_BIND_VAR_LOCLIST = 0x6D -- 109: DW_TAG_variable no children + DW_AT_type = ref4 + DW_AT_location = sec_offset
|
||||
-- Typed-view pointer_type (for the synthetic V4_S2* / V3_S2* / U4* / void* chains).
|
||||
-- MUST be a fresh abbrev code in the appended table — emitting uleb128(9) collides with GCC's
|
||||
-- existing abbrev 9 (a pointer_type that carries DW_AT_byte_size + DW_AT_type), so gdb misparses
|
||||
-- our 4-byte ref4 as (byte_size, type[0..2]) and lands the cursor mid-attribute.
|
||||
local ABBREV_TYPED_VIEW_POINTER = 0x6E -- 110: DW_TAG_pointer_type no children + DW_AT_type = ref4 (typed-view / U4 / void chain)
|
||||
|
||||
-- DWARF5 §7.7.3 loclist opcodes.
|
||||
local DW_LLE_end_of_list = 0x00
|
||||
@@ -134,6 +139,7 @@ local DW_TAG_variable = 0x34
|
||||
local DW_TAG_structure_type = 0x13
|
||||
local DW_TAG_member = 0x0D
|
||||
local DW_TAG_base_type = 0x24
|
||||
local DW_TAG_pointer_type = 0x0F
|
||||
-- Component step-into.
|
||||
local DW_TAG_inlined_subroutine = 0x1D
|
||||
|
||||
@@ -289,21 +295,42 @@ local function build_debug_loclists_section(atom_table, registries)
|
||||
return header .. body
|
||||
end
|
||||
|
||||
-- Compute the size of one tape piece for an atom's struct field offset.
|
||||
-- The piece is: DW_OP_bregN(1) + sleb128(offset)(1..5) + DW_OP_piece(1) + uleb128(4)(1).
|
||||
-- Sleb128(0) is 1 byte; sleb128(63) is 1 byte; sleb128(64) is 2 bytes; ...; sleb128(2^28) is 5 bytes.
|
||||
-- 4 = U4_BYTE_SIZE: each field is sizeof(uint32_t) on MIPS32.
|
||||
-- @param offset integer -- the field's offset within the struct (0..2^32-1)
|
||||
-- @return integer -- encoded size in bytes (4 for offsets < 64, 5 for offsets 64..8191, ..., 8 for > 2^28)
|
||||
local function tape_piece_size(offset)
|
||||
return 1 + elf_dwarf.sleb128_size(offset) + 1 + elf_dwarf.uleb128_size(U4_BYTE_SIZE)
|
||||
end
|
||||
|
||||
-- Compute the per-atom loclist offset within a .debug_loclists section.
|
||||
-- @param atom_table table[] -- list of atoms with .rbind set
|
||||
-- @return table -- {[atom_name] = offset_in_section}
|
||||
local function compute_loclists_offsets(atom_table)
|
||||
local LOCLIST_ENTRY_HEADER_SIZE = 1 + 4 + 1 -- DW_LLE_start_length(1) + addr(4) + uleb_length(1)
|
||||
local offsets = {}
|
||||
local cursor = 4 + 2 + 1 + 1 + 4
|
||||
-- Loclist unit header (DWARF5 §7.7.2): unit_length(4) + version(2) + address_size(1) + segment_size(1) + offset_entry_count(4) = 12 bytes.
|
||||
-- The unit_length itself is not counted in the unit_length value, so the body starts at byte 12.
|
||||
local cursor = 4 + 2 + 1 + 1 + 4 -- = 12
|
||||
for _, atom in ipairs(atom_table) do
|
||||
if atom.rbind then
|
||||
offsets[atom.name] = cursor
|
||||
local n_fields = #atom.rbind.fields
|
||||
local tape_expr_len = n_fields * 3
|
||||
local gpr_expr_len = n_fields * 3
|
||||
local tape_entry = 1 + 4 + 1 + tape_expr_len
|
||||
local gpr_entry = 1 + 4 + 1 + gpr_expr_len
|
||||
local body_len = tape_entry + gpr_entry + 1
|
||||
-- Sum the actual size of each tape piece based on the field's offset, not an assumed constant.
|
||||
-- The expression below mirrors what build_debug_loclists_section produces:
|
||||
-- 1 (DW_LLE_start_length) + 4 (PC) + 1 (uleb length prefix) + sum(tape_piece_size(field.offset))
|
||||
-- + 1 (DW_LLE_start_length) + 4 (transition_pc) + 1 (uleb length prefix) + n_fields * 3 (gpr pieces)
|
||||
-- + 1 (DW_LLE_end_of_list)
|
||||
local tape_pieces_size = 0
|
||||
for _, f in ipairs(atom.rbind.fields or {}) do
|
||||
tape_pieces_size = tape_pieces_size + tape_piece_size(f.offset or 0)
|
||||
end
|
||||
local gpr_pieces_size = n_fields * 3 -- each gpr piece: DW_OP_regN(1) + DW_OP_piece(1) + uleb(4)(1) = 3 bytes
|
||||
local tape_entry = LOCLIST_ENTRY_HEADER_SIZE + tape_pieces_size
|
||||
local gpr_entry = LOCLIST_ENTRY_HEADER_SIZE + gpr_pieces_size
|
||||
local body_len = tape_entry + gpr_entry + 1 -- +1 for DW_LLE_end_of_list
|
||||
cursor = cursor + body_len
|
||||
end
|
||||
end
|
||||
@@ -1072,7 +1099,10 @@ end
|
||||
--- @param atom_table table
|
||||
--- @return string
|
||||
local function build_dwarf_aranges_section(existing, atom_table)
|
||||
if #existing < 12 then return existing end -- header sanity
|
||||
if #existing < 12 then
|
||||
io.stderr:write("[dwarf_injection] WARN: .debug_aranges section too short (" .. #existing .. " bytes) to contain a unit header; passing through unchanged\n")
|
||||
return existing
|
||||
end -- header sanity
|
||||
|
||||
-- .debug_aranges can contain multiple compilation units (CUs).
|
||||
-- gcc-mips-elf emits one CU per .text section TU.
|
||||
@@ -1099,6 +1129,7 @@ local function build_dwarf_aranges_section(existing, atom_table)
|
||||
local ul = elf_dwarf.read_u32_le(existing, i)
|
||||
if ul == elf_dwarf.ELF32.dw_dwarf32_terminator then
|
||||
-- DWARF64 marker - not supported.
|
||||
io.stderr:write("[dwarf_injection] WARN: .debug_aranges contains a DWARF64 marker (0xFFFFFFFF); the 64-bit extension is not supported by this metaprogram; passing through unchanged\n")
|
||||
return existing
|
||||
end
|
||||
|
||||
@@ -1131,8 +1162,10 @@ local function build_dwarf_aranges_section(existing, atom_table)
|
||||
end
|
||||
|
||||
if not is_last_unit then
|
||||
-- Malformed or no terminator found; append a new unit at the end.
|
||||
-- For now, return existing unchanged to avoid making it worse.
|
||||
-- Malformed: walked past the end of the section without finding a unit whose end aligns with #existing.
|
||||
-- This means a unit's length field overruns the section, or there is no terminator on the last unit.
|
||||
-- For now, return existing unchanged to avoid making it worse; warn so the user can investigate.
|
||||
io.stderr:write("[dwarf_injection] WARN: .debug_aranges layout is malformed (no unit's end aligned with section end at " .. #existing .. " bytes); passing through unchanged\n")
|
||||
return existing
|
||||
end
|
||||
|
||||
@@ -1444,11 +1477,18 @@ local function build_new_abbrev()
|
||||
.. attr(DW_AT_location, DW_FORM_sec_offset)
|
||||
.. attr(DW_AT_type, DW_FORM_ref4))
|
||||
|
||||
-- Typed-view pointer_type: DW_TAG_pointer_type, DW_AT_type = ref4 (no DW_AT_byte_size; the
|
||||
-- chain target carries the byte size via the base_type or struct_type we point at).
|
||||
-- MUST be in the appended table — see ABBREV_TYPED_VIEW_POINTER above.
|
||||
local abbrev_typed_view_pointer = abbrev(ABBREV_TYPED_VIEW_POINTER, DW_TAG_pointer_type, false, -- DW_CHILDREN_no
|
||||
attr(DW_AT_type, DW_FORM_ref4))
|
||||
|
||||
return abbrev_cu .. abbrev_subprogram .. abbrev_variable
|
||||
.. abbrev_struct_type .. abbrev_member .. abbrev_bind_var .. abbrev_base_type
|
||||
.. abbrev_abstract_subprogram .. abbrev_inlined_subroutine
|
||||
.. abbrev_bind_var_loclists
|
||||
.. string.char(DW_LLE_end_of_list) -- section terminator (the loclist-unit end marker per DWARF5 §7.7.3)
|
||||
.. abbrev_typed_view_pointer
|
||||
.. string.char(0x00) -- abbrev table terminator (DWARF5 §7.5.3)
|
||||
end
|
||||
|
||||
|
||||
@@ -1629,14 +1669,14 @@ local function build_inserted_children(main_cu_offset, main_cu_end_excl, atom_ta
|
||||
|
||||
|
||||
-- 1) Emit the base_type DIE first (member ref4s reference it).
|
||||
-- (Use a local alias for S.next_offset; the rest of the function body still
|
||||
-- uses the bare name `next_offset` from the previous unrefactored version).
|
||||
local next_offset = S.next_offset
|
||||
local base_type_section_offset = next_offset
|
||||
local base_type_section_offset = S.next_offset
|
||||
emit(uleb128(ABBREV_BASE_TYPE))
|
||||
emit("unsigned int\0") -- DW_FORM_string (DW_AT_name)
|
||||
emit(string.char(4)) -- DW_FORM_data1 (DW_AT_byte_size)
|
||||
emit(string.char(DW_ATE_unsigned)) -- DW_FORM_data1 (DW_AT_encoding)
|
||||
-- (The function body below reads S.next_offset directly via the `next_offset` function;
|
||||
-- the old code used a stale local snapshot that stayed at base_type_section_offset.)
|
||||
local function next_offset() return S.next_offset end
|
||||
|
||||
-- Typed local views.
|
||||
-- For each unique (type_name, pointer_depth) pair across all rbind atom fields, emit a synthetic type chain.
|
||||
@@ -1736,7 +1776,7 @@ local function build_inserted_children(main_cu_offset, main_cu_end_excl, atom_ta
|
||||
local function ensure_member_base_type(tn, byte_size, encoding)
|
||||
local key = tn .. "|" .. byte_size .. "|" .. encoding
|
||||
if member_base_type_offsets[key] then return member_base_type_offsets[key] end
|
||||
local off = next_offset
|
||||
local off = next_offset()
|
||||
emit(uleb128(ABBREV_BASE_TYPE))
|
||||
emit(tn .. "\0")
|
||||
emit(string.char(byte_size))
|
||||
@@ -1757,18 +1797,18 @@ local function build_inserted_children(main_cu_offset, main_cu_end_excl, atom_ta
|
||||
if not type_info then
|
||||
-- Unknown typed view — fall back to a generic 4-byte unsigned base_type to keep the wire valid
|
||||
-- (gdb will render as the typename but `print *ptr` will only see the first 4 bytes).
|
||||
local innermost_offset = next_offset
|
||||
local innermost_offset = next_offset()
|
||||
emit(uleb128(ABBREV_BASE_TYPE))
|
||||
emit(tn .. "\0")
|
||||
emit(string.char(U4_BYTE_SIZE)) -- byte_size = 4 (fallback for unknown types)
|
||||
emit(string.char(DW_ATE_unsigned)) -- encoding = unsigned
|
||||
local outermost_offset = next_offset
|
||||
emit(uleb128(9)) -- DW_TAG_pointer_type
|
||||
local outermost_offset = next_offset()
|
||||
emit(uleb128(ABBREV_TYPED_VIEW_POINTER)) -- DW_TAG_pointer_type (abbrev 110; NOT 9)
|
||||
emit(elf_dwarf.write_u32_le(ref4_of(innermost_offset)))
|
||||
type_chain_offsets[tn .. "|" .. depth] = outermost_offset
|
||||
else
|
||||
-- Emit a proper structure_type DIE for this typed view.
|
||||
local struct_offset = next_offset
|
||||
local struct_offset = next_offset()
|
||||
emit(uleb128(ABBREV_STRUCT_TYPE))
|
||||
emit(tn .. "\0") -- DW_AT_name (struct_type has children, no name in abbrev 103 [DW_FORM_string only])
|
||||
emit(uleb128(type_info.byte_size)) -- DW_AT_byte_size (DW_FORM_udata)
|
||||
@@ -1794,11 +1834,11 @@ local function build_inserted_children(main_cu_offset, main_cu_end_excl, atom_ta
|
||||
emit(elf_dwarf.write_u32_le(ref4_of(member_base_off))) -- DW_AT_type ref4 → base_type
|
||||
end
|
||||
emit(string.char(DIE_CHILDREN_TERMINATOR)) -- end of structure_type's children (DWARF5 §7.5.3)
|
||||
-- Emit a single DW_TAG_pointer_type (abbrev 9) pointing at the structure_type.
|
||||
-- Emit a single DW_TAG_pointer_type (abbrev 110, NOT 9) pointing at the structure_type.
|
||||
-- For depth > 1, we'd chain pointer_type → pointer_type → ... → structure_type; not exercised.
|
||||
if depth == 1 then
|
||||
local outermost_offset = next_offset
|
||||
emit(uleb128(9)) -- DW_TAG_pointer_type
|
||||
local outermost_offset = next_offset()
|
||||
emit(uleb128(ABBREV_TYPED_VIEW_POINTER)) -- DW_TAG_pointer_type (abbrev 110; NOT 9)
|
||||
emit(elf_dwarf.write_u32_le(ref4_of(struct_offset))) -- DW_AT_type → structure_type
|
||||
type_chain_offsets[tn .. "|" .. depth] = outermost_offset
|
||||
else
|
||||
@@ -1815,12 +1855,12 @@ local function build_inserted_children(main_cu_offset, main_cu_end_excl, atom_ta
|
||||
-- The void base_type is emitted BEFORE any other typed chain so its ref4 pointer remains stable.
|
||||
-- Follow the SAME pattern as the typed-views chain above: capture the offset BEFORE the uleb tag
|
||||
-- (this is the ref4 target), emit the DIE bytes, then emit the pointer_type pointing at the offset.
|
||||
local void_chain_offset = next_offset
|
||||
local void_chain_offset = next_offset()
|
||||
emit(uleb128(ABBREV_BASE_TYPE))
|
||||
emit("void\0") -- DW_FORM_string (DW_AT_name)
|
||||
emit(string.char(1)) -- DW_FORM_data1 (DW_AT_byte_size = 1; DWARF's "void" base_type)
|
||||
emit(string.char(DW_ATE_unsigned)) -- DW_FORM_data1 (DW_AT_encoding = unsigned; DWARF doesn't define a void encoding but gdb reads the name "void" off the DIE and renders it correctly as `(void *)` when wrapped in a pointer_type)
|
||||
emit(uleb128(9)) -- DW_TAG_pointer_type (abbrev 9; DW_AT_type = ref4 to its target)
|
||||
emit(uleb128(ABBREV_TYPED_VIEW_POINTER)) -- DW_TAG_pointer_type (abbrev 110; NOT 9; void chain target)
|
||||
emit(elf_dwarf.write_u32_le(ref4_of(void_chain_offset))) -- 4-byte ref4: points at the void base_type's tag byte
|
||||
-- type_chain_offsets["void|1"] is what step (f) of the per-RR_<R_Name> chain looks up.
|
||||
type_chain_offsets["void|1"] = void_chain_offset -- both the base_type offset and the pointer_type are emitted consecutively; the OUTERMOST is the pointer_type. The variable's DW_AT_type must reference the pointer_type, not the base_type. Patch below.
|
||||
@@ -1836,9 +1876,9 @@ local function build_inserted_children(main_cu_offset, main_cu_end_excl, atom_ta
|
||||
-- reusing the pre-emitted base type keeps the wire consistent.
|
||||
-- Once this chain is registered as `type_chain_offsets["U4|1"]`, step (e) of the per-RR_<R_Name> precedence chain will resolve `atom_type(U4 *)`
|
||||
-- declarations on aliases like `R_PrimCursor` and `R_OtBase` to `U4 *` (gdb renders as `(unsigned int *)` with the value displayed in hex).
|
||||
emit(uleb128(9)) -- DW_TAG_pointer_type (abbrev 9; DW_AT_type = ref4 to its target)
|
||||
emit(uleb128(ABBREV_TYPED_VIEW_POINTER)) -- DW_TAG_pointer_type (abbrev 110; NOT 9; U4 chain target)
|
||||
emit(elf_dwarf.write_u32_le(ref4_of(base_type_section_offset))) -- 4-byte ref4 → "unsigned int" base_type
|
||||
local u4_chain_offset = next_offset - 5 -- 1 (uleb tag) + 4 (ref4) = 5 bytes; capture the pointer_type's start offset
|
||||
local u4_chain_offset = next_offset() - 5 -- 1 (uleb tag) + 4 (ref4) = 5 bytes; capture the pointer_type's start offset
|
||||
type_chain_offsets["U4|1"] = u4_chain_offset
|
||||
|
||||
-- 2) Emit one DW_TAG_structure_type per unique Binds_X.
|
||||
@@ -1848,7 +1888,7 @@ local function build_inserted_children(main_cu_offset, main_cu_end_excl, atom_ta
|
||||
table.sort(sorted_struct_names)
|
||||
for _, binds_name in ipairs(sorted_struct_names) do
|
||||
local struct = rbind_structs[binds_name]
|
||||
struct_section_offsets[binds_name] = next_offset
|
||||
struct_section_offsets[binds_name] = next_offset()
|
||||
|
||||
emit(uleb128(ABBREV_STRUCT_TYPE))
|
||||
emit(binds_name .. "\0") -- DW_FORM_string (DW_AT_name)
|
||||
@@ -1888,7 +1928,7 @@ local function build_inserted_children(main_cu_offset, main_cu_end_excl, atom_ta
|
||||
local DW_INL_inlined = 0x01
|
||||
for _, comp_name in ipairs(sorted_comp_names) do
|
||||
local def = component_defs[comp_name]
|
||||
abstract_offsets[comp_name] = next_offset
|
||||
abstract_offsets[comp_name] = next_offset()
|
||||
emit(uleb128(ABBREV_ABSTRACT_SUBPROGRAM))
|
||||
emit("mac_" .. comp_name .. "\0") -- DW_FORM_string (DW_AT_name)
|
||||
emit(string.char(DW_INL_inlined)) -- DW_FORM_data1 (DW_AT_inline)
|
||||
@@ -2407,4 +2447,10 @@ function M.run(ctx)
|
||||
return { outputs = {}, errors = {}, warnings = {} }
|
||||
end
|
||||
|
||||
-- Test-only re-exports: keep the module's main M table lean while letting scratch
|
||||
-- tests drive the real emission and offset computation paths.
|
||||
M.compute_loclists_offsets_for_test = compute_loclists_offsets
|
||||
M.build_debug_loclists_section_for_test = build_debug_loclists_section
|
||||
M.tape_piece_size_for_test = tape_piece_size
|
||||
|
||||
return M
|
||||
|
||||
Reference in New Issue
Block a user