mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-07-13 21:01:27 -07:00
Fix off by one ahead issue with stepping into atoms. Support for local register symbols used in atoms + atom bindings locals in gdb.
This commit is contained in:
@@ -14,7 +14,7 @@ typedef U4 const MipsCode;
|
||||
typedef Slice_(MipsCode);
|
||||
typedef Slice_MipsCode MipsAtom;
|
||||
|
||||
#define MipsAtom_(sym) MipsCode tmpl(code,sym) [] align_(4) =
|
||||
#define MipsAtom_(sym) MipsCode sym [] align_(4) =
|
||||
|
||||
// Bare form: file-scope declaration with hardcoded body.
|
||||
// Used for components with no args (e.g., ac_load_tri_indices) or identifier-args (hardcoded register names).
|
||||
@@ -89,13 +89,13 @@ FI_ void tb_init(TapeBuilder* tb, FArena* arena) { tb->ptr = arena->start
|
||||
FI_ TapeBuilder tb_make_old( FArena* arena) { return (TapeBuilder){ arena->start, 0 }; }
|
||||
FI_ TapeBuilder tb_make(Slice mem) { return (TapeBuilder){ mem.ptr, mem.len, 0 }; }
|
||||
|
||||
#define tb_emit_(tb, atom) tb_emit(tb, tmpl(code,atom))
|
||||
#define tb_emit_(tb, atom) tb_emit(tb, atom)
|
||||
FI_ void tb_emit(TapeBuilder* tb, MipsCode* atom) { u4_r(tb->ptr)[tb->used] = u4_(atom); ++ tb->used; }
|
||||
FI_ void tb_data(TapeBuilder* tb, U4 data) { u4_r(tb->ptr)[tb->used] = u4_(data); ++ tb->used; }
|
||||
|
||||
FI_ Slice_U4 tb_end (TapeBuilder* tb) { tb_emit(tb,code_tape_exit); return (Slice_U4){ C_(U4*,tb->ptr), tb->used }; }
|
||||
FI_ Slice_U4 tb_end (TapeBuilder* tb) { tb_emit(tb,tape_exit); return (Slice_U4){ C_(U4*,tb->ptr), tb->used }; }
|
||||
FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Slice_U4){ C_(U4*,tb.ptr), tb.used }; }
|
||||
#define tb_scope(tb) for(U4 tbs_once=0;tbs_once==0;++tbs_once,tb_emit(tb,code_tape_exit))
|
||||
#define tb_scope(tb) for(U4 tbs_once=0;tbs_once==0;++tbs_once,tb_emit(tb,tape_exit))
|
||||
|
||||
#pragma endregion Tape Drive
|
||||
|
||||
@@ -237,9 +237,8 @@ FI_ void atombuilder_unroll(MipsAtomBuilder_R ab, Slice_MipsCode_R code) {
|
||||
|
||||
// When done authoring, utilize this to cap-off the atom
|
||||
FI_ void atombuilder_end(MipsAtomBuilder_R ab) {
|
||||
LP_ MipsAtom_(yield) { mac_yield() };
|
||||
mem_copy(ab->start, u4_(code_yield), S_(code_yield));
|
||||
mem_bump(ab->start, ab->capacity, & ab->used, S_(code_yield));
|
||||
mem_copy(ab->start, u4_(ac_yield), S_(ac_yield));
|
||||
mem_bump(ab->start, ab->capacity, & ab->used, S_(ac_yield));
|
||||
}
|
||||
|
||||
#define mipsatom_from_builder(ab) (MipsAtom){ab.start, ab.used}
|
||||
|
||||
@@ -261,7 +261,7 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
||||
|
||||
LP_ U4 mem_temp_tape[512]; FArena tape_arena; farena_init(& tape_arena, slice_ut_arr(mem_temp_tape));
|
||||
TapeBuilder tb = tb_make_old(&tape_arena); tb_scope(& tb) {
|
||||
tb_emit(& tb, code_rbind_cube_g4_face);
|
||||
tb_emit(& tb, rbind_cube_g4_face);
|
||||
tb_data(& tb, prim_cursor);
|
||||
tb_data(& tb, u4_(smem.cube.faces));
|
||||
tb_data(& tb, u4_(smem.cube.verts));
|
||||
@@ -269,10 +269,10 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
||||
|
||||
for (U4 i = 0; i < Cube_num_faces; i++) {
|
||||
// Two triangles per quad face: (x,y,z) and (x,z,w)
|
||||
tb_emit(& tb, code_cube_g4_face);
|
||||
tb_emit(& tb, cube_g4_face);
|
||||
}
|
||||
|
||||
tb_emit(& tb, code_sync_primitive_arena);
|
||||
tb_emit(& tb, sync_primitive_arena);
|
||||
tb_data(& tb, u4_(& pa->used));
|
||||
tb_data(& tb, prim_base);
|
||||
}
|
||||
@@ -350,20 +350,20 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
|
||||
// Prepare the tape. (Push protocol to tape)
|
||||
LP_ U4 mem_temp_tape[512];
|
||||
TapeBuilder tb = tb_make(slice_ut_arr(mem_temp_tape)); tb_scope(& tb) {
|
||||
tb_emit(& tb, code_set_gte_world);
|
||||
tb_emit(& tb, set_gte_world);
|
||||
tb_data(& tb, u4_(& smem.tform_world));
|
||||
|
||||
tb_emit(& tb, code_rbind_floor_f3_face);
|
||||
tb_emit(& tb, rbind_floor_f3_face);
|
||||
// TODO(Ed): Just use a single context struct ref
|
||||
tb_data(& tb, prim_cursor);
|
||||
tb_data(& tb, u4_(smem.floor.faces));
|
||||
tb_data(& tb, u4_(smem.floor.verts));
|
||||
tb_data(& tb, u4_(ordering_buf));
|
||||
for (U4 i = 0; i < Floor_num_faces; i++) {
|
||||
tb_emit(& tb, code_floor_f3_face);
|
||||
tb_emit(& tb, floor_f3_face);
|
||||
}
|
||||
// After code_floor_f3_face iterations complete, the primitive arena's used counter needs updating.
|
||||
tb_emit(& tb, code_sync_primitive_arena);
|
||||
// After floor_f3_face iterations complete, the primitive arena's used counter needs updating.
|
||||
tb_emit(& tb, sync_primitive_arena);
|
||||
tb_data(& tb, u4_(& pa->used));
|
||||
tb_data(& tb, prim_base);
|
||||
}
|
||||
|
||||
+79
-33
@@ -385,61 +385,107 @@ function build-gte_hello {
|
||||
link-modules $link_modules $elf $link_args
|
||||
make-binary $elf $exe
|
||||
|
||||
# Post-link: emit ONLY build/gen/gdb_tape_atoms_runtime.gdb. The per-source
|
||||
# *.atoms.sourcemap.txt was already generated by the pre-link --all call,
|
||||
# so we skip --atoms-source-map here to avoid re-doing the work. The
|
||||
# gdb-runtime emission requires --elf (for nm-based address lookup) so it
|
||||
# MUST happen post-link. ON by default per user pref 2026-07-11.
|
||||
# TODO(Ed): Do both -gdb-runtime and dwarf-injection passes in a single ps1-meta call.
|
||||
|
||||
# Post-link: emit ONLY build/gen/gdb_tape_atoms_runtime.gdb.
|
||||
# The per-source *.atoms.sourcemap.txt was already generated by the pre-link --all call,
|
||||
# so we skip --atoms-source-map here to avoid re-doing the work.
|
||||
# The gdb-runtime emission requires --elf (for nm-based address lookup) so it MUST happen post-link.
|
||||
ps1-meta -sources $atom_sources -metadata $path_atom_metadata `
|
||||
-out_root (join-path $path_build 'gen') `
|
||||
-passes @('--gdb-runtime') `
|
||||
-extra_args @('--elf', $elf)
|
||||
# F' + G' consolidated: --dwarf-injection now emits 7 .bin blobs
|
||||
# (.debug_line, .debug_aranges, .debug_rnglists, .debug_info, .debug_abbrev, .debug_str, .debug_loc) all in one pass.
|
||||
ps1-meta -sources $atom_sources -metadata $path_atom_metadata `
|
||||
-out_root (join-path $path_build 'gen') `
|
||||
-passes @('--dwarf-injection') `
|
||||
-extra_args @('--elf', $elf)
|
||||
|
||||
# F' track: post-link DWARF injection. The new Lua pass writes
|
||||
# build/gen/<basename>.dwarf_*.bin blobs; we splice them into a COPY
|
||||
# of the ELF via objcopy --update-section (works fine from PowerShell).
|
||||
#TODO(Ed): Move the below into ps-1 meta pass to reduce syscall latency?
|
||||
|
||||
# F' track: post-link DWARF injection. The new Lua pass writes build/gen/<basename>.dwarf_*.bin blobs;
|
||||
# we splice them into a COPY of the ELF via objcopy --update-section (works fine from PowerShell).
|
||||
# The un-injected $elf + $exe are unchanged (shipping binary).
|
||||
$dwarfLineBin = Join-Path (Join-Path $path_build 'gen') 'hello_gte.dwarf_line.bin'
|
||||
$dwarfArangesBin = Join-Path (Join-Path $path_build 'gen') 'hello_gte.dwarf_aranges.bin'
|
||||
$dwarfRnglistsBin = Join-Path (Join-Path $path_build 'gen') 'hello_gte.dwarf_rnglists.bin'
|
||||
$injectElf = Join-Path $path_build 'hello_gte.dwarf-injected.elf'
|
||||
if ((Test-Path $dwarfLineBin) -and (Test-Path $dwarfArangesBin) -and (Test-Path $dwarfRnglistsBin)) {
|
||||
if ((Test-Path $dwarfLineBin) -and (Test-Path $dwarfArangesBin) -and (Test-Path $dwarfRnglistsBin))
|
||||
{
|
||||
Write-Host "[build] DWARF-injecting $elf -> $injectElf"
|
||||
Copy-Item -LiteralPath $elf -Destination $injectElf
|
||||
& $Objcopy --update-section ".debug_line=$dwarfLineBin" $injectElf
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
$last_exit_code_error = $LASTEXITCODE -ne 0
|
||||
if ($last_exit_code_error) {
|
||||
Write-Warning "[build] objcopy .debug_line update failed (exit $LASTEXITCODE); removing $injectElf"
|
||||
Remove-Item -LiteralPath $injectElf -ErrorAction SilentlyContinue
|
||||
} else {
|
||||
& $Objcopy --update-section ".debug_aranges=$dwarfArangesBin" $injectElf
|
||||
return;
|
||||
}
|
||||
& $Objcopy --update-section ".debug_aranges=$dwarfArangesBin" $injectElf
|
||||
$last_exit_code_error = $LASTEXITCODE -ne 0
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "[build] objcopy .debug_aranges update failed (exit $LASTEXITCODE); removing $injectElf"
|
||||
Remove-Item -LiteralPath $injectElf -ErrorAction SilentlyContinue
|
||||
return;
|
||||
}
|
||||
& $Objcopy --update-section ".debug_rnglists=$dwarfRnglistsBin" $injectElf
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "[build] objcopy .debug_rnglists update failed (exit $LASTEXITCODE); removing $injectElf"
|
||||
Remove-Item -LiteralPath $injectElf -ErrorAction SilentlyContinue
|
||||
}
|
||||
else
|
||||
{
|
||||
# Baked atoms execute from RAM but are emitted as C data arrays, so their ELF sections lack SHF_EXECINSTR.
|
||||
# GDB discards line rows for non-code sections.
|
||||
# Mark only the debug-copy sections executable; the shipping ELF and PS-EXE remain byte/flag unchanged.
|
||||
& $Objcopy `
|
||||
--set-section-flags ".rodata=alloc,load,readonly,code,contents" `
|
||||
--set-section-flags ".data=alloc,load,data,code,contents" `
|
||||
$injectElf
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "[build] objcopy .debug_aranges update failed (exit $LASTEXITCODE); removing $injectElf"
|
||||
Write-Warning "[build] objcopy atom-section flag update failed (exit $LASTEXITCODE); removing $injectElf"
|
||||
Remove-Item -LiteralPath $injectElf -ErrorAction SilentlyContinue
|
||||
} else {
|
||||
& $Objcopy --update-section ".debug_rnglists=$dwarfRnglistsBin" $injectElf
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "[build] objcopy .debug_rnglists update failed (exit $LASTEXITCODE); removing $injectElf"
|
||||
Remove-Item -LiteralPath $injectElf -ErrorAction SilentlyContinue
|
||||
} else {
|
||||
# Baked atoms execute from RAM but are emitted as C data arrays, so
|
||||
# their ELF sections lack SHF_EXECINSTR. GDB discards line rows for
|
||||
# non-code sections. Mark only the debug-copy sections executable;
|
||||
# the shipping ELF and PS-EXE remain byte/flag unchanged.
|
||||
& $Objcopy `
|
||||
--set-section-flags ".rodata=alloc,load,readonly,code,contents" `
|
||||
--set-section-flags ".data=alloc,load,data,code,contents" `
|
||||
$injectElf
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "[build] objcopy atom-section flag update failed (exit $LASTEXITCODE); removing $injectElf"
|
||||
Remove-Item -LiteralPath $injectElf -ErrorAction SilentlyContinue
|
||||
} else {
|
||||
Write-Host "[build] DWARF-injected ELF: $injectElf"
|
||||
}
|
||||
}
|
||||
Write-Host "[build] DWARF-injected ELF: $injectElf"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# G' (atom locals) is now part of --dwarf-injection.
|
||||
# The F' splice block above already covered .debug_line / .debug_aranges / .debug_rnglists;
|
||||
# we extend the same Copy-Item + objcopy chain to splice the G' 4 sections
|
||||
# (.debug_info, .debug_abbrev, .debug_str via --update-section; .debug_loc via --add-section since it doesn't exist in the source ELF).
|
||||
$dwarfInfoBin = Join-Path (Join-Path $path_build 'gen') 'hello_gte.dwarf_info.bin'
|
||||
$dwarfAbbrevBin = Join-Path (Join-Path $path_build 'gen') 'hello_gte.dwarf_abbrev.bin'
|
||||
$dwarfStrBin = Join-Path (Join-Path $path_build 'gen') 'hello_gte.dwarf_str.bin'
|
||||
$dwarfLocBin = Join-Path (Join-Path $path_build 'gen') 'hello_gte.dwarf_loc.bin'
|
||||
if ((Test-Path $dwarfInfoBin) -and (Test-Path $dwarfAbbrevBin) -and (Test-Path $dwarfStrBin) -and (Test-Path $dwarfLocBin))
|
||||
{
|
||||
Write-Host "[build] G' atom-locals: splicing .debug_info/.debug_abbrev/.debug_str/.debug_loc into $injectElf"
|
||||
& $Objcopy --update-section ".debug_info=$dwarfInfoBin" $injectElf
|
||||
$last_exit_code_error = ($LASTEXITCODE -ne 0)
|
||||
if ($last_exit_code_error) {
|
||||
Write-Warning "[build] objcopy .debug_info update failed (exit $LASTEXITCODE)"
|
||||
return;
|
||||
}
|
||||
& $Objcopy --update-section ".debug_abbrev=$dwarfAbbrevBin" $injectElf
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "[build] objcopy .debug_abbrev update failed (exit $LASTEXITCODE)"
|
||||
return;
|
||||
}
|
||||
& $Objcopy --update-section ".debug_str=$dwarfStrBin" $injectElf
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "[build] objcopy .debug_str update failed (exit $LASTEXITCODE)"
|
||||
}
|
||||
else
|
||||
{
|
||||
# .debug_loc doesn't exist in the source ELF; --add-section creates it.
|
||||
& $Objcopy --add-section ".debug_loc=$dwarfLocBin" $injectElf
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "[build] objcopy .debug_loc add-section failed (exit $LASTEXITCODE)"
|
||||
} else {
|
||||
Write-Host "[build] G' atom-locals-injected: $injectElf"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-28
@@ -3,11 +3,9 @@
|
||||
--- All ELF32 + DWARF-specific code lives here.
|
||||
---
|
||||
--- **What this module contains:**
|
||||
--- - **Format-constant tables** (
|
||||
--- the byte-offset / opcode / size encyclopedias for ELF32, DWARF4 aranges, DWARF5 rnglists, DWARF line-program, MIPS).
|
||||
--- - **Format-constant tables** (the byte-offset / opcode / size encyclopedias for ELF32, DWARF4 aranges, DWARF5 rnglists, DWARF line-program, MIPS).
|
||||
--- Every constant carries a spec:` comment naming the spec section that defines it (convention established by F'').
|
||||
--- - **I/O helpers**: little-endian byte read/write, ELF32 section walker, nm symbol reader,
|
||||
--- source-map parser, native directory glob.
|
||||
--- - **I/O helpers**: little-endian byte read/write, ELF32 section walker, nm symbol reader, source-map parser, native directory glob.
|
||||
---
|
||||
--- **Conventions:** tabs (1/level), EmmyLua annotations, no regex,
|
||||
--- Lua 5.3 compatible.
|
||||
@@ -208,7 +206,6 @@ end
|
||||
--- **Cost:** one file open + one `f:seek` + one `f:read` per section header
|
||||
--- (we walk all `e_shnum` headers regardless of how many names are requested, to find the .shstrtab first).
|
||||
--- For frequent callers, pass the union of all needed sections in one call.
|
||||
---
|
||||
-- can add `.debug_info` + `.debug_loc` + `.debug_str_offsets` to the list without writing a 2nd ELF walker.
|
||||
--- @param elf_path Path
|
||||
--- @param section_names string[] -- list of section names to read
|
||||
@@ -305,9 +302,8 @@ function M.read_elf_sections(elf_path, section_names)
|
||||
return result
|
||||
end
|
||||
|
||||
--- Read ELF symbol addresses by walking the `.symtab` + `.strtab` sections
|
||||
--- directly (no `nm` subprocess). Returns a map `{name -> {addr, size_bytes}}`
|
||||
--- for every `code_<name>` symbol.
|
||||
--- Read ELF symbol addresses by walking the `.symtab` + `.strtab` sections directly (no `nm` subprocess).
|
||||
--- Returns a map `{name -> {addr, size_bytes}}` for every `code_<name>` symbol.
|
||||
---
|
||||
--- **Why direct parsing instead of `mipsel-none-elf-nm -S`?**
|
||||
--- The `nm` subprocess costs ~50ms per spawn on Windows (cmd.exe + mipsel-none-elf-nm.exe). Parsing `.symtab` ourselves is ~0ms.
|
||||
@@ -319,9 +315,6 @@ end
|
||||
--- - We strip the `code_` prefix to match the previous `read_nm` output.
|
||||
--- - `st_size > 0` filter excludes undefined/imported symbols.
|
||||
---
|
||||
--- **Cost:** ~1ms (file open + 2 section reads + symtab iteration).
|
||||
--- Previously: ~50ms (nm subprocess spawn).
|
||||
---
|
||||
--- @param elf_path Path
|
||||
--- @return table<string, {integer, integer}>
|
||||
function M.read_nm(elf_path)
|
||||
@@ -359,11 +352,11 @@ function M.read_nm(elf_path)
|
||||
-- Extract the name from .strtab (null-terminated C string).
|
||||
local name_end = strtab:find("\0", st_name_off + 1, true) or (st_name_off + 1)
|
||||
local name = strtab:sub(st_name_off + 1, name_end - 1)
|
||||
-- Filter: only `code_<name>` symbols (matches nm output).
|
||||
local short = name:match("^code_(.+)$")
|
||||
if short then
|
||||
-- Filter: keep all symbol-table symbols (atoms emit their name as the bare `<name>` since the `code_` prefix was removed from the MipsAtom_ macro).
|
||||
-- The atoms_source_map pass already filters out non-atom symbols via the source-map.txt cross-ref.
|
||||
if name and #name > 0 then
|
||||
local st_value = M.read_u32_le(symtab, entry_off + SYM_ST_VALUE - 1)
|
||||
addrs[short] = { st_value, st_size }
|
||||
addrs[name] = { st_value, st_size }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -376,9 +369,8 @@ end
|
||||
-- LEB128 encoders (Unsigned + Signed Little-Endian Base 128)
|
||||
-- ════════════════════════════════════════════════════════════════════════════
|
||||
--
|
||||
-- DWARF uses LEB128 to encode variable-length integers in its wire format
|
||||
-- (line-program opcodes, DW_AT values, etc.). Both encoders pack 7 bits
|
||||
-- of data per byte + 1 bit of "more bytes follow" signaling.
|
||||
-- DWARF uses LEB128 to encode variable-length integers in its wire format (line-program opcodes, DW_AT values, etc.).
|
||||
-- Both encoders pack 7 bits of data per byte + 1 bit of "more bytes follow" signaling.
|
||||
--
|
||||
-- Per-byte layout:
|
||||
--
|
||||
@@ -391,8 +383,7 @@ end
|
||||
-- bit 6 = 0 → value is positive (or zero); zero-extend on decode
|
||||
-- bit 6 = 1 → value is negative; one-extend on decode
|
||||
--
|
||||
-- The signed encoder must emit the MINIMUM number of bytes whose final 7-bit
|
||||
-- payload already has the correct sign bit set
|
||||
-- The signed encoder must emit the MINIMUM number of bytes whose final 7-bit payload already has the correct sign bit set
|
||||
-- (otherwise the decoder would round-trip to a different value).
|
||||
--
|
||||
-- Spec: DWARF5 §7.6 "Variable-Length Data" / Appendix C.
|
||||
@@ -403,14 +394,11 @@ local LEB_CONT_BIT = 0x80
|
||||
-- Low 7 bits of each LEB128 byte. The actual data payload.
|
||||
local LEB_DATA_MASK = 0x7F
|
||||
|
||||
-- Bit 6 of the 7-bit data (i.e. 0x40). For SLEB128: the sign-bit position
|
||||
-- used by the decoder for sign extension. Encoders MUST stop when the next
|
||||
-- byte would be redundant AND the sign bit in the last byte matches the
|
||||
-- value's sign.
|
||||
-- Bit 6 of the 7-bit data (i.e. 0x40). For SLEB128: the sign-bit position used by the decoder for sign extension.
|
||||
-- Encoders MUST stop when the next byte would be redundant AND the sign bit in the last byte matches the value's sign.
|
||||
local SLEB_SIGN_BIT = 0x40
|
||||
|
||||
--- ULEB128 (Unsigned Little-Endian Base 128) encoder. Returns the byte
|
||||
--- string for the non-negative integer `n`.
|
||||
--- ULEB128 (Unsigned Little-Endian Base 128) encoder. Returns the byte string for the non-negative integer `n`.
|
||||
---
|
||||
--- Algorithm:
|
||||
--- - Extract the low 7 bits of `n` (LEB_DATA_MASK = 0x7F).
|
||||
@@ -442,8 +430,7 @@ end
|
||||
--- - If `n == -1` (sign-extended all-1s) AND bit 6 of the data = 1 → negative terminator (sign bit says "one-extend").
|
||||
---
|
||||
--- Without these checks, the decoder would round-trip to a different value
|
||||
--- (e.g. encoding `0` as `0x80 0x00` decodes to `0` correctly but is 2
|
||||
--- bytes long; the termination check picks the 1-byte `0x00` form).
|
||||
--- (e.g. encoding `0` as `0x80 0x00` decodes to `0` correctly but is 2 bytes long; the termination check picks the 1-byte `0x00` form).
|
||||
---
|
||||
--- @param n integer -- any integer (negative allowed)
|
||||
--- @return string
|
||||
|
||||
+1094
-43
File diff suppressed because it is too large
Load Diff
+15
-10
@@ -158,12 +158,16 @@ local PASSES = {
|
||||
["dwarf-injection"] = {
|
||||
module = "passes.dwarf_injection",
|
||||
kind = "shared",
|
||||
deps = {"atoms-source-map"},
|
||||
desc = "Inject per-atom .debug_line + .debug_aranges into the ELF (post-link; writes section .bin blobs for objcopy splice)",
|
||||
deps = {"scan-source", "atoms-source-map"},
|
||||
desc = "Inject per-atom .debug_line + .debug_aranges (F') + per-atom .debug_info subprogram + per-wave-context-reg .debug_info variables (G') into the ELF (post-link; writes 7 section .bin blobs for objcopy splice). (rbind composite) reads ctx.sources[i].scan to find atom_bind(Binds_X) atoms + their Binds_X struct fields; emits per-Binds_X DW_TAG_structure_type DIEs + per-rbind-atom DW_TAG_variable 'bind_args' DIEs with piece-chain DW_OP_bregN/DW_OP_piece location expressions.",
|
||||
out = {
|
||||
{ kind = "report", path_template = "<out_root>/<basename>.dwarf_line.bin" },
|
||||
{ kind = "report", path_template = "<out_root>/<basename>.dwarf_aranges.bin" },
|
||||
{ kind = "report", path_template = "<out_root>/<basename>.dwarf_line.bin" },
|
||||
{ kind = "report", path_template = "<out_root>/<basename>.dwarf_aranges.bin" },
|
||||
{ kind = "report", path_template = "<out_root>/<basename>.dwarf_rnglists.bin" },
|
||||
{ kind = "report", path_template = "<out_root>/<basename>.dwarf_abbrev.bin" },
|
||||
{ kind = "report", path_template = "<out_root>/<basename>.dwarf_info.bin" },
|
||||
{ kind = "report", path_template = "<out_root>/<basename>.dwarf_str.bin" },
|
||||
{ kind = "report", path_template = "<out_root>/<basename>.dwarf_loc.bin" },
|
||||
},
|
||||
},
|
||||
report = {
|
||||
@@ -290,6 +294,8 @@ FLAG_HANDLERS["--dwarf-injection"] = function(args)
|
||||
args.requested_set[#args.requested_set + 1] = "dwarf-injection"
|
||||
end
|
||||
|
||||
-- G' (atom locals) is now consolidated into --dwarf-injection; no separate flag.
|
||||
|
||||
-- Pass-flag handler. Reads the closed-set table, expands --all, appends to requested_set. Single-statement, no nesting.
|
||||
FLAG_HANDLERS[PASS_FLAG_DISPATCH_KEY] = function(args, a)
|
||||
local name = PASS_FLAG_TO_NAME[a]
|
||||
@@ -381,9 +387,8 @@ local function build_ctx(args)
|
||||
dir = dir:sub(1, -2)
|
||||
end
|
||||
|
||||
-- src.scan is populated by the "scan-source" pass (the first pass in the
|
||||
-- dep graph). build_ctx just opens + reads the files; the scan itself
|
||||
-- happens in the pass module, not inline in the orchestrator.
|
||||
-- src.scan is populated by the "scan-source" pass (the first pass in the dep graph).
|
||||
-- build_ctx just opens + reads the files; the scan itself happens in the pass module, not inline in the orchestrator.
|
||||
sources[#sources + 1] = {
|
||||
path = path,
|
||||
text = text,
|
||||
@@ -523,9 +528,9 @@ local function topo_sort(passes, requested_set)
|
||||
process_next_ready(passes, needed, in_degree, ready, order)
|
||||
end
|
||||
|
||||
-- Cycle detection: if order doesn't include all needed passes, some are stuck with in_degree > 0 (the cycle closed on itself
|
||||
-- before Kahn could process them). Without this check, a fully-closed cycle (e.g. A -> B -> A) would silently return an emspty order list,
|
||||
-- leaving the orchestrator to dispatch nothing.
|
||||
-- Cycle detection: if order doesn't include all needed passes, some are stuck with in_degree > 0
|
||||
-- (the cycle closed on itself before Kahn could process them).
|
||||
-- Without this check, a fully-closed cycle (e.g. A -> B -> A) would silently return an emspty order list, leaving the orchestrator to dispatch nothing.
|
||||
if #order ~= count_entries(needed) then
|
||||
for name, deg in pairs(in_degree) do
|
||||
if deg > 0 then
|
||||
|
||||
Reference in New Issue
Block a user