╭────────────╮ │next lines →│ ╰────────────╯ ╭ Dwarf.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 const Dwarf = @This(); 2 3 const std = @import("std"); 4 const Io = std.Io; 5 const Allocator = std.mem.Allocator; 6 const DW = std.dwarf; 7 const Zir = std.zig.Zir; 8 const assert = std.debug.assert; 9 const log = std.log.scoped(.dwarf); 10 const Writer = std.Io.Writer; 11 12 const InternPool = @import("../InternPool.zig"); 13 const Module = @import("../Module.zig"); 14 const Type = @import("../Type.zig"); 15 const Value = @import("../Value.zig"); 16 const Zcu = @import("../Zcu.zig"); 17 const codegen = @import("../codegen.zig"); 18 const dev = @import("../dev.zig"); 19 const link = @import("../link.zig"); 20 const target_info = @import("../target.zig"); 21 22 gpa: Allocator, 23 bin_file: *link.File, 24 format: DW.Format, 25 endian: std.lang.Endian, 26 address_size: AddressSize, 27 28 const_pool: link.ConstPool, 29 30 mods: std.array_hash_map.Auto(*Module, ModInfo), 31 /// Indices are `link.ConstPool.Index`. 32 values: std.ArrayList(struct { Unit.Index, Entry.Index }), 33 navs: std.array_hash_map.Auto(InternPool.Nav.Index, Entry.Index), 34 decls: std.array_hash_map.Auto(InternPool.TrackedInst.Index, Entry.Index), 35 36 debug_abbrev: DebugAbbrev, 37 debug_aranges: DebugAranges, 38 debug_frame: DebugFrame, 39 debug_info: DebugInfo, 40 debug_line: DebugLine, 41 debug_line_str: StringSection, 42 debug_loclists: DebugLocLists, 43 debug_rnglists: DebugRngLists, 44 debug_str: StringSection, 45 46 pub const UpdateError = error{ 47 WriteFailed, 48 ReinterpretDeclRef, 49 Unimplemented, 50 EndOfStream, 51 Underflow, 52 UnexpectedEndOfFile, 53 NonResizable, 54 Overflow, 55 } || 56 link.Error || 57 Io.File.OpenError || 58 Io.File.LengthError || 59 Io.File.ReadPositionalError || 60 Io.File.WritePositionalError; 61 62 pub const RelocError = Io.File.PWriteError; 63 64 pub const AddressSize = enum(u8) { 65 @"32" = 4, 66 @"64" = 8, 67 _, 68 }; 69 70 const ModInfo = struct { 71 root_dir_path: Entry.Index, 72 dirs: std.array_hash_map.Auto(Unit.Index, void), 73 files: std.array_hash_map.Auto(Zcu.File.Index, void), 74 75 fn deinit(mod_info: *ModInfo, gpa: Allocator) void { 76 mod_info.dirs.deinit(gpa); 77 mod_info.files.deinit(gpa); 78 mod_info.* = undefined; 79 } 80 }; 81 82 const DebugAbbrev = struct { 83 section: Section, 84 const unit: Unit.Index = @fromBackingInt(@intCast(0)); 85 86 const header_bytes = 0; 87 88 const trailer_bytes = uleb128Bytes(@backingInt(AbbrevCode.null)); 89 }; 90 91 const DebugAranges = struct { 92 section: Section, 93 94 fn headerBytes(dwarf: *Dwarf) u32 { 95 return dwarf.unitLengthBytes() + 2 + dwarf.sectionOffsetBytes() + 1 + 1; 96 } 97 98 fn trailerBytes(dwarf: *Dwarf) u32 { 99 return @backingInt(dwarf.address_size) * 2; 100 } 101 }; 102 103 const DebugFrame = struct { 104 header: Header, 105 section: Section, 106 107 const Format = enum { none, debug_frame, eh_frame }; 108 const Header = struct { 109 format: Format, 110 code_alignment_factor: u32, 111 data_alignment_factor: i32, 112 return_address_register: u32, 113 initial_instructions: []const Cfa, 114 }; 115 116 fn headerBytes(dwarf: *Dwarf) u32 { 117 const target = &dwarf.bin_file.comp.root_mod.resolved_target.result; 118 return @intCast(switch (dwarf.debug_frame.header.format) { 119 .none => return 0, 120 .debug_frame => dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() + 1 + "\x00".len + 1 + 1, 121 .eh_frame => dwarf.unitLengthBytes() + 4 + 1 + "zR\x00".len + 122 uleb128Bytes(1) + 1, 123 } + switch (target.cpu.arch) { 124 .x86_64 => len: { 125 dev.checkAny(&.{ .llvm_backend, .x86_64_backend }); 126 const Register = @import("../codegen/x86_64/bits.zig").Register; 127 break :len uleb128Bytes(1) + sleb128Bytes(-8) + uleb128Bytes(Register.rip.dwarfNum()) + 128 1 + uleb128Bytes(Register.rsp.dwarfNum()) + sleb128Bytes(-1) + 129 1 + uleb128Bytes(1); 130 }, 131 else => unreachable, 132 }); 133 } 134 135 fn trailerBytes(dwarf: *Dwarf) u32 { 136 return @intCast(switch (dwarf.debug_frame.header.format) { 137 .none => 0, 138 .debug_frame => dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() + 1 + "\x00".len + 1 + 1 + uleb128Bytes(1) + sleb128Bytes(1) + uleb128Bytes(0), 139 .eh_frame => dwarf.unitLengthBytes() + 4 + 1 + "\x00".len + uleb128Bytes(1) + sleb128Bytes(1) + uleb128Bytes(0), 140 }); 141 } 142 }; 143 144 const DebugInfo = struct { 145 section: Section, 146 147 fn headerBytes(dwarf: *Dwarf) u32 { 148 return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() + 149 uleb128Bytes(@backingInt(AbbrevCode.compile_unit)) + 1 + dwarf.sectionOffsetBytes() * 6 + uleb128Bytes(0) + 150 uleb128Bytes(@backingInt(AbbrevCode.module)) + dwarf.sectionOffsetBytes() + uleb128Bytes(0); 151 } 152 153 fn declEntryLineOff(dwarf: *Dwarf) u32 { 154 return AbbrevCode.decl_bytes + dwarf.sectionOffsetBytes(); 155 } 156 157 fn declAbbrevCode(debug_info: *DebugInfo, unit: Unit.Index, entry: Entry.Index) !AbbrevCode { 158 const dwarf: *Dwarf = @fieldParentPtr("debug_info", debug_info); 159 const comp = dwarf.bin_file.comp; 160 const io = comp.io; 161 const unit_ptr = debug_info.section.getUnit(unit); 162 const entry_ptr = unit_ptr.getEntry(entry); 163 if (entry_ptr.len < AbbrevCode.decl_bytes) return .null; 164 var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined; 165 if (try dwarf.getFile().?.readPositionalAll( 166 io, 167 &abbrev_code_buf, 168 debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off, 169 ) != abbrev_code_buf.len) return error.InputOutput; 170 var abbrev_code_reader: std.Io.Reader = .fixed(&abbrev_code_buf); 171 return @fromBackingInt(@intCast( 172 abbrev_code_reader.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable, 173 )); 174 } 175 176 const trailer_bytes = 1 + 1; 177 }; 178 179 const DebugLine = struct { 180 header: Header, 181 section: Section, 182 183 const Header = struct { 184 minimum_instruction_length: u8, 185 maximum_operations_per_instruction: u8, 186 default_is_stmt: bool, 187 line_base: i8, 188 line_range: u8, 189 opcode_base: u8, 190 }; 191 192 fn dirIndexInfo(dir_count: u32) struct { bytes: u8, form: DeclValEnum(DW.FORM) } { 193 return if (dir_count <= 1 << 8) 194 .{ .bytes = 1, .form = .data1 } 195 else if (dir_count <= 1 << 16) 196 .{ .bytes = 2, .form = .data2 } 197 else 198 unreachable; 199 } 200 201 fn headerBytes(dwarf: *Dwarf, dir_count: u32, file_count: u32) u32 { 202 const dir_index_info = dirIndexInfo(dir_count); 203 return dwarf.unitLengthBytes() + 2 + 1 + 1 + dwarf.sectionOffsetBytes() + 1 + 1 + 1 + 1 + 1 + 1 + 1 * (dwarf.debug_line.header.opcode_base - 1) + 204 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(dir_count) + (dwarf.sectionOffsetBytes()) * dir_count + 205 1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(DW.LNCT.directory_index) + uleb128Bytes(@backingInt(dir_index_info.form)) + uleb128Bytes(DW.LNCT.LLVM_source) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(file_count) + (dwarf.sectionOffsetBytes() + dir_index_info.bytes + dwarf.sectionOffsetBytes()) * file_count; 206 } 207 208 const trailer_bytes = 1 + uleb128Bytes(1) + 1; 209 }; 210 211 const DebugLocLists = struct { 212 section: Section, 213 214 fn baseOffset(dwarf: *Dwarf) u32 { 215 return dwarf.unitLengthBytes() + 2 + 1 + 1 + 4; 216 } 217 218 fn headerBytes(dwarf: *Dwarf) u32 { 219 return baseOffset(dwarf); 220 } 221 222 const trailer_bytes = 0; 223 }; 224 225 const DebugRngLists = struct { 226 section: Section, 227 228 const baseOffset = DebugLocLists.baseOffset; 229 230 fn headerBytes(dwarf: *Dwarf) u32 { 231 return baseOffset(dwarf) + dwarf.sectionOffsetBytes() * 1; 232 } 233 234 const trailer_bytes = 1; 235 }; 236 237 const StringSection = struct { 238 contents: std.ArrayList(u8), 239 map: std.array_hash_map.Auto(void, void), 240 section: Section, 241 242 const unit: Unit.Index = @fromBackingInt(@intCast(0)); 243 244 const init: StringSection = .{ 245 .contents = .empty, 246 .map = .empty, 247 .section = Section.init, 248 }; 249 250 fn deinit(str_sec: *StringSection, gpa: Allocator) void { 251 str_sec.contents.deinit(gpa); 252 str_sec.map.deinit(gpa); 253 str_sec.section.deinit(gpa); 254 } 255 256 fn addString(str_sec: *StringSection, dwarf: *Dwarf, str: []const u8) UpdateError!Entry.Index { 257 const gop = try str_sec.map.getOrPutAdapted(dwarf.gpa, str, Adapter{ .str_sec = str_sec }); 258 const entry: Entry.Index = @fromBackingInt(@intCast(gop.index)); 259 if (!gop.found_existing) { 260 errdefer _ = str_sec.map.pop(); 261 const unit_ptr = str_sec.section.getUnit(unit); 262 assert(try str_sec.section.getUnit(unit).addEntry(dwarf.gpa) == entry); 263 errdefer _ = unit_ptr.entries.pop(); 264 const entry_ptr = unit_ptr.getEntry(entry); 265 if (unit_ptr.last.unwrap()) |last_entry| 266 unit_ptr.getEntry(last_entry).next = entry.toOptional(); 267 entry_ptr.prev = unit_ptr.last; 268 unit_ptr.last = entry.toOptional(); 269 entry_ptr.off = @intCast(str_sec.contents.items.len); 270 entry_ptr.len = @intCast(str.len + 1); 271 try str_sec.contents.ensureUnusedCapacity(dwarf.gpa, str.len + 1); 272 str_sec.contents.appendSliceAssumeCapacity(str); 273 str_sec.contents.appendAssumeCapacity(0); 274 str_sec.section.dirty = true; 275 } 276 return entry; 277 } 278 279 const Adapter = struct { 280 str_sec: *StringSection, 281 282 pub fn hash(_: Adapter, key: []const u8) u32 { 283 return @truncate(std.hash.Wyhash.hash(0, key)); 284 } 285 286 pub fn eql(adapter: Adapter, key: []const u8, _: void, rhs_index: usize) bool { 287 const entry = adapter.str_sec.section.getUnit(unit).getEntry(@fromBackingInt(@intCast(rhs_index))); 288 return std.mem.eql(u8, key, adapter.str_sec.contents.items[entry.off..][0 .. entry.len - 1 :0]); 289 } 290 }; 291 }; 292 293 /// A linker section containing a sequence of `Unit`s. 294 pub const Section = struct { 295 dirty: bool, 296 pad_entries_to_ideal: bool, 297 alignment: InternPool.Alignment, 298 index: u32, 299 first: Unit.Index.Optional, 300 last: Unit.Index.Optional, 301 len: u64, 302 units: std.ArrayList(Unit), 303 304 pub const Index = enum { 305 debug_abbrev, 306 debug_aranges, 307 debug_frame, 308 debug_info, 309 debug_line, 310 debug_line_str, 311 debug_loclists, 312 debug_rnglists, 313 debug_str, 314 }; 315 316 const init: Section = .{ 317 .dirty = true, 318 .pad_entries_to_ideal = true, 319 .alignment = .@"1", 320 .index = std.math.maxInt(u32), 321 .first = .none, 322 .last = .none, 323 .units = .empty, 324 .len = 0, 325 }; 326 327 fn deinit(sec: *Section, gpa: Allocator) void { 328 for (sec.units.items) |*unit| unit.deinit(gpa); 329 sec.units.deinit(gpa); 330 sec.* = undefined; 331 } 332 333 fn off(sec: Section, dwarf: *Dwarf) u64 { 334 if (dwarf.bin_file.cast(.elf)) |elf_file| { 335 const zo = elf_file.zigObjectPtr().?; 336 const atom = zo.symbol(sec.index).atom(elf_file).?; 337 return atom.offset(elf_file); 338 } else if (dwarf.bin_file.cast(.macho)) |macho_file| { 339 const header = if (macho_file.d_sym) |d_sym| 340 d_sym.sections.items[sec.index] 341 else 342 macho_file.sections.items(.header)[sec.index]; 343 return header.offset; 344 } else unreachable; 345 } 346 347 fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index { 348 const unit: Unit.Index = @fromBackingInt(@intCast(sec.units.items.len)); 349 const unit_ptr = try sec.units.addOne(dwarf.gpa); 350 errdefer sec.popUnit(dwarf.gpa); 351 const aligned_header_len: u32 = @intCast(sec.alignment.forward(header_len)); 352 const aligned_trailer_len: u32 = @intCast(sec.alignment.forward(trailer_len)); 353 unit_ptr.* = .{ 354 .prev = sec.last, 355 .next = .none, 356 .first = .none, 357 .last = .none, 358 .free = .none, 359 .header_len = aligned_header_len, 360 .trailer_len = aligned_trailer_len, 361 .off = 0, 362 .len = aligned_header_len + aligned_trailer_len, 363 .entries = .empty, 364 .cross_unit_relocs = .empty, 365 .cross_section_relocs = .empty, 366 }; 367 if (sec.last.unwrap()) |last_unit| { 368 const last_unit_ptr = sec.getUnit(last_unit); 369 last_unit_ptr.next = unit.toOptional(); 370 unit_ptr.off = last_unit_ptr.off + sec.padUnitToIdeal(last_unit_ptr.len); 371 } 372 if (sec.first == .none) 373 sec.first = unit.toOptional(); 374 sec.last = unit.toOptional(); 375 try sec.resize(dwarf, unit_ptr.off + sec.padUnitToIdeal(unit_ptr.len)); 376 return unit; 377 } 378 379 fn unlinkUnit(sec: *Section, unit: Unit.Index) void { 380 const unit_ptr = sec.getUnit(unit); 381 if (unit_ptr.prev.unwrap()) |prev_unit| sec.getUnit(prev_unit).next = unit_ptr.next; 382 if (unit_ptr.next.unwrap()) |next_unit| sec.getUnit(next_unit).prev = unit_ptr.prev; 383 if (sec.first == unit.toOptional()) sec.first = unit_ptr.next; 384 if (sec.last == unit.toOptional()) sec.last = unit_ptr.prev; 385 } 386 387 fn popUnit(sec: *Section, gpa: Allocator) void { 388 const unit_index: Unit.Index = @fromBackingInt(@intCast(sec.units.items.len - 1)); 389 sec.unlinkUnit(unit_index); 390 var unit = sec.units.pop().?; 391 unit.deinit(gpa); 392 } 393 394 pub fn getUnit(sec: *Section, unit: Unit.Index) *Unit { 395 return &sec.units.items[@backingInt(unit)]; 396 } 397 398 fn resizeEntry( 399 sec: *Section, 400 unit: Unit.Index, 401 entry: Entry.Index, 402 dwarf: *Dwarf, 403 len: u32, 404 ) (UpdateError || Writer.Error)!void { 405 const unit_ptr = sec.getUnit(unit); 406 const entry_ptr = unit_ptr.getEntry(entry); 407 if (len > 0) { 408 if (entry_ptr.len == 0) { 409 assert(entry_ptr.prev == .none and entry_ptr.next == .none); 410 entry_ptr.off = if (unit_ptr.last.unwrap()) |last_entry| off: { 411 const last_entry_ptr = unit_ptr.getEntry(last_entry); 412 last_entry_ptr.next = entry.toOptional(); 413 break :off last_entry_ptr.off + sec.padEntryToIdeal(last_entry_ptr.len); 414 } else 0; 415 entry_ptr.prev = unit_ptr.last; 416 unit_ptr.last = entry.toOptional(); 417 if (unit_ptr.first == .none) unit_ptr.first = unit_ptr.last; 418 if (entry_ptr.prev.unwrap()) |prev_entry| try unit_ptr.getEntry(prev_entry).pad(unit_ptr, sec, dwarf); 419 } 420 try entry_ptr.resize(unit_ptr, sec, dwarf, len); 421 } 422 assert(entry_ptr.len == len); 423 } 424 425 fn replaceEntry( 426 sec: *Section, 427 unit: Unit.Index, 428 entry: Entry.Index, 429 dwarf: *Dwarf, 430 contents: []const u8, 431 ) (UpdateError || Writer.Error)!void { 432 try sec.resizeEntry(unit, entry, dwarf, @intCast(contents.len)); 433 const unit_ptr = sec.getUnit(unit); 434 try unit_ptr.getEntry(entry).replace(unit_ptr, sec, dwarf, contents); 435 } 436 437 fn freeEntry( 438 sec: *Section, 439 unit: Unit.Index, 440 entry: Entry.Index, 441 dwarf: *Dwarf, 442 ) (UpdateError || Writer.Error)!void { 443 const unit_ptr = sec.getUnit(unit); 444 const entry_ptr = unit_ptr.getEntry(entry); 445 if (entry_ptr.len > 0) { 446 if (entry_ptr.next.unwrap()) |next_entry| unit_ptr.getEntry(next_entry).prev = entry_ptr.prev; 447 if (entry_ptr.prev.unwrap()) |prev_entry| { 448 const prev_entry_ptr = unit_ptr.getEntry(prev_entry); 449 prev_entry_ptr.next = entry_ptr.next; 450 try prev_entry_ptr.pad(unit_ptr, sec, dwarf); 451 } else { 452 unit_ptr.trim(); 453 sec.trim(dwarf); 454 } 455 } else assert(entry_ptr.prev == .none and entry_ptr.next == .none); 456 entry_ptr.prev = .none; 457 entry_ptr.next = unit_ptr.free; 458 entry_ptr.off = 0; 459 entry_ptr.len = 0; 460 entry_ptr.clear(); 461 unit_ptr.free = entry.toOptional(); 462 } 463 464 fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void { 465 if (len <= sec.len) return; 466 if (dwarf.bin_file.cast(.elf)) |elf_file| { 467 const zo = elf_file.zigObjectPtr().?; 468 const atom = zo.symbol(sec.index).atom(elf_file).?; 469 atom.size = len; 470 atom.alignment = sec.alignment; 471 sec.len = len; 472 try zo.allocateAtom(atom, false, elf_file); 473 } else if (dwarf.bin_file.cast(.macho)) |macho_file| { 474 const header = if (macho_file.d_sym) |*d_sym| header: { 475 try d_sym.growSection(@intCast(sec.index), len, true, macho_file); 476 break :header &d_sym.sections.items[sec.index]; 477 } else header: { 478 try macho_file.growSection(@intCast(sec.index), len); 479 break :header &macho_file.sections.items(.header)[sec.index]; 480 }; 481 sec.len = header.size; 482 } 483 } 484 485 fn trim(sec: *Section, dwarf: *Dwarf) void { 486 const len = sec.getUnit(sec.first.unwrap() orelse return).off; 487 if (len == 0) return; 488 for (sec.units.items) |*unit| unit.off -= len; 489 sec.len -= len; 490 if (dwarf.bin_file.cast(.elf)) |elf_file| { 491 const zo = elf_file.zigObjectPtr().?; 492 const atom = zo.symbol(sec.index).atom(elf_file).?; 493 if (atom.prevAtom(elf_file)) |_| { 494 atom.value += len; 495 } else { 496 const shdr = &elf_file.sections.items(.shdr)[atom.output_section_index]; 497 shdr.sh_offset += len; 498 shdr.sh_size -= len; 499 atom.value = 0; 500 } 501 atom.size -= len; 502 } else if (dwarf.bin_file.cast(.macho)) |macho_file| { 503 const header = if (macho_file.d_sym) |*d_sym| 504 &d_sym.sections.items[sec.index] 505 else 506 &macho_file.sections.items(.header)[sec.index]; 507 header.offset += @intCast(len); 508 header.size -= len; 509 } 510 } 511 512 fn resolveRelocs(sec: *Section, dwarf: *Dwarf) RelocError!void { 513 for (sec.units.items) |*unit| try unit.resolveRelocs(sec, dwarf); 514 } 515 516 fn padUnitToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) { 517 return @intCast(sec.alignment.forward(Dwarf.padToIdeal(actual_size))); 518 } 519 520 fn padEntryToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) { 521 return @intCast(sec.alignment.forward(if (sec.pad_entries_to_ideal) Dwarf.padToIdeal(actual_size) else actual_size)); 522 } 523 }; 524 525 /// A unit within a `Section` containing a sequence of `Entry`s. 526 const Unit = struct { 527 prev: Index.Optional, 528 next: Index.Optional, 529 first: Entry.Index.Optional, 530 last: Entry.Index.Optional, 531 free: Entry.Index.Optional, 532 /// offset within containing section 533 off: u32, 534 header_len: u32, 535 trailer_len: u32, 536 /// data length in bytes 537 len: u32, 538 entries: std.ArrayList(Entry), 539 cross_unit_relocs: std.ArrayList(CrossUnitReloc), 540 cross_section_relocs: std.ArrayList(CrossSectionReloc), 541 542 const Index = enum(u32) { 543 main, 544 _, 545 546 const Optional = enum(u32) { 547 none = std.math.maxInt(u32), 548 _, 549 550 pub fn unwrap(uio: Optional) ?Index { 551 return if (uio != .none) @fromBackingInt(@intCast(@backingInt(uio))) else null; 552 } 553 }; 554 555 fn toOptional(ui: Index) Optional { 556 return @fromBackingInt(@intCast(@backingInt(ui))); 557 } 558 }; 559 560 fn clear(unit: *Unit) void { 561 unit.cross_unit_relocs.clearRetainingCapacity(); 562 unit.cross_section_relocs.clearRetainingCapacity(); 563 } 564 565 fn deinit(unit: *Unit, gpa: Allocator) void { 566 for (unit.entries.items) |*entry| entry.deinit(gpa); 567 unit.entries.deinit(gpa); 568 unit.cross_unit_relocs.deinit(gpa); 569 unit.cross_section_relocs.deinit(gpa); 570 unit.* = undefined; 571 } 572 573 fn addEntry(unit: *Unit, gpa: Allocator) Allocator.Error!Entry.Index { 574 if (unit.free.unwrap()) |entry| { 575 const entry_ptr = unit.getEntry(entry); 576 unit.free = entry_ptr.next; 577 entry_ptr.next = .none; 578 return entry; 579 } 580 const entry: Entry.Index = @fromBackingInt(@intCast(unit.entries.items.len)); 581 const entry_ptr = try unit.entries.addOne(gpa); 582 entry_ptr.* = .{ 583 .prev = .none, 584 .next = .none, 585 .off = 0, 586 .len = 0, 587 .cross_entry_relocs = .empty, 588 .cross_unit_relocs = .empty, 589 .cross_section_relocs = .empty, 590 .external_relocs = .empty, 591 }; 592 return entry; 593 } 594 595 pub fn getEntry(unit: *Unit, entry: Entry.Index) *Entry { 596 return &unit.entries.items[@backingInt(entry)]; 597 } 598 599 fn resize(unit_ptr: *Unit, sec: *Section, dwarf: *Dwarf, extra_header_len: u32, len: u32) UpdateError!void { 600 const end = if (unit_ptr.next.unwrap()) |next_unit| 601 sec.getUnit(next_unit).off 602 else 603 sec.len; 604 if (extra_header_len > 0 or unit_ptr.off + len > end) { 605 unit_ptr.len = @min(unit_ptr.len, len); 606 var new_off = unit_ptr.off; 607 if (unit_ptr.next.unwrap()) |next_unit| { 608 const next_unit_ptr = sec.getUnit(next_unit); 609 if (unit_ptr.prev.unwrap()) |prev_unit| 610 sec.getUnit(prev_unit).next = unit_ptr.next 611 else 612 sec.first = unit_ptr.next; 613 const unit = next_unit_ptr.prev; 614 next_unit_ptr.prev = unit_ptr.prev; 615 const last_unit_ptr = sec.getUnit(sec.last.unwrap().?); 616 last_unit_ptr.next = unit; 617 unit_ptr.prev = sec.last; 618 unit_ptr.next = .none; 619 new_off = last_unit_ptr.off + sec.padUnitToIdeal(last_unit_ptr.len); 620 sec.last = unit; 621 sec.dirty = true; 622 } else if (extra_header_len > 0) { 623 // `copyRangeAll` in `move` does not support overlapping ranges 624 // so make sure new location is disjoint from current location. 625 new_off += unit_ptr.len -| extra_header_len; 626 } 627 try sec.resize(dwarf, new_off + len); 628 try unit_ptr.move(sec, dwarf, new_off + extra_header_len); 629 unit_ptr.off -= extra_header_len; 630 unit_ptr.header_len += extra_header_len; 631 sec.trim(dwarf); 632 } 633 unit_ptr.len = len; 634 } 635 636 fn trim(unit: *Unit) void { 637 const len = unit.getEntry(unit.first.unwrap() orelse return).off; 638 if (len == 0) return; 639 for (unit.entries.items) |*entry| entry.off -= len; 640 unit.off += len; 641 unit.len -= len; 642 } 643 644 fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void { 645 if (unit.off == new_off) return; 646 const comp = dwarf.bin_file.comp; 647 const io = comp.io; 648 const file = dwarf.getFile().?; 649 try link.File.copyRangeAll2(io, file, file, sec.off(dwarf) + unit.off, sec.off(dwarf) + new_off, unit.len); 650 unit.off = new_off; 651 } 652 653 fn resizeHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void { 654 unit.trim(); 655 if (unit.header_len == len) return; 656 const available_len = if (unit.prev.unwrap()) |prev_unit| prev_excess: { 657 const prev_unit_ptr = sec.getUnit(prev_unit); 658 break :prev_excess unit.off - prev_unit_ptr.off - prev_unit_ptr.len; 659 } else 0; 660 if (available_len + unit.header_len < len) 661 try unit.resize(sec, dwarf, len - unit.header_len, unit.len - unit.header_len + len); 662 if (unit.header_len > len) { 663 const excess_header_len = unit.header_len - len; 664 unit.off += excess_header_len; 665 unit.header_len -= excess_header_len; 666 unit.len -= excess_header_len; 667 } else if (unit.header_len < len) { 668 const needed_header_len = len - unit.header_len; 669 unit.off -= needed_header_len; 670 unit.header_len += needed_header_len; 671 unit.len += needed_header_len; 672 } 673 assert(unit.header_len == len); 674 sec.trim(dwarf); 675 } 676 677 fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void { 678 assert(contents.len == unit.header_len); 679 const comp = dwarf.bin_file.comp; 680 const io = comp.io; 681 try dwarf.getFile().?.writePositionalAll(io, contents, sec.off(dwarf) + unit.off); 682 } 683 684 fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void { 685 const comp = dwarf.bin_file.comp; 686 const io = comp.io; 687 const start = unit.off + unit.header_len + if (unit.last.unwrap()) |last_entry| end: { 688 const last_entry_ptr = unit.getEntry(last_entry); 689 break :end last_entry_ptr.off + last_entry_ptr.len; 690 } else 0; 691 const end = if (unit.next.unwrap()) |next_unit| sec.getUnit(next_unit).off else sec.len; 692 const len: usize = @intCast(end - start); 693 assert(len >= unit.trailer_len); 694 if (sec == &dwarf.debug_line.section) { 695 var buf: [1 + uleb128Bytes(std.math.maxInt(u32)) + 1]u8 = undefined; 696 var fw: Writer = .fixed(&buf); 697 fw.writeByte(DW.LNS.extended_op) catch unreachable; 698 const extended_op_bytes = fw.end; 699 var op_len_bytes: u5 = 1; 700 while (true) switch (std.math.order(len - extended_op_bytes - op_len_bytes, @as(u32, 1) << 7 * op_len_bytes)) { 701 .lt => break fw.writeUleb128(len - extended_op_bytes - op_len_bytes) catch unreachable, 702 .eq => { 703 // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte 704 op_len_bytes += 1; 705 std.leb.writeUnsignedExtended( 706 fw.writableSlice(op_len_bytes) catch unreachable, 707 len - extended_op_bytes - op_len_bytes, 708 ); 709 break; 710 }, 711 .gt => op_len_bytes += 1, 712 }; 713 assert(fw.end == extended_op_bytes + op_len_bytes); 714 fw.writeByte(DW.LNE.padding) catch unreachable; 715 assert(fw.end >= unit.trailer_len and fw.end <= len); 716 return dwarf.getFile().?.writePositionalAll(io, fw.buffered(), sec.off(dwarf) + start); 717 } 718 var trailer_aw: Writer.Allocating = try .initCapacity(dwarf.gpa, len); 719 defer trailer_aw.deinit(); 720 const tw = &trailer_aw.writer; 721 const fill_byte: u8 = if (sec == &dwarf.debug_abbrev.section) fill: { 722 tw.writeUleb128(@backingInt(AbbrevCode.null)) catch unreachable; 723 assert(uleb128Bytes(@backingInt(AbbrevCode.null)) == 1); 724 break :fill @backingInt(AbbrevCode.null); 725 } else if (sec == &dwarf.debug_aranges.section) fill: { 726 tw.splatByteAll(0, @backingInt(dwarf.address_size) * 2) catch unreachable; 727 break :fill 0; 728 } else if (sec == &dwarf.debug_frame.section) fill: { 729 switch (dwarf.debug_frame.header.format) { 730 .none => {}, 731 .debug_frame, .eh_frame => |format| { 732 const unit_len = len - dwarf.unitLengthBytes(); 733 switch (dwarf.format) { 734 .@"32" => tw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable, 735 .@"64" => { 736 tw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable; 737 tw.writeInt(u64, unit_len, dwarf.endian) catch unreachable; 738 }, 739 } 740 switch (format) { 741 .none => unreachable, 742 .debug_frame => { 743 switch (dwarf.format) { 744 .@"32" => tw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable, 745 .@"64" => tw.writeInt(u64, std.math.maxInt(u64), dwarf.endian) catch unreachable, 746 } 747 tw.writeByte(4) catch unreachable; 748 tw.writeAll("\x00") catch unreachable; 749 tw.writeByte(@backingInt(dwarf.address_size)) catch unreachable; 750 tw.writeByte(0) catch unreachable; 751 }, 752 .eh_frame => { 753 tw.writeInt(u32, 0, dwarf.endian) catch unreachable; 754 tw.writeByte(1) catch unreachable; 755 tw.writeAll("\x00") catch unreachable; 756 }, 757 } 758 tw.writeUleb128(1) catch unreachable; 759 tw.writeSleb128(1) catch unreachable; 760 tw.writeUleb128(0) catch unreachable; 761 }, 762 } 763 tw.splatByteAll(DW.CFA.nop, unit.trailer_len - tw.end) catch unreachable; 764 break :fill DW.CFA.nop; 765 } else if (sec == &dwarf.debug_info.section) fill: { 766 for (0..2) |_| tw.writeUleb128(@backingInt(AbbrevCode.null)) catch unreachable; 767 assert(uleb128Bytes(@backingInt(AbbrevCode.null)) == 1); 768 break :fill @backingInt(AbbrevCode.null); 769 } else if (sec == &dwarf.debug_rnglists.section) fill: { 770 tw.writeByte(DW.RLE.end_of_list) catch unreachable; 771 break :fill DW.RLE.end_of_list; 772 } else unreachable; 773 assert(tw.end == unit.trailer_len); 774 tw.splatByteAll(fill_byte, len - unit.trailer_len) catch unreachable; 775 assert(tw.end == len); 776 try dwarf.getFile().?.writePositionalAll(io, trailer_aw.written(), sec.off(dwarf) + start); 777 } 778 779 fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { 780 const unit_off = sec.off(dwarf) + unit.off; 781 for (unit.cross_unit_relocs.items) |reloc| { 782 const target_unit = sec.getUnit(reloc.target_unit); 783 try dwarf.resolveReloc( 784 unit_off + reloc.source_off, 785 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| 786 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(target_unit, sec, dwarf).off 787 else 788 0) + reloc.target_off, 789 dwarf.sectionOffsetBytes(), 790 ); 791 } 792 for (unit.cross_section_relocs.items) |reloc| { 793 const target_sec = switch (reloc.target_sec) { 794 inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section, 795 }; 796 const target_unit = target_sec.getUnit(reloc.target_unit); 797 try dwarf.resolveReloc( 798 unit_off + reloc.source_off, 799 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| 800 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(target_unit, sec, dwarf).off 801 else 802 0) + reloc.target_off, 803 dwarf.sectionOffsetBytes(), 804 ); 805 } 806 for (unit.entries.items) |*entry| try entry.resolveRelocs(unit, sec, dwarf); 807 } 808 }; 809 810 /// An indivisible entry within a `Unit` containing section-specific data. 811 const Entry = struct { 812 prev: Index.Optional, 813 next: Index.Optional, 814 /// offset from end of containing unit header 815 off: u32, 816 /// data length in bytes 817 len: u32, 818 cross_entry_relocs: std.ArrayList(CrossEntryReloc), 819 cross_unit_relocs: std.ArrayList(CrossUnitReloc), 820 cross_section_relocs: std.ArrayList(CrossSectionReloc), 821 external_relocs: std.ArrayList(ExternalReloc), 822 823 fn clear(entry: *Entry) void { 824 entry.cross_entry_relocs.clearRetainingCapacity(); 825 entry.cross_unit_relocs.clearRetainingCapacity(); 826 entry.cross_section_relocs.clearRetainingCapacity(); 827 entry.external_relocs.clearRetainingCapacity(); 828 } 829 830 fn deinit(entry: *Entry, gpa: Allocator) void { 831 entry.cross_entry_relocs.deinit(gpa); 832 entry.cross_unit_relocs.deinit(gpa); 833 entry.cross_section_relocs.deinit(gpa); 834 entry.external_relocs.deinit(gpa); 835 entry.* = undefined; 836 } 837 838 const Index = enum(u32) { 839 _, 840 841 const Optional = enum(u32) { 842 none = std.math.maxInt(u32), 843 _, 844 845 pub fn unwrap(eio: Optional) ?Index { 846 return if (eio != .none) @fromBackingInt(@intCast(@backingInt(eio))) else null; 847 } 848 }; 849 850 fn toOptional(ei: Index) Optional { 851 return @fromBackingInt(@intCast(@backingInt(ei))); 852 } 853 }; 854 855 fn pad( 856 entry: *Entry, 857 unit: *Unit, 858 sec: *Section, 859 dwarf: *Dwarf, 860 ) (UpdateError || Writer.Error)!void { 861 assert(entry.len > 0); 862 const comp = dwarf.bin_file.comp; 863 const io = comp.io; 864 const start = entry.off + entry.len; 865 if (sec == &dwarf.debug_frame.section) { 866 const len = if (entry.next.unwrap()) |next_entry| 867 unit.getEntry(next_entry).off - entry.off 868 else 869 entry.len; 870 var unit_len_buf: [8]u8 = undefined; 871 const unit_len_bytes = unit_len_buf[0..dwarf.sectionOffsetBytes()]; 872 dwarf.writeInt(unit_len_bytes, len - dwarf.unitLengthBytes()); 873 try dwarf.getFile().?.writePositionalAll(io, unit_len_bytes, sec.off(dwarf) + unit.off + unit.header_len + entry.off); 874 const buf = try dwarf.gpa.alloc(u8, len - entry.len); 875 defer dwarf.gpa.free(buf); 876 @memset(buf, DW.CFA.nop); 877 try dwarf.getFile().?.writePositionalAll(io, buf, sec.off(dwarf) + unit.off + unit.header_len + start); 878 return; 879 } 880 const len = unit.getEntry(entry.next.unwrap() orelse return).off - start; 881 var buf: [ 882 @max( 883 uleb128Bytes(@backingInt(AbbrevCode.pad_1)), 884 uleb128Bytes(@backingInt(AbbrevCode.pad_n)) + uleb128Bytes(std.math.maxInt(u32)), 885 1 + uleb128Bytes(std.math.maxInt(u32)) + 1, 886 ) 887 ]u8 = undefined; 888 var fw: Writer = .fixed(&buf); 889 if (sec == &dwarf.debug_info.section) switch (len) { 890 0 => {}, 891 1 => fw.writeUleb128(try dwarf.refAbbrevCode(.pad_1)) catch unreachable, 892 else => { 893 fw.writeUleb128(try dwarf.refAbbrevCode(.pad_n)) catch unreachable; 894 const abbrev_code_bytes = fw.end; 895 var block_len_bytes: u5 = 1; 896 while (true) switch (std.math.order(len - abbrev_code_bytes - block_len_bytes, @as(u32, 1) << 7 * block_len_bytes)) { 897 .lt => break fw.writeUleb128(len - abbrev_code_bytes - block_len_bytes) catch unreachable, 898 .eq => { 899 // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte 900 block_len_bytes += 1; 901 std.leb.writeUnsignedExtended( 902 fw.writableSlice(block_len_bytes) catch unreachable, 903 len - abbrev_code_bytes - block_len_bytes, 904 ); 905 break; 906 }, 907 .gt => block_len_bytes += 1, 908 }; 909 assert(fw.end == abbrev_code_bytes + block_len_bytes); 910 }, 911 } else if (sec == &dwarf.debug_line.section) switch (len) { 912 0 => {}, 913 1 => fw.writeByte(DW.LNS.const_add_pc) catch unreachable, 914 else => { 915 fw.writeByte(DW.LNS.extended_op) catch unreachable; 916 const extended_op_bytes = fw.end; 917 var op_len_bytes: u5 = 1; 918 while (true) switch (std.math.order(len - extended_op_bytes - op_len_bytes, @as(u32, 1) << 7 * op_len_bytes)) { 919 .lt => break fw.writeUleb128(len - extended_op_bytes - op_len_bytes) catch unreachable, 920 .eq => { 921 // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte 922 op_len_bytes += 1; 923 std.leb.writeUnsignedExtended( 924 fw.writableSlice(op_len_bytes) catch unreachable, 925 len - extended_op_bytes - op_len_bytes, 926 ); 927 break; 928 }, 929 .gt => op_len_bytes += 1, 930 }; 931 assert(fw.end == extended_op_bytes + op_len_bytes); 932 if (len > 2) fw.writeByte(DW.LNE.padding) catch unreachable; 933 }, 934 } else assert(!sec.pad_entries_to_ideal and len == 0); 935 assert(fw.end <= len); 936 try dwarf.getFile().?.writePositionalAll(io, fw.buffered(), sec.off(dwarf) + unit.off + unit.header_len + start); 937 } 938 939 fn resize( 940 entry_ptr: *Entry, 941 unit: *Unit, 942 sec: *Section, 943 dwarf: *Dwarf, 944 len: u32, 945 ) (UpdateError || Writer.Error)!void { 946 assert(len > 0); 947 assert(sec.alignment.check(len)); 948 if (entry_ptr.len == len) return; 949 const end = if (entry_ptr.next.unwrap()) |next_entry| 950 unit.getEntry(next_entry).off 951 else 952 unit.len -| (unit.header_len + unit.trailer_len); 953 if (entry_ptr.off + len > end) { 954 if (entry_ptr.next.unwrap()) |next_entry| { 955 if (entry_ptr.prev.unwrap()) |prev_entry| { 956 const prev_entry_ptr = unit.getEntry(prev_entry); 957 prev_entry_ptr.next = entry_ptr.next; 958 try prev_entry_ptr.pad(unit, sec, dwarf); 959 } else unit.first = entry_ptr.next; 960 const next_entry_ptr = unit.getEntry(next_entry); 961 const entry = next_entry_ptr.prev; 962 next_entry_ptr.prev = entry_ptr.prev; 963 const last_entry_ptr = unit.getEntry(unit.last.unwrap().?); 964 last_entry_ptr.next = entry; 965 entry_ptr.prev = unit.last; 966 entry_ptr.next = .none; 967 entry_ptr.off = last_entry_ptr.off + sec.padEntryToIdeal(last_entry_ptr.len); 968 unit.last = entry; 969 try last_entry_ptr.pad(unit, sec, dwarf); 970 } 971 try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padEntryToIdeal(len) + unit.trailer_len)); 972 } 973 entry_ptr.len = len; 974 try entry_ptr.pad(unit, sec, dwarf); 975 } 976 977 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void { 978 assert(contents.len == entry_ptr.len); 979 const comp = dwarf.bin_file.comp; 980 const io = comp.io; 981 try dwarf.getFile().?.writePositionalAll(io, contents, sec.off(dwarf) + unit.off + unit.header_len + entry_ptr.off); 982 if (false) { 983 const buf = try dwarf.gpa.alloc(u8, sec.len); 984 defer dwarf.gpa.free(buf); 985 _ = try dwarf.getFile().?.readPositionalAll(io, buf, sec.off(dwarf)); 986 log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{ 987 @backingInt(sec.first), 988 @backingInt(sec.last), 989 sec.off(dwarf), 990 sec.len, 991 }); 992 for (sec.units.items) |*unit_ptr| { 993 log.info(" Unit{{ .prev = {}, .next = {}, .first = {}, .last = {}, .off = 0x{x}, .header_len = 0x{x}, .trailer_len = 0x{x}, .len = 0x{x} }}", .{ 994 @backingInt(unit_ptr.prev), 995 @backingInt(unit_ptr.next), 996 @backingInt(unit_ptr.first), 997 @backingInt(unit_ptr.last), 998 unit_ptr.off, 999 unit_ptr.header_len, 1000 unit_ptr.trailer_len, 1001 unit_ptr.len, 1002 }); 1003 for (unit_ptr.entries.items) |*entry| { 1004 log.info(" Entry{{ .prev = {}, .next = {}, .off = 0x{x}, .len = 0x{x} }}", .{ 1005 @backingInt(entry.prev), 1006 @backingInt(entry.next), 1007 entry.off, 1008 entry.len, 1009 }); 1010 } 1011 } 1012 std.debug.dumpHex(buf); 1013 } 1014 } 1015 1016 pub fn assertNonEmpty(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) *Entry { 1017 if (entry.len > 0) return entry; 1018 if (std.debug.runtime_safety) { 1019 log.err("missing {} from {s}", .{ 1020 @as(Entry.Index, @fromBackingInt(@intCast(entry - unit.entries.items.ptr))), 1021 std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file| 1022 elf_file.zigObjectPtr().?.symbol(sec.index).name(elf_file) 1023 else if (dwarf.bin_file.cast(.macho)) |macho_file| 1024 if (macho_file.d_sym) |*d_sym| 1025 &d_sym.sections.items[sec.index].segname 1026 else 1027 &macho_file.sections.items(.header)[sec.index].segname 1028 else 1029 "?", 0), 1030 }); 1031 const zcu = dwarf.bin_file.comp.zcu.?; 1032 const ip = &zcu.intern_pool; 1033 for (0.., dwarf.values.items) |raw_index, unit_and_entry| { 1034 const index: link.ConstPool.Index = @fromBackingInt(@intCast(raw_index)); 1035 const val = index.val(&dwarf.const_pool); 1036 const val_unit, const val_entry = unit_and_entry; 1037 if (sec.getUnit(val_unit) == unit and unit.getEntry(val_entry) == entry) 1038 log.err("missing Value({f}({d}))", .{ 1039 Value.fromInterned(val).fmtValue(.{ .tid = .main, .zcu = zcu }), 1040 @backingInt(val), 1041 }); 1042 } 1043 for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| { 1044 const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFile(ip)).mod.?) catch unreachable; 1045 if (sec.getUnit(nav_unit) == unit and unit.getEntry(other_entry) == entry) 1046 log.err("missing Nav({f}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @backingInt(nav) }); 1047 } 1048 } 1049 @panic("missing dwarf relocation target"); 1050 } 1051 1052 fn resolveRelocs(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { 1053 const entry_off = sec.off(dwarf) + unit.off + unit.header_len + entry.off; 1054 for (entry.cross_entry_relocs.items) |reloc| { 1055 try dwarf.resolveReloc( 1056 entry_off + reloc.source_off, 1057 unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off, 1058 dwarf.sectionOffsetBytes(), 1059 ); 1060 } 1061 for (entry.cross_unit_relocs.items) |reloc| { 1062 const target_unit = sec.getUnit(reloc.target_unit); 1063 try dwarf.resolveReloc( 1064 entry_off + reloc.source_off, 1065 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| 1066 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(target_unit, sec, dwarf).off 1067 else 1068 0) + reloc.target_off, 1069 dwarf.sectionOffsetBytes(), 1070 ); 1071 } 1072 for (entry.cross_section_relocs.items) |reloc| { 1073 const target_sec = switch (reloc.target_sec) { 1074 inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section, 1075 }; 1076 const target_unit = target_sec.getUnit(reloc.target_unit); 1077 try dwarf.resolveReloc( 1078 entry_off + reloc.source_off, 1079 target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| 1080 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(target_unit, sec, dwarf).off 1081 else 1082 0) + reloc.target_off, 1083 dwarf.sectionOffsetBytes(), 1084 ); 1085 } 1086 if (sec == &dwarf.debug_frame.section) switch (DebugFrame.format(dwarf)) { 1087 .none, .debug_frame => {}, 1088 .eh_frame => return if (dwarf.bin_file.cast(.elf)) |elf_file| { 1089 const zo = elf_file.zigObjectPtr().?; 1090 const shndx = zo.symbol(sec.index).atom(elf_file).?.output_section_index; 1091 const entry_addr: i64 = @intCast(entry_off - sec.off(dwarf) + elf_file.shdrs.items[shndx].sh_addr); 1092 for (entry.external_relocs.items) |reloc| { 1093 const symbol = zo.symbol(reloc.target_sym); 1094 try dwarf.resolveReloc( 1095 entry_off + reloc.source_off, 1096 @bitCast((symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off))) - 1097 (entry_addr + reloc.source_off + 4)), 1098 4, 1099 ); 1100 } 1101 } else unreachable, 1102 }; 1103 if (dwarf.bin_file.cast(.elf)) |elf_file| { 1104 const zo = elf_file.zigObjectPtr().?; 1105 for (entry.external_relocs.items) |reloc| { 1106 const symbol = zo.symbol(reloc.target_sym); 1107 try dwarf.resolveReloc( 1108 entry_off + reloc.source_off, 1109 @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) - 1110 if (symbol.flags.is_tls) elf_file.dtpAddress() else 0), 1111 @backingInt(dwarf.address_size), 1112 ); 1113 } 1114 } else if (dwarf.bin_file.cast(.macho)) |macho_file| { 1115 const zo = macho_file.getZigObject().?; 1116 for (entry.external_relocs.items) |reloc| { 1117 const ref = zo.getSymbolRef(reloc.target_sym, macho_file); 1118 try dwarf.resolveReloc( 1119 entry_off + reloc.source_off, 1120 ref.getSymbol(macho_file).?.getAddress(.{}, macho_file) + @as(i64, @intCast(reloc.target_off)), 1121 @backingInt(dwarf.address_size), 1122 ); 1123 } 1124 } 1125 } 1126 }; 1127 1128 const CrossEntryReloc = struct { 1129 source_off: u32 = 0, 1130 target_entry: Entry.Index.Optional = .none, 1131 target_off: u32 = 0, 1132 }; 1133 const CrossUnitReloc = struct { 1134 source_off: u32 = 0, 1135 target_unit: Unit.Index, 1136 target_entry: Entry.Index.Optional = .none, 1137 target_off: u32 = 0, 1138 }; 1139 const CrossSectionReloc = struct { 1140 source_off: u32 = 0, 1141 target_sec: Section.Index, 1142 target_unit: Unit.Index, 1143 target_entry: Entry.Index.Optional = .none, 1144 target_off: u32 = 0, 1145 }; 1146 const ExternalReloc = struct { 1147 source_off: u32 = 0, 1148 target_sym: link.File.SymbolId, 1149 target_off: u64 = 0, 1150 }; 1151 1152 pub const Loc = union(enum) { 1153 empty, 1154 addr_reloc: link.File.SymbolId, 1155 deref: *const Loc, 1156 constu: u64, 1157 consts: i64, 1158 plus: Bin, 1159 reg: u32, 1160 breg: u32, 1161 push_object_address, 1162 call: struct { 1163 args: []const Loc = &.{}, 1164 unit: Unit.Index, 1165 entry: Entry.Index, 1166 }, 1167 form_tls_address: *const Loc, 1168 implicit_value: []const u8, 1169 stack_value: *const Loc, 1170 implicit_pointer: struct { 1171 unit: Unit.Index, 1172 entry: Entry.Index, 1173 offset: i65, 1174 }, 1175 wasm_ext: union(enum) { 1176 local: u32, 1177 global: u32, 1178 operand_stack: u32, 1179 }, 1180 1181 pub const Bin = struct { *const Loc, *const Loc }; 1182 1183 fn getConst(loc: Loc, comptime Int: type) ?Int { 1184 return switch (loc) { 1185 .constu => |constu| std.math.cast(Int, constu), 1186 .consts => |consts| std.math.cast(Int, consts), 1187 else => null, 1188 }; 1189 } 1190 1191 fn getBaseReg(loc: Loc) ?u32 { 1192 return switch (loc) { 1193 .breg => |breg| breg, 1194 else => null, 1195 }; 1196 } 1197 1198 fn writeReg(reg: u32, op0: u8, opx: u8, writer: *Writer) Writer.Error!void { 1199 if (std.math.cast(u5, reg)) |small_reg| { 1200 try writer.writeByte(op0 + small_reg); 1201 } else { 1202 try writer.writeByte(opx); 1203 try writer.writeUleb128(reg); 1204 } 1205 } 1206 1207 fn write(loc: Loc, adapter: anytype) (UpdateError || Writer.Error)!void { 1208 const writer = adapter.writer(); 1209 switch (loc) { 1210 .empty => {}, 1211 .addr_reloc => |sym_index| { 1212 try writer.writeByte(DW.OP.addr); 1213 try adapter.addrSym(sym_index); 1214 }, 1215 .deref => |addr| { 1216 try addr.write(adapter); 1217 try writer.writeByte(DW.OP.deref); 1218 }, 1219 .constu => |constu| if (std.math.cast(u5, constu)) |lit| { 1220 try writer.writeByte(@as(u8, DW.OP.lit0) + lit); 1221 } else if (std.math.cast(u8, constu)) |const1u| { 1222 try writer.writeAll(&.{ DW.OP.const1u, const1u }); 1223 } else if (std.math.cast(u16, constu)) |const2u| { 1224 try writer.writeByte(DW.OP.const2u); 1225 try writer.writeInt(u16, const2u, adapter.endian()); 1226 } else if (std.math.cast(u21, constu)) |const3u| { 1227 try writer.writeByte(DW.OP.constu); 1228 try writer.writeUleb128(const3u); 1229 } else if (std.math.cast(u32, constu)) |const4u| { 1230 try writer.writeByte(DW.OP.const4u); 1231 try writer.writeInt(u32, const4u, adapter.endian()); 1232 } else if (std.math.cast(u49, constu)) |const7u| { 1233 try writer.writeByte(DW.OP.constu); 1234 try writer.writeUleb128(const7u); 1235 } else { 1236 try writer.writeByte(DW.OP.const8u); 1237 try writer.writeInt(u64, constu, adapter.endian()); 1238 }, 1239 .consts => |consts| if (std.math.cast(i8, consts)) |const1s| { 1240 try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) }); 1241 } else if (std.math.cast(i16, consts)) |const2s| { 1242 try writer.writeByte(DW.OP.const2s); 1243 try writer.writeInt(i16, const2s, adapter.endian()); 1244 } else if (std.math.cast(i21, consts)) |const3s| { 1245 try writer.writeByte(DW.OP.consts); 1246 try writer.writeSleb128(const3s); 1247 } else if (std.math.cast(i32, consts)) |const4s| { 1248 try writer.writeByte(DW.OP.const4s); 1249 try writer.writeInt(i32, const4s, adapter.endian()); 1250 } else if (std.math.cast(i49, consts)) |const7s| { 1251 try writer.writeByte(DW.OP.consts); 1252 try writer.writeSleb128(const7s); 1253 } else { 1254 try writer.writeByte(DW.OP.const8s); 1255 try writer.writeInt(i64, consts, adapter.endian()); 1256 }, 1257 .plus => |plus| done: { 1258 if (plus[0].getConst(u0)) |_| { 1259 try plus[1].write(adapter); 1260 break :done; 1261 } 1262 if (plus[1].getConst(u0)) |_| { 1263 try plus[0].write(adapter); 1264 break :done; 1265 } 1266 if (plus[0].getBaseReg()) |breg| { 1267 if (plus[1].getConst(i65)) |offset| { 1268 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer); 1269 try writer.writeSleb128(offset); 1270 break :done; 1271 } 1272 } 1273 if (plus[1].getBaseReg()) |breg| { 1274 if (plus[0].getConst(i65)) |offset| { 1275 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer); 1276 try writer.writeSleb128(offset); 1277 break :done; 1278 } 1279 } 1280 if (plus[0].getConst(u64)) |uconst| { 1281 try plus[1].write(adapter); 1282 try writer.writeByte(DW.OP.plus_uconst); 1283 try writer.writeUleb128(uconst); 1284 break :done; 1285 } 1286 if (plus[1].getConst(u64)) |uconst| { 1287 try plus[0].write(adapter); 1288 try writer.writeByte(DW.OP.plus_uconst); 1289 try writer.writeUleb128(uconst); 1290 break :done; 1291 } 1292 try plus[0].write(adapter); 1293 try plus[1].write(adapter); 1294 try writer.writeByte(DW.OP.plus); 1295 }, 1296 .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer), 1297 .breg => |breg| { 1298 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer); 1299 try writer.writeSleb128(0); 1300 }, 1301 .push_object_address => try writer.writeByte(DW.OP.push_object_address), 1302 .call => |call| { 1303 for (call.args) |arg| try arg.write(adapter); 1304 try writer.writeByte(DW.OP.call_ref); 1305 try adapter.infoEntry(call.unit, call.entry); 1306 }, 1307 .form_tls_address => |addr| { 1308 try addr.write(adapter); 1309 try writer.writeByte(DW.OP.form_tls_address); 1310 }, 1311 .implicit_value => |value| { 1312 try writer.writeByte(DW.OP.implicit_value); 1313 try writer.writeUleb128(value.len); 1314 try writer.writeAll(value); 1315 }, 1316 .stack_value => |value| { 1317 try value.write(adapter); 1318 try writer.writeByte(DW.OP.stack_value); 1319 }, 1320 .implicit_pointer => |implicit_pointer| { 1321 try writer.writeByte(DW.OP.implicit_pointer); 1322 try adapter.infoEntry(implicit_pointer.unit, implicit_pointer.entry); 1323 try writer.writeSleb128(implicit_pointer.offset); 1324 }, 1325 .wasm_ext => |wasm_ext| { 1326 try writer.writeByte(DW.OP.WASM_location); 1327 switch (wasm_ext) { 1328 .local => |local| { 1329 try writer.writeByte(DW.OP.WASM_local); 1330 try writer.writeUleb128(local); 1331 }, 1332 .global => |global| if (std.math.cast(u21, global)) |global_u21| { 1333 try writer.writeByte(DW.OP.WASM_global); 1334 try writer.writeUleb128(global_u21); 1335 } else { 1336 try writer.writeByte(DW.OP.WASM_global_u32); 1337 try writer.writeInt(u32, global, adapter.endian()); 1338 }, 1339 .operand_stack => |operand_stack| { 1340 try writer.writeByte(DW.OP.WASM_operand_stack); 1341 try writer.writeUleb128(operand_stack); 1342 }, 1343 } 1344 }, 1345 } 1346 } 1347 }; 1348 1349 pub const Cfa = union(enum) { 1350 nop, 1351 advance_loc: u32, 1352 offset: RegOff, 1353 rel_offset: RegOff, 1354 restore: u32, 1355 undefined: u32, 1356 same_value: u32, 1357 register: [2]u32, 1358 remember_state, 1359 restore_state, 1360 def_cfa: RegOff, 1361 def_cfa_register: u32, 1362 def_cfa_offset: i64, 1363 adjust_cfa_offset: i64, 1364 def_cfa_expression: Loc, 1365 expression: RegExpr, 1366 val_offset: RegOff, 1367 val_expression: RegExpr, 1368 escape: []const u8, 1369 1370 const RegOff = struct { reg: u32, off: i64 }; 1371 const RegExpr = struct { reg: u32, expr: Loc }; 1372 1373 fn write(cfa: Cfa, wip_nav: *WipNav) (UpdateError || Writer.Error)!void { 1374 const dfw = &wip_nav.debug_frame.writer; 1375 switch (cfa) { 1376 .nop => try dfw.writeByte(DW.CFA.nop), 1377 .advance_loc => |loc| { 1378 const delta = @divExact(loc - wip_nav.cfi.loc, wip_nav.dwarf.debug_frame.header.code_alignment_factor); 1379 if (delta == 0) {} else if (std.math.cast(u6, delta)) |small_delta| 1380 try dfw.writeByte(@as(u8, DW.CFA.advance_loc) + small_delta) 1381 else if (std.math.cast(u8, delta)) |ubyte_delta| 1382 try dfw.writeAll(&.{ DW.CFA.advance_loc1, ubyte_delta }) 1383 else if (std.math.cast(u16, delta)) |uhalf_delta| { 1384 try dfw.writeByte(DW.CFA.advance_loc2); 1385 try dfw.writeInt(u16, uhalf_delta, wip_nav.dwarf.endian); 1386 } else if (std.math.cast(u32, delta)) |uword_delta| { 1387 try dfw.writeByte(DW.CFA.advance_loc4); 1388 try dfw.writeInt(u32, uword_delta, wip_nav.dwarf.endian); 1389 } 1390 wip_nav.cfi.loc = loc; 1391 }, 1392 .offset, .rel_offset => |reg_off| { 1393 const factored_off = @divExact(reg_off.off - switch (cfa) { 1394 else => unreachable, 1395 .offset => 0, 1396 .rel_offset => wip_nav.cfi.cfa.off, 1397 }, wip_nav.dwarf.debug_frame.header.data_alignment_factor); 1398 if (std.math.cast(u63, factored_off)) |unsigned_off| { 1399 if (std.math.cast(u6, reg_off.reg)) |small_reg| { 1400 try dfw.writeByte(@as(u8, DW.CFA.offset) + small_reg); 1401 } else { 1402 try dfw.writeByte(DW.CFA.offset_extended); 1403 try dfw.writeUleb128(reg_off.reg); 1404 } 1405 try dfw.writeUleb128(unsigned_off); 1406 } else { 1407 try dfw.writeByte(DW.CFA.offset_extended_sf); 1408 try dfw.writeUleb128(reg_off.reg); 1409 try dfw.writeSleb128(factored_off); 1410 } 1411 }, 1412 .restore => |reg| if (std.math.cast(u6, reg)) |small_reg| 1413 try dfw.writeByte(@as(u8, DW.CFA.restore) + small_reg) 1414 else { 1415 try dfw.writeByte(DW.CFA.restore_extended); 1416 try dfw.writeUleb128(reg); 1417 }, 1418 .undefined => |reg| { 1419 try dfw.writeByte(DW.CFA.undefined); 1420 try dfw.writeUleb128(reg); 1421 }, 1422 .same_value => |reg| { 1423 try dfw.writeByte(DW.CFA.same_value); 1424 try dfw.writeUleb128(reg); 1425 }, 1426 .register => |regs| if (regs[0] != regs[1]) { 1427 try dfw.writeByte(DW.CFA.register); 1428 for (regs) |reg| try dfw.writeUleb128(reg); 1429 } else { 1430 try dfw.writeByte(DW.CFA.same_value); 1431 try dfw.writeUleb128(regs[0]); 1432 }, 1433 .remember_state => try dfw.writeByte(DW.CFA.remember_state), 1434 .restore_state => try dfw.writeByte(DW.CFA.restore_state), 1435 .def_cfa, .def_cfa_register, .def_cfa_offset, .adjust_cfa_offset => { 1436 const reg_off: RegOff = switch (cfa) { 1437 else => unreachable, 1438 .def_cfa => |reg_off| reg_off, 1439 .def_cfa_register => |reg| .{ .reg = reg, .off = wip_nav.cfi.cfa.off }, 1440 .def_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = off }, 1441 .adjust_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = wip_nav.cfi.cfa.off + off }, 1442 }; 1443 const changed_reg = reg_off.reg != wip_nav.cfi.cfa.reg; 1444 const unsigned_off = std.math.cast(u63, reg_off.off); 1445 if (reg_off.off == wip_nav.cfi.cfa.off) { 1446 if (changed_reg) { 1447 try dfw.writeByte(DW.CFA.def_cfa_register); 1448 try dfw.writeUleb128(reg_off.reg); 1449 } 1450 } else if (switch (wip_nav.dwarf.debug_frame.header.data_alignment_factor) { 1451 0 => unreachable, 1452 1 => unsigned_off != null, 1453 else => |data_alignment_factor| @rem(reg_off.off, data_alignment_factor) != 0, 1454 }) { 1455 try dfw.writeByte(if (changed_reg) DW.CFA.def_cfa else DW.CFA.def_cfa_offset); 1456 if (changed_reg) try dfw.writeUleb128(reg_off.reg); 1457 try dfw.writeUleb128(unsigned_off.?); 1458 } else { 1459 try dfw.writeByte(if (changed_reg) DW.CFA.def_cfa_sf else DW.CFA.def_cfa_offset_sf); 1460 if (changed_reg) try dfw.writeUleb128(reg_off.reg); 1461 try dfw.writeSleb128(@divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor)); 1462 } 1463 wip_nav.cfi.cfa = reg_off; 1464 }, 1465 .def_cfa_expression => |expr| { 1466 try dfw.writeByte(DW.CFA.def_cfa_expression); 1467 try wip_nav.frameExprLoc(expr); 1468 }, 1469 .expression => |reg_expr| { 1470 try dfw.writeByte(DW.CFA.expression); 1471 try dfw.writeUleb128(reg_expr.reg); 1472 try wip_nav.frameExprLoc(reg_expr.expr); 1473 }, 1474 .val_offset => |reg_off| { 1475 const factored_off = @divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor); 1476 if (std.math.cast(u63, factored_off)) |unsigned_off| { 1477 try dfw.writeByte(DW.CFA.val_offset); 1478 try dfw.writeUleb128(reg_off.reg); 1479 try dfw.writeUleb128(unsigned_off); 1480 } else { 1481 try dfw.writeByte(DW.CFA.val_offset_sf); 1482 try dfw.writeUleb128(reg_off.reg); 1483 try dfw.writeSleb128(factored_off); 1484 } 1485 }, 1486 .val_expression => |reg_expr| { 1487 try dfw.writeByte(DW.CFA.val_expression); 1488 try dfw.writeUleb128(reg_expr.reg); 1489 try wip_nav.frameExprLoc(reg_expr.expr); 1490 }, 1491 .escape => |bytes| try dfw.writeAll(bytes), 1492 } 1493 } 1494 }; 1495 1496 pub const WipNav = struct { 1497 dwarf: *Dwarf, 1498 pt: Zcu.PerThread, 1499 unit: Unit.Index, 1500 entry: Entry.Index, 1501 any_children: bool, 1502 func: InternPool.Index, 1503 func_sym_index: link.File.SymbolId, 1504 func_high_pc: u32, 1505 blocks: std.ArrayList(struct { 1506 abbrev_code: u32, 1507 low_pc_off: u64, 1508 high_pc: u32, 1509 }), 1510 cfi: struct { 1511 loc: u32, 1512 cfa: Cfa.RegOff, 1513 }, 1514 debug_frame: Writer.Allocating, 1515 debug_info: Writer.Allocating, 1516 debug_line: Writer.Allocating, 1517 debug_loclists: Writer.Allocating, 1518 1519 pub fn deinit(wip_nav: *WipNav) void { 1520 const gpa = wip_nav.dwarf.gpa; 1521 if (wip_nav.func != .none) wip_nav.blocks.deinit(gpa); 1522 wip_nav.debug_frame.deinit(); 1523 wip_nav.debug_info.deinit(); 1524 wip_nav.debug_line.deinit(); 1525 wip_nav.debug_loclists.deinit(); 1526 } 1527 1528 pub fn genDebugFrame(wip_nav: *WipNav, loc: u32, cfa: Cfa) UpdateError!void { 1529 return wip_nav.genDebugFrameWriterError(loc, cfa) catch |err| switch (err) { 1530 error.WriteFailed => error.OutOfMemory, 1531 else => |e| e, 1532 }; 1533 } 1534 fn genDebugFrameWriterError(wip_nav: *WipNav, loc: u32, cfa: Cfa) (UpdateError || Writer.Error)!void { 1535 assert(wip_nav.func != .none); 1536 if (wip_nav.dwarf.debug_frame.header.format == .none) return; 1537 const loc_cfa: Cfa = .{ .advance_loc = loc }; 1538 try loc_cfa.write(wip_nav); 1539 try cfa.write(wip_nav); 1540 } 1541 1542 pub const LocalVarTag = enum { arg, local_var }; 1543 pub fn genLocalVarDebugInfo( 1544 wip_nav: *WipNav, 1545 tag: LocalVarTag, 1546 opt_name: ?[]const u8, 1547 ty: Type, 1548 loc: Loc, 1549 ) UpdateError!void { 1550 return wip_nav.genLocalVarDebugInfoWriterError(tag, opt_name, ty, loc) catch |err| switch (err) { 1551 error.WriteFailed => error.OutOfMemory, 1552 else => |e| e, 1553 }; 1554 } 1555 fn genLocalVarDebugInfoWriterError( 1556 wip_nav: *WipNav, 1557 tag: LocalVarTag, 1558 opt_name: ?[]const u8, 1559 ty: Type, 1560 loc: Loc, 1561 ) (UpdateError || Writer.Error)!void { 1562 assert(wip_nav.func != .none); 1563 try wip_nav.abbrevCode(switch (tag) { 1564 .arg => if (opt_name) |_| .arg else .unnamed_arg, 1565 .local_var => if (opt_name) |_| .local_var else unreachable, 1566 }); 1567 if (opt_name) |name| try wip_nav.strp(name); 1568 try wip_nav.refType(ty); 1569 try wip_nav.infoExprLoc(loc); 1570 wip_nav.any_children = true; 1571 } 1572 1573 pub const LocalConstTag = enum { comptime_arg, local_const }; 1574 pub fn genLocalConstDebugInfo( 1575 wip_nav: *WipNav, 1576 tag: LocalConstTag, 1577 opt_name: ?[]const u8, 1578 val: Value, 1579 ) UpdateError!void { 1580 return wip_nav.genLocalConstDebugInfoWriterError(tag, opt_name, val) catch |err| switch (err) { 1581 error.WriteFailed => error.OutOfMemory, 1582 else => |e| e, 1583 }; 1584 } 1585 fn genLocalConstDebugInfoWriterError( 1586 wip_nav: *WipNav, 1587 tag: LocalConstTag, 1588 opt_name: ?[]const u8, 1589 val: Value, 1590 ) (UpdateError || Writer.Error)!void { 1591 assert(wip_nav.func != .none); 1592 const pt = wip_nav.pt; 1593 const zcu = pt.zcu; 1594 const ty = val.typeOf(zcu); 1595 const has_runtime_bits = ty.hasRuntimeBits(zcu); 1596 const has_comptime_state = ty.comptimeOnly(zcu); 1597 try wip_nav.abbrevCode(if (has_runtime_bits and has_comptime_state) switch (tag) { 1598 .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits_comptime_state else .unnamed_comptime_arg_runtime_bits_comptime_state, 1599 .local_const => if (opt_name) |_| .local_const_runtime_bits_comptime_state else unreachable, 1600 } else if (has_comptime_state) switch (tag) { 1601 .comptime_arg => if (opt_name) |_| .comptime_arg_comptime_state else .unnamed_comptime_arg_comptime_state, 1602 .local_const => if (opt_name) |_| .local_const_comptime_state else unreachable, 1603 } else if (has_runtime_bits) switch (tag) { 1604 .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits else .unnamed_comptime_arg_runtime_bits, 1605 .local_const => if (opt_name) |_| .local_const_runtime_bits else unreachable, 1606 } else switch (tag) { 1607 .comptime_arg => if (opt_name) |_| .comptime_arg else .unnamed_comptime_arg, 1608 .local_const => if (opt_name) |_| .local_const else unreachable, 1609 }); 1610 if (opt_name) |name| try wip_nav.strp(name); 1611 try wip_nav.refType(ty); 1612 if (has_runtime_bits) try wip_nav.blockValue(val); 1613 if (has_comptime_state) try wip_nav.refValue(val); 1614 wip_nav.any_children = true; 1615 } 1616 1617 pub fn genVarArgsDebugInfo(wip_nav: *WipNav) UpdateError!void { 1618 return wip_nav.genVarArgsDebugInfoWriterError() catch |err| switch (err) { 1619 error.WriteFailed => error.OutOfMemory, 1620 else => |e| e, 1621 }; 1622 } 1623 fn genVarArgsDebugInfoWriterError(wip_nav: *WipNav) (UpdateError || Writer.Error)!void { 1624 assert(wip_nav.func != .none); 1625 try wip_nav.abbrevCode(.is_var_args); 1626 wip_nav.any_children = true; 1627 } 1628 1629 pub fn advanceLineAndPc( 1630 wip_nav: *WipNav, 1631 delta_line: i33, 1632 delta_pc: u64, 1633 end: bool, 1634 ) Allocator.Error!void { 1635 return wip_nav.advanceLineAndPcWriterError( 1636 delta_line, 1637 delta_pc, 1638 end, 1639 ) catch |err| switch (err) { 1640 error.WriteFailed => error.OutOfMemory, 1641 }; 1642 } 1643 fn advanceLineAndPcWriterError( 1644 wip_nav: *WipNav, 1645 delta_line: i33, 1646 delta_pc: u64, 1647 end: bool, 1648 ) Writer.Error!void { 1649 const dlw = &wip_nav.debug_line.writer; 1650 1651 const header = wip_nav.dwarf.debug_line.header; 1652 assert(header.maximum_operations_per_instruction == 1); 1653 const delta_op: u64 = 0; 1654 1655 const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or 1656 delta_line - header.line_base >= header.line_range) 1657 remaining: { 1658 assert(delta_line != 0); 1659 try dlw.writeByte(DW.LNS.advance_line); 1660 try dlw.writeSleb128(delta_line); 1661 break :remaining 0; 1662 } else delta_line); 1663 1664 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) * 1665 header.maximum_operations_per_instruction + delta_op; 1666 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range; 1667 const remaining_op_advance: u8 = @intCast(if (end or 1668 op_advance >= 2 * max_op_advance) 1669 remaining: { 1670 if (op_advance == max_op_advance) { 1671 try dlw.writeByte(DW.LNS.const_add_pc); 1672 } else if (op_advance != 0) { 1673 try dlw.writeByte(DW.LNS.advance_pc); 1674 try dlw.writeUleb128(op_advance); 1675 } else assert(end); 1676 break :remaining 0; 1677 } else if (op_advance >= max_op_advance) remaining: { 1678 try dlw.writeByte(DW.LNS.const_add_pc); 1679 break :remaining op_advance - max_op_advance; 1680 } else op_advance); 1681 1682 if (remaining_delta_line != 0 or remaining_op_advance != 0) { 1683 assert(!end); 1684 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) + 1685 (header.line_range * remaining_op_advance) + header.opcode_base)); 1686 } else if (end) { 1687 try dlw.writeByte(DW.LNS.extended_op); 1688 try dlw.writeUleb128(1); 1689 try dlw.writeByte(DW.LNE.end_sequence); 1690 } else try dlw.writeByte(DW.LNS.copy); 1691 } 1692 1693 pub fn setColumn(wip_nav: *WipNav, column: u32) Allocator.Error!void { 1694 return wip_nav.setColumnWriterError(column) catch |err| switch (err) { 1695 error.WriteFailed => error.OutOfMemory, 1696 }; 1697 } 1698 fn setColumnWriterError(wip_nav: *WipNav, column: u32) Writer.Error!void { 1699 const dlw = &wip_nav.debug_line.writer; 1700 try dlw.writeByte(DW.LNS.set_column); 1701 try dlw.writeUleb128(column + 1); 1702 } 1703 1704 pub fn negateStmt(wip_nav: *WipNav) Allocator.Error!void { 1705 return wip_nav.negateStmtWriterError() catch |err| switch (err) { 1706 error.WriteFailed => error.OutOfMemory, 1707 }; 1708 } 1709 fn negateStmtWriterError(wip_nav: *WipNav) Writer.Error!void { 1710 try wip_nav.debug_line.writer.writeByte(DW.LNS.negate_stmt); 1711 } 1712 1713 pub fn setPrologueEnd(wip_nav: *WipNav) Allocator.Error!void { 1714 return wip_nav.setPrologueEndWriterError() catch |err| switch (err) { 1715 error.WriteFailed => error.OutOfMemory, 1716 }; 1717 } 1718 fn setPrologueEndWriterError(wip_nav: *WipNav) Writer.Error!void { 1719 try wip_nav.debug_line.writer.writeByte(DW.LNS.set_prologue_end); 1720 } 1721 1722 pub fn setEpilogueBegin(wip_nav: *WipNav) Allocator.Error!void { 1723 return wip_nav.setEpilogueBeginWriterError() catch |err| switch (err) { 1724 error.WriteFailed => error.OutOfMemory, 1725 }; 1726 } 1727 fn setEpilogueBeginWriterError(wip_nav: *WipNav) Writer.Error!void { 1728 try wip_nav.debug_line.writer.writeByte(DW.LNS.set_epilogue_begin); 1729 } 1730 1731 pub fn enterBlock(wip_nav: *WipNav, code_off: u64) UpdateError!void { 1732 return wip_nav.enterBlockWriterError(code_off) catch |err| switch (err) { 1733 error.WriteFailed => error.OutOfMemory, 1734 else => |e| e, 1735 }; 1736 } 1737 fn enterBlockWriterError(wip_nav: *WipNav, code_off: u64) (UpdateError || Writer.Error)!void { 1738 const dwarf = wip_nav.dwarf; 1739 const diw = &wip_nav.debug_info.writer; 1740 const block = try wip_nav.blocks.addOne(dwarf.gpa); 1741 1742 block.abbrev_code = @intCast(diw.end); 1743 try wip_nav.abbrevCode(.block); 1744 block.low_pc_off = code_off; 1745 try wip_nav.infoAddrSym(wip_nav.func_sym_index, code_off); 1746 block.high_pc = @intCast(diw.end); 1747 try diw.writeInt(u32, 0, dwarf.endian); 1748 wip_nav.any_children = false; 1749 } 1750 1751 pub fn leaveBlock(wip_nav: *WipNav, code_off: u64) UpdateError!void { 1752 return wip_nav.leaveBlockWriterError(code_off) catch |err| switch (err) { 1753 error.WriteFailed => error.OutOfMemory, 1754 else => |e| e, 1755 }; 1756 } 1757 fn leaveBlockWriterError(wip_nav: *WipNav, code_off: u64) (UpdateError || Writer.Error)!void { 1758 const block_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.block)); 1759 const block = wip_nav.blocks.pop().?; 1760 if (wip_nav.any_children) 1761 try wip_nav.debug_info.writer.writeUleb128(@backingInt(AbbrevCode.null)) 1762 else 1763 std.leb.writeUnsignedFixed( 1764 block_bytes, 1765 wip_nav.debug_info.written()[block.abbrev_code..][0..block_bytes], 1766 @intCast(try wip_nav.dwarf.refAbbrevCode(.empty_block)), 1767 ); 1768 std.mem.writeInt(u32, wip_nav.debug_info.written()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian); 1769 wip_nav.any_children = true; 1770 } 1771 1772 pub fn enterInlineFunc( 1773 wip_nav: *WipNav, 1774 func: InternPool.Index, 1775 code_off: u64, 1776 line: u32, 1777 column: u32, 1778 ) UpdateError!void { 1779 return wip_nav.enterInlineFuncWriterError(func, code_off, line, column) catch |err| switch (err) { 1780 error.WriteFailed => error.OutOfMemory, 1781 else => |e| e, 1782 }; 1783 } 1784 fn enterInlineFuncWriterError( 1785 wip_nav: *WipNav, 1786 func: InternPool.Index, 1787 code_off: u64, 1788 line: u32, 1789 column: u32, 1790 ) (UpdateError || Writer.Error)!void { 1791 const dwarf = wip_nav.dwarf; 1792 const zcu = wip_nav.pt.zcu; 1793 const diw = &wip_nav.debug_info.writer; 1794 const block = try wip_nav.blocks.addOne(dwarf.gpa); 1795 1796 block.abbrev_code = @intCast(diw.end); 1797 try wip_nav.abbrevCode(.inlined_func); 1798 try wip_nav.refNav(zcu.funcInfo(func).owner_nav); 1799 try diw.writeUleb128(zcu.navSrcLine(zcu.funcInfo(wip_nav.func).owner_nav) + line + 1); 1800 try diw.writeUleb128(column + 1); 1801 block.low_pc_off = code_off; 1802 try wip_nav.infoAddrSym(wip_nav.func_sym_index, code_off); 1803 block.high_pc = @intCast(diw.end); 1804 try diw.writeInt(u32, 0, dwarf.endian); 1805 try wip_nav.setInlineFunc(func); 1806 wip_nav.any_children = false; 1807 } 1808 1809 pub fn leaveInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64) UpdateError!void { 1810 return wip_nav.leaveInlineFuncWriterError(func, code_off) catch |err| switch (err) { 1811 error.WriteFailed => error.OutOfMemory, 1812 else => |e| e, 1813 }; 1814 } 1815 fn leaveInlineFuncWriterError( 1816 wip_nav: *WipNav, 1817 func: InternPool.Index, 1818 code_off: u64, 1819 ) (UpdateError || Writer.Error)!void { 1820 const inlined_func_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.inlined_func)); 1821 const block = wip_nav.blocks.pop().?; 1822 if (wip_nav.any_children) 1823 try wip_nav.debug_info.writer.writeUleb128(@backingInt(AbbrevCode.null)) 1824 else 1825 std.leb.writeUnsignedFixed( 1826 inlined_func_bytes, 1827 wip_nav.debug_info.written()[block.abbrev_code..][0..inlined_func_bytes], 1828 @intCast(try wip_nav.dwarf.refAbbrevCode(.empty_inlined_func)), 1829 ); 1830 std.mem.writeInt(u32, wip_nav.debug_info.written()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian); 1831 try wip_nav.setInlineFunc(func); 1832 wip_nav.any_children = true; 1833 } 1834 1835 pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void { 1836 return wip_nav.setInlineFuncWriterError(func) catch |err| switch (err) { 1837 error.WriteFailed => error.OutOfMemory, 1838 else => |e| e, 1839 }; 1840 } 1841 fn setInlineFuncWriterError(wip_nav: *WipNav, func: InternPool.Index) (UpdateError || Writer.Error)!void { 1842 const zcu = wip_nav.pt.zcu; 1843 const dwarf = wip_nav.dwarf; 1844 if (wip_nav.func == func) return; 1845 1846 const new_func_info = zcu.funcInfo(func); 1847 const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav); 1848 const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod.?); 1849 1850 const dlw = &wip_nav.debug_line.writer; 1851 if (dwarf.incremental()) { 1852 const new_nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, new_func_info.owner_nav); 1853 errdefer _ = if (!new_nav_gop.found_existing) dwarf.navs.pop(); 1854 if (!new_nav_gop.found_existing) new_nav_gop.value_ptr.* = try dwarf.addCommonEntry(new_unit); 1855 1856 try dlw.writeByte(DW.LNS.extended_op); 1857 try dlw.writeUleb128(1 + dwarf.sectionOffsetBytes()); 1858 try dlw.writeByte(DW.LNE.ZIG_set_decl); 1859 try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{ 1860 .source_off = @intCast(dlw.end), 1861 .target_sec = .debug_info, 1862 .target_unit = new_unit, 1863 .target_entry = new_nav_gop.value_ptr.toOptional(), 1864 }); 1865 try dlw.splatByteAll(0, dwarf.sectionOffsetBytes()); 1866 return; 1867 } 1868 1869 const old_func_info = zcu.funcInfo(wip_nav.func); 1870 const old_file = zcu.navFileScopeIndex(old_func_info.owner_nav); 1871 if (old_file != new_file) { 1872 const mod_info = dwarf.getModInfo(wip_nav.unit); 1873 try mod_info.dirs.put(dwarf.gpa, new_unit, {}); 1874 const file_gop = try mod_info.files.getOrPut(dwarf.gpa, new_file); 1875 1876 try dlw.writeByte(DW.LNS.set_file); 1877 try dlw.writeUleb128(file_gop.index); 1878 } 1879 1880 const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav); 1881 const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav); 1882 if (new_src_line != old_src_line) { 1883 try dlw.writeByte(DW.LNS.advance_line); 1884 try dlw.writeSleb128(new_src_line - old_src_line); 1885 } 1886 1887 wip_nav.func = func; 1888 } 1889 1890 fn externalReloc(wip_nav: *WipNav, sec: *Section, reloc: ExternalReloc) Allocator.Error!void { 1891 try sec.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(wip_nav.dwarf.gpa, reloc); 1892 } 1893 1894 pub fn infoExternalReloc(wip_nav: *WipNav, reloc: ExternalReloc) Allocator.Error!void { 1895 try wip_nav.externalReloc(&wip_nav.dwarf.debug_info.section, reloc); 1896 } 1897 1898 fn frameExternalReloc(wip_nav: *WipNav, reloc: ExternalReloc) Allocator.Error!void { 1899 try wip_nav.externalReloc(&wip_nav.dwarf.debug_frame.section, reloc); 1900 } 1901 1902 fn abbrevCode(wip_nav: *WipNav, abbrev_code: AbbrevCode) (UpdateError || Writer.Error)!void { 1903 try wip_nav.debug_info.writer.writeUleb128(try wip_nav.dwarf.refAbbrevCode(abbrev_code)); 1904 } 1905 1906 fn sectionOffset( 1907 wip_nav: *WipNav, 1908 comptime sec: Section.Index, 1909 target_sec: Section.Index, 1910 target_unit: Unit.Index, 1911 target_entry: Entry.Index, 1912 target_off: u32, 1913 ) (UpdateError || Writer.Error)!void { 1914 const dwarf = wip_nav.dwarf; 1915 const gpa = dwarf.gpa; 1916 const entry_ptr = @field(dwarf, @tagName(sec)).section.getUnit(wip_nav.unit).getEntry(wip_nav.entry); 1917 const sw = &@field(wip_nav, @tagName(sec)).writer; 1918 const source_off: u32 = @intCast(sw.end); 1919 if (target_sec != sec) { 1920 try entry_ptr.cross_section_relocs.append(gpa, .{ 1921 .source_off = source_off, 1922 .target_sec = target_sec, 1923 .target_unit = target_unit, 1924 .target_entry = target_entry.toOptional(), 1925 .target_off = target_off, 1926 }); 1927 } else if (target_unit != wip_nav.unit) { 1928 try entry_ptr.cross_unit_relocs.append(gpa, .{ 1929 .source_off = source_off, 1930 .target_unit = target_unit, 1931 .target_entry = target_entry.toOptional(), 1932 .target_off = target_off, 1933 }); 1934 } else { 1935 try entry_ptr.cross_entry_relocs.append(gpa, .{ 1936 .source_off = source_off, 1937 .target_entry = target_entry.toOptional(), 1938 .target_off = target_off, 1939 }); 1940 } 1941 try sw.splatByteAll(0, dwarf.sectionOffsetBytes()); 1942 } 1943 1944 fn infoSectionOffset( 1945 wip_nav: *WipNav, 1946 target_sec: Section.Index, 1947 target_unit: Unit.Index, 1948 target_entry: Entry.Index, 1949 target_off: u32, 1950 ) (UpdateError || Writer.Error)!void { 1951 try wip_nav.sectionOffset(.debug_info, target_sec, target_unit, target_entry, target_off); 1952 } 1953 1954 fn strp(wip_nav: *WipNav, str: []const u8) (UpdateError || Writer.Error)!void { 1955 try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0); 1956 } 1957 1958 fn strpFmt(wip_nav: *WipNav, comptime fmt: []const u8, args: anytype) (UpdateError || Writer.Error)!void { 1959 const str = try std.fmt.allocPrint(wip_nav.dwarf.gpa, fmt, args); 1960 defer wip_nav.dwarf.gpa.free(str); 1961 return wip_nav.strp(str); 1962 } 1963 1964 const ExprLocCounter = struct { 1965 dw: Writer.Discarding, 1966 section_offset_bytes: u32, 1967 address_size: AddressSize, 1968 fn init(dwarf: *Dwarf, buf: []u8) ExprLocCounter { 1969 return .{ 1970 .dw = .init(buf), 1971 .section_offset_bytes = dwarf.sectionOffsetBytes(), 1972 .address_size = dwarf.address_size, 1973 }; 1974 } 1975 fn writer(counter: *ExprLocCounter) *Writer { 1976 return &counter.dw.writer; 1977 } 1978 fn endian(_: ExprLocCounter) std.lang.Endian { 1979 return @import("builtin").cpu.arch.endian(); 1980 } 1981 fn addrSym(counter: *ExprLocCounter, _: link.File.SymbolId) Writer.Error!void { 1982 try counter.dw.writer.splatByteAll(undefined, @backingInt(counter.address_size)); 1983 } 1984 fn infoEntry(counter: *ExprLocCounter, _: Unit.Index, _: Entry.Index) Writer.Error!void { 1985 try counter.dw.writer.splatByteAll(undefined, counter.section_offset_bytes); 1986 } 1987 }; 1988 1989 fn infoExprLoc(wip_nav: *WipNav, loc: Loc) (UpdateError || Writer.Error)!void { 1990 var buf: [64]u8 = undefined; 1991 var counter: ExprLocCounter = .init(wip_nav.dwarf, &buf); 1992 try loc.write(&counter); 1993 1994 const adapter: struct { 1995 wip_nav: *WipNav, 1996 fn writer(ctx: @This()) *Writer { 1997 return &ctx.wip_nav.debug_info.writer; 1998 } 1999 fn endian(ctx: @This()) std.lang.Endian { 2000 return ctx.wip_nav.dwarf.endian; 2001 } 2002 fn addrSym(ctx: @This(), sym_index: link.File.SymbolId) (UpdateError || Writer.Error)!void { 2003 try ctx.wip_nav.infoAddrSym(sym_index, 0); 2004 } 2005 fn infoEntry( 2006 ctx: @This(), 2007 unit: Unit.Index, 2008 entry: Entry.Index, 2009 ) (UpdateError || Writer.Error)!void { 2010 try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); 2011 } 2012 } = .{ .wip_nav = wip_nav }; 2013 try adapter.writer().writeUleb128(counter.dw.fullCount()); 2014 try loc.write(adapter); 2015 } 2016 2017 fn infoAddrSym( 2018 wip_nav: *WipNav, 2019 sym_index: link.File.SymbolId, 2020 sym_off: u64, 2021 ) (UpdateError || Writer.Error)!void { 2022 const diw = &wip_nav.debug_info.writer; 2023 try wip_nav.infoExternalReloc(.{ 2024 .source_off = @intCast(diw.end), 2025 .target_sym = sym_index, 2026 .target_off = sym_off, 2027 }); 2028 try diw.splatByteAll(0, @backingInt(wip_nav.dwarf.address_size)); 2029 } 2030 2031 fn frameExprLoc(wip_nav: *WipNav, loc: Loc) (UpdateError || Writer.Error)!void { 2032 var buf: [64]u8 = undefined; 2033 var counter: ExprLocCounter = .init(wip_nav.dwarf, &buf); 2034 try loc.write(&counter); 2035 2036 const adapter: struct { 2037 wip_nav: *WipNav, 2038 fn writer(ctx: @This()) *Writer { 2039 return &ctx.wip_nav.debug_frame.writer; 2040 } 2041 fn endian(ctx: @This()) std.lang.Endian { 2042 return ctx.wip_nav.dwarf.endian; 2043 } 2044 fn addrSym(ctx: @This(), sym_index: link.File.SymbolId) (UpdateError || Writer.Error)!void { 2045 try ctx.wip_nav.frameAddrSym(sym_index, 0); 2046 } 2047 fn infoEntry( 2048 ctx: @This(), 2049 unit: Unit.Index, 2050 entry: Entry.Index, 2051 ) (UpdateError || Writer.Error)!void { 2052 try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0); 2053 } 2054 } = .{ .wip_nav = wip_nav }; 2055 try adapter.writer().writeUleb128(counter.dw.fullCount()); 2056 try loc.write(adapter); 2057 } 2058 2059 fn frameAddrSym( 2060 wip_nav: *WipNav, 2061 sym_index: link.File.SymbolId, 2062 sym_off: u64, 2063 ) (UpdateError || Writer.Error)!void { 2064 const dfw = &wip_nav.debug_frame.writer; 2065 try wip_nav.frameExternalReloc(.{ 2066 .source_off = @intCast(dfw.end), 2067 .target_sym = sym_index, 2068 .target_off = sym_off, 2069 }); 2070 try dfw.splatByteAll(0, @backingInt(wip_nav.dwarf.address_size)); 2071 } 2072 2073 fn refNav( 2074 wip_nav: *WipNav, 2075 nav_index: InternPool.Nav.Index, 2076 ) (UpdateError || Writer.Error)!void { 2077 const unit, const entry = try wip_nav.dwarf.getNavEntry(nav_index); 2078 try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); 2079 } 2080 2081 fn refType(wip_nav: *WipNav, ty: Type) (UpdateError || Writer.Error)!void { 2082 return wip_nav.refValue(ty.toValue()); 2083 } 2084 2085 fn refValue(wip_nav: *WipNav, value: Value) (UpdateError || Writer.Error)!void { 2086 const unit, const entry = try wip_nav.getValueEntry(value); 2087 try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); 2088 } 2089 2090 fn getValueEntry(wip_nav: *WipNav, value: Value) UpdateError!struct { Unit.Index, Entry.Index } { 2091 if (value.typeOf(wip_nav.pt.zcu).toIntern() != .type_type) { 2092 assert(value.typeOf(wip_nav.pt.zcu).comptimeOnly(wip_nav.pt.zcu)); 2093 } 2094 const dwarf = wip_nav.dwarf; 2095 const index = try dwarf.const_pool.get(wip_nav.pt, dwarf.constPoolUser(), value.toIntern()); 2096 return dwarf.values.items[@backingInt(index)]; 2097 } 2098 2099 fn refForward(wip_nav: *WipNav) (Allocator.Error || Writer.Error)!u32 { 2100 const dwarf = wip_nav.dwarf; 2101 const diw = &wip_nav.debug_info.writer; 2102 const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs; 2103 const reloc_index: u32 = @intCast(cross_entry_relocs.items.len); 2104 try cross_entry_relocs.append(dwarf.gpa, .{ 2105 .source_off = @intCast(diw.end), 2106 .target_entry = undefined, 2107 .target_off = undefined, 2108 }); 2109 try diw.splatByteAll(0, dwarf.sectionOffsetBytes()); 2110 return reloc_index; 2111 } 2112 2113 fn finishForward(wip_nav: *WipNav, reloc_index: u32) void { 2114 const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs.items[reloc_index]; 2115 reloc.target_entry = wip_nav.entry.toOptional(); 2116 reloc.target_off = @intCast(wip_nav.debug_info.writer.end); 2117 } 2118 2119 fn blockValue( 2120 wip_nav: *WipNav, 2121 val: Value, 2122 ) (UpdateError || Writer.Error)!void { 2123 const ty = val.typeOf(wip_nav.pt.zcu); 2124 const diw = &wip_nav.debug_info.writer; 2125 const size = ty.abiSize(wip_nav.pt.zcu); 2126 try diw.writeUleb128(size); 2127 if (size == 0) return; 2128 const old_end = diw.end; 2129 try codegen.generateSymbol( 2130 wip_nav.dwarf.bin_file, 2131 wip_nav.pt, 2132 val, 2133 diw, 2134 .{ .debug_output = .{ .dwarf = wip_nav } }, 2135 ); 2136 if (old_end + size != diw.end) { 2137 std.debug.print("{f} [{}]: {} != {}\n", .{ 2138 ty.fmt(wip_nav.pt), 2139 ty.toIntern(), 2140 size, 2141 diw.end - old_end, 2142 }); 2143 unreachable; 2144 } 2145 } 2146 2147 fn bigIntConstValue(wip_nav: *WipNav, ty: Type, big_int: std.math.big.int.Const) (UpdateError || Writer.Error)!void { 2148 const zcu = wip_nav.pt.zcu; 2149 const diw = &wip_nav.debug_info.writer; 2150 const signedness = switch (ty.toIntern()) { 2151 .comptime_int_type => .signed, 2152 else => ty.intInfo(zcu).signedness, 2153 }; 2154 const bits = @max(1, big_int.bitCountTwosCompForSignedness(signedness)); 2155 if (bits <= 64) { 2156 try diw.writeUleb128(@as(u13, switch (signedness) { 2157 .signed => DW.FORM.sdata, 2158 .unsigned => DW.FORM.udata, 2159 })); 2160 try wip_nav.debug_info.ensureUnusedCapacity(@divCeil(bits, 7)); 2161 var bit: usize = 0; 2162 var carry: u1 = 1; 2163 while (bit < bits) { 2164 const limb_bits = @typeInfo(std.math.big.Limb).int.bits; 2165 const limb_index = bit / limb_bits; 2166 const limb_shift: std.math.Log2Int(std.math.big.Limb) = @intCast(bit % limb_bits); 2167 const low_abs_part: u7 = @truncate(big_int.limbs[limb_index] >> limb_shift); 2168 const abs_part = if (limb_shift > limb_bits - 7 and limb_index + 1 < big_int.limbs.len) abs_part: { 2169 const high_abs_part: u7 = @truncate(big_int.limbs[limb_index + 1] << -%limb_shift); 2170 break :abs_part high_abs_part | low_abs_part; 2171 } else low_abs_part; 2172 const twos_comp_part = if (big_int.positive) abs_part else twos_comp_part: { 2173 const twos_comp_part, carry = @addWithOverflow(~abs_part, carry); 2174 break :twos_comp_part twos_comp_part; 2175 }; 2176 bit += 7; 2177 diw.writeByte(@as(u8, if (bit < bits) 0x80 else 0x00) | twos_comp_part) catch unreachable; 2178 } 2179 } else { 2180 try diw.writeUleb128(DW.FORM.block); 2181 const bytes = @max(ty.abiSize(zcu), @divCeil(bits, 8)); 2182 try diw.writeUleb128(bytes); 2183 try wip_nav.debug_info.ensureUnusedCapacity(@intCast(bytes)); 2184 big_int.writeTwosComplement( 2185 try diw.writableSlice(@intCast(bytes)), 2186 wip_nav.dwarf.endian, 2187 ); 2188 } 2189 } 2190 2191 fn enumConstValue(wip_nav: *WipNav, loaded_enum: InternPool.LoadedEnumType, field_index: usize) (UpdateError || Writer.Error)!void { 2192 const zcu = wip_nav.pt.zcu; 2193 const ip = &zcu.intern_pool; 2194 var big_int_space: Value.BigIntSpace = undefined; 2195 try wip_nav.bigIntConstValue(.fromInterned(loaded_enum.int_tag_type), if (loaded_enum.field_values.len > 0) 2196 Value.fromInterned(loaded_enum.field_values.get(ip)[field_index]).toBigInt(&big_int_space, zcu) 2197 else 2198 std.math.big.int.Mutable.init(&big_int_space.limbs, field_index).toConst()); 2199 } 2200 2201 fn declCommon( 2202 wip_nav: *WipNav, 2203 abbrev_code: struct { 2204 decl: AbbrevCode, 2205 decl_specification: AbbrevCode, 2206 decl_instance: AbbrevCode, 2207 }, 2208 nav: *const InternPool.Nav, 2209 file: Zcu.File.Index, 2210 decl: *const std.zig.Zir.Inst.Declaration.Unwrapped, 2211 ) (UpdateError || Writer.Error)!void { 2212 const zcu = wip_nav.pt.zcu; 2213 const ip = &zcu.intern_pool; 2214 const dwarf = wip_nav.dwarf; 2215 const diw = &wip_nav.debug_info.writer; 2216 2217 const orig_entry = wip_nav.entry; 2218 defer wip_nav.entry = orig_entry; 2219 const parent_type, const is_specification = if (nav.analysis) |analysis| parent_info: { 2220 const parent_type: Type = .fromInterned(zcu.namespacePtr(analysis.namespace).owner_type); 2221 const decl_gop = try dwarf.decls.getOrPut(dwarf.gpa, analysis.zir_index); 2222 errdefer _ = if (!decl_gop.found_existing) dwarf.decls.pop(); 2223 const was_specification = decl_gop.found_existing and 2224 switch (try dwarf.debug_info.declAbbrevCode(wip_nav.unit, decl_gop.value_ptr.*)) { 2225 .null, 2226 .decl_alias, 2227 .decl_empty_enum, 2228 .decl_enum, 2229 .decl_namespace_struct, 2230 .decl_struct, 2231 .decl_packed_struct, 2232 .decl_union, 2233 .decl_var, 2234 .decl_const, 2235 .decl_const_runtime_bits, 2236 .decl_const_comptime_state, 2237 .decl_const_runtime_bits_comptime_state, 2238 .decl_nullary_func, 2239 .decl_func, 2240 .decl_nullary_func_generic, 2241 .decl_func_generic, 2242 .decl_extern_nullary_func, 2243 .decl_extern_func, 2244 => false, 2245 .decl_specification_var, 2246 .decl_specification_const, 2247 .decl_specification_func, 2248 => true, 2249 2250 // This comes from a decl which was previously generated as an incomplete value 2251 // (I think that must mean either a function or an extern which previously had 2252 // incomplete types). 2253 .undefined_comptime_value => false, 2254 2255 else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}), 2256 }; 2257 if (parent_type.getCaptures(zcu).len == 0) { 2258 if (was_specification) try dwarf.freeCommonEntry(wip_nav.unit, decl_gop.value_ptr.*); 2259 decl_gop.value_ptr.* = orig_entry; 2260 break :parent_info .{ parent_type, false }; 2261 } else { 2262 if (was_specification) 2263 dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(decl_gop.value_ptr.*).clear() 2264 else 2265 decl_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit); 2266 wip_nav.entry = decl_gop.value_ptr.*; 2267 break :parent_info .{ parent_type, true }; 2268 } 2269 } else .{ null, false }; 2270 2271 try wip_nav.abbrevCode(if (is_specification) abbrev_code.decl_specification else abbrev_code.decl); 2272 try wip_nav.refType((if (is_specification) null else parent_type) orelse 2273 .fromInterned(zcu.fileRootType(file))); 2274 assert(diw.end == DebugInfo.declEntryLineOff(dwarf)); 2275 try diw.writeInt(u32, decl.src_line + 1, dwarf.endian); 2276 try diw.writeUleb128(decl.src_column + 1); 2277 try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private); 2278 try wip_nav.strp(nav.name.toSlice(ip)); 2279 2280 if (!is_specification) return; 2281 const specification_entry = wip_nav.entry; 2282 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, specification_entry, dwarf, wip_nav.debug_info.written()); 2283 wip_nav.debug_info.clearRetainingCapacity(); 2284 wip_nav.entry = orig_entry; 2285 try wip_nav.abbrevCode(abbrev_code.decl_instance); 2286 try wip_nav.refType(parent_type.?); 2287 try wip_nav.infoSectionOffset(.debug_info, wip_nav.unit, specification_entry, 0); 2288 } 2289 }; 2290 2291 /// When allocating, the ideal_capacity is calculated by 2292 /// actual_capacity + (actual_capacity / ideal_factor) 2293 const ideal_factor = 3; 2294 2295 fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { 2296 return actual_size +| (actual_size / ideal_factor); 2297 } 2298 2299 pub fn init(lf: *link.File, format: DW.Format) Dwarf { 2300 const comp = lf.comp; 2301 const target = &comp.root_mod.resolved_target.result; 2302 return .{ 2303 .gpa = comp.gpa, 2304 .bin_file = lf, 2305 .format = format, 2306 .address_size = switch (target.ptrBitWidth()) { 2307 0...32 => .@"32", 2308 33...64 => .@"64", 2309 else => unreachable, 2310 }, 2311 .endian = target.cpu.arch.endian(), 2312 2313 .const_pool = .empty, 2314 2315 .mods = .empty, 2316 .values = .empty, 2317 .navs = .empty, 2318 .decls = .empty, 2319 2320 .debug_abbrev = .{ .section = Section.init }, 2321 .debug_aranges = .{ .section = Section.init }, 2322 .debug_frame = .{ 2323 .header = if (target.cpu.arch == .x86_64 and target.ofmt == .elf) header: { 2324 const Register = @import("../codegen/x86_64/bits.zig").Register; 2325 break :header comptime .{ 2326 .format = .eh_frame, 2327 .code_alignment_factor = 1, 2328 .data_alignment_factor = -8, 2329 .return_address_register = Register.rip.dwarfNum(), 2330 .initial_instructions = &.{ 2331 .{ .def_cfa = .{ .reg = Register.rsp.dwarfNum(), .off = 8 } }, 2332 .{ .offset = .{ .reg = Register.rip.dwarfNum(), .off = -8 } }, 2333 }, 2334 }; 2335 } else .{ 2336 .format = .none, 2337 .code_alignment_factor = undefined, 2338 .data_alignment_factor = undefined, 2339 .return_address_register = undefined, 2340 .initial_instructions = &.{}, 2341 }, 2342 .section = Section.init, 2343 }, 2344 .debug_info = .{ .section = Section.init }, 2345 .debug_line = .{ 2346 .header = switch (target.cpu.arch) { 2347 .x86_64, .aarch64 => .{ 2348 .minimum_instruction_length = 1, 2349 .maximum_operations_per_instruction = 1, 2350 .default_is_stmt = true, 2351 .line_base = -5, 2352 .line_range = 14, 2353 .opcode_base = DW.LNS.set_isa + 1, 2354 }, 2355 else => .{ 2356 .minimum_instruction_length = 1, 2357 .maximum_operations_per_instruction = 1, 2358 .default_is_stmt = true, 2359 .line_base = 0, 2360 .line_range = 1, 2361 .opcode_base = DW.LNS.set_isa + 1, 2362 }, 2363 }, 2364 .section = Section.init, 2365 }, 2366 .debug_line_str = StringSection.init, 2367 .debug_loclists = .{ .section = Section.init }, 2368 .debug_rnglists = .{ .section = Section.init }, 2369 .debug_str = StringSection.init, 2370 }; 2371 } 2372 2373 pub fn reloadSectionMetadata(dwarf: *Dwarf) void { 2374 if (dwarf.bin_file.cast(.macho)) |macho_file| { 2375 if (macho_file.d_sym) |*d_sym| { 2376 for ([_]*Section{ 2377 &dwarf.debug_abbrev.section, 2378 &dwarf.debug_aranges.section, 2379 &dwarf.debug_info.section, 2380 &dwarf.debug_line.section, 2381 &dwarf.debug_line_str.section, 2382 &dwarf.debug_loclists.section, 2383 &dwarf.debug_rnglists.section, 2384 &dwarf.debug_str.section, 2385 }, [_]u8{ 2386 d_sym.debug_abbrev_section_index.?, 2387 d_sym.debug_aranges_section_index.?, 2388 d_sym.debug_info_section_index.?, 2389 d_sym.debug_line_section_index.?, 2390 d_sym.debug_line_str_section_index.?, 2391 d_sym.debug_loclists_section_index.?, 2392 d_sym.debug_rnglists_section_index.?, 2393 d_sym.debug_str_section_index.?, 2394 }) |sec, sect_index| { 2395 const header = &d_sym.sections.items[sect_index]; 2396 sec.index = sect_index; 2397 sec.len = header.size; 2398 } 2399 } else { 2400 for ([_]*Section{ 2401 &dwarf.debug_abbrev.section, 2402 &dwarf.debug_aranges.section, 2403 &dwarf.debug_info.section, 2404 &dwarf.debug_line.section, 2405 &dwarf.debug_line_str.section, 2406 &dwarf.debug_loclists.section, 2407 &dwarf.debug_rnglists.section, 2408 &dwarf.debug_str.section, 2409 }, [_]u8{ 2410 macho_file.debug_abbrev_sect_index.?, 2411 macho_file.debug_aranges_sect_index.?, 2412 macho_file.debug_info_sect_index.?, 2413 macho_file.debug_line_sect_index.?, 2414 macho_file.debug_line_str_sect_index.?, 2415 macho_file.debug_loclists_sect_index.?, 2416 macho_file.debug_rnglists_sect_index.?, 2417 macho_file.debug_str_sect_index.?, 2418 }) |sec, sect_index| { 2419 const header = &macho_file.sections.items(.header)[sect_index]; 2420 sec.index = sect_index; 2421 sec.len = header.size; 2422 } 2423 } 2424 } 2425 } 2426 2427 pub fn initMetadata(dwarf: *Dwarf) UpdateError!void { 2428 if (dwarf.bin_file.cast(.elf)) |elf_file| { 2429 const zo = elf_file.zigObjectPtr().?; 2430 for ([_]*Section{ 2431 &dwarf.debug_abbrev.section, 2432 &dwarf.debug_aranges.section, 2433 &dwarf.debug_frame.section, 2434 &dwarf.debug_info.section, 2435 &dwarf.debug_line.section, 2436 &dwarf.debug_line_str.section, 2437 &dwarf.debug_loclists.section, 2438 &dwarf.debug_rnglists.section, 2439 &dwarf.debug_str.section, 2440 }, [_]u32{ 2441 zo.debug_abbrev_index.?, 2442 zo.debug_aranges_index.?, 2443 zo.eh_frame_index.?, 2444 zo.debug_info_index.?, 2445 zo.debug_line_index.?, 2446 zo.debug_line_str_index.?, 2447 zo.debug_loclists_index.?, 2448 zo.debug_rnglists_index.?, 2449 zo.debug_str_index.?, 2450 }) |sec, sym_index| { 2451 sec.index = sym_index; 2452 } 2453 } 2454 dwarf.reloadSectionMetadata(); 2455 2456 dwarf.debug_abbrev.section.pad_entries_to_ideal = false; 2457 assert(try dwarf.debug_abbrev.section.addUnit(DebugAbbrev.header_bytes, DebugAbbrev.trailer_bytes, dwarf) == DebugAbbrev.unit); 2458 errdefer dwarf.debug_abbrev.section.popUnit(dwarf.gpa); 2459 for (std.enums.values(AbbrevCode)) |abbrev_code| 2460 assert(@backingInt(try dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).addEntry(dwarf.gpa)) == @backingInt(abbrev_code)); 2461 2462 dwarf.debug_aranges.section.pad_entries_to_ideal = false; 2463 dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@backingInt(dwarf.address_size) * 2); 2464 2465 dwarf.debug_frame.section.alignment = switch (dwarf.debug_frame.header.format) { 2466 .none => .@"1", 2467 .debug_frame => InternPool.Alignment.fromNonzeroByteUnits(@backingInt(dwarf.address_size)), 2468 .eh_frame => .@"4", 2469 }; 2470 2471 dwarf.debug_line_str.section.pad_entries_to_ideal = false; 2472 assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit); 2473 errdefer dwarf.debug_line_str.section.popUnit(dwarf.gpa); 2474 2475 dwarf.debug_str.section.pad_entries_to_ideal = false; 2476 assert(try dwarf.debug_str.section.addUnit(0, 0, dwarf) == StringSection.unit); 2477 errdefer dwarf.debug_str.section.popUnit(dwarf.gpa); 2478 2479 dwarf.debug_loclists.section.pad_entries_to_ideal = false; 2480 2481 dwarf.debug_rnglists.section.pad_entries_to_ideal = false; 2482 } 2483 2484 pub fn deinit(dwarf: *Dwarf) void { 2485 const gpa = dwarf.gpa; 2486 dwarf.const_pool.deinit(gpa); 2487 for (dwarf.mods.values()) |*mod_info| mod_info.deinit(gpa); 2488 dwarf.mods.deinit(gpa); 2489 dwarf.values.deinit(gpa); 2490 dwarf.navs.deinit(gpa); 2491 dwarf.decls.deinit(gpa); 2492 dwarf.debug_abbrev.section.deinit(gpa); 2493 dwarf.debug_aranges.section.deinit(gpa); 2494 dwarf.debug_frame.section.deinit(gpa); 2495 dwarf.debug_info.section.deinit(gpa); 2496 dwarf.debug_line.section.deinit(gpa); 2497 dwarf.debug_line_str.deinit(gpa); 2498 dwarf.debug_loclists.section.deinit(gpa); 2499 dwarf.debug_rnglists.section.deinit(gpa); 2500 dwarf.debug_str.deinit(gpa); 2501 dwarf.* = undefined; 2502 } 2503 2504 fn getNavEntry( 2505 dwarf: *Dwarf, 2506 nav_index: InternPool.Nav.Index, 2507 ) UpdateError!struct { Unit.Index, Entry.Index } { 2508 const zcu = dwarf.bin_file.comp.zcu.?; 2509 const ip = &zcu.intern_pool; 2510 const nav = ip.getNav(nav_index); 2511 const unit = try dwarf.getUnit(zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?); 2512 const gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index); 2513 if (gop.found_existing) return .{ unit, gop.value_ptr.* }; 2514 const entry = try dwarf.addCommonEntry(unit); 2515 gop.value_ptr.* = entry; 2516 return .{ unit, entry }; 2517 } 2518 2519 fn getUnit(dwarf: *Dwarf, mod: *Module) !Unit.Index { 2520 const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod); 2521 const unit: Unit.Index = @fromBackingInt(@intCast(mod_gop.index)); 2522 if (!mod_gop.found_existing) { 2523 errdefer _ = dwarf.mods.pop(); 2524 mod_gop.value_ptr.* = .{ 2525 .root_dir_path = undefined, 2526 .dirs = .empty, 2527 .files = .empty, 2528 }; 2529 errdefer mod_gop.value_ptr.dirs.deinit(dwarf.gpa); 2530 try mod_gop.value_ptr.dirs.putNoClobber(dwarf.gpa, unit, {}); 2531 assert(try dwarf.debug_aranges.section.addUnit( 2532 DebugAranges.headerBytes(dwarf), 2533 DebugAranges.trailerBytes(dwarf), 2534 dwarf, 2535 ) == unit); 2536 errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa); 2537 assert(try dwarf.debug_frame.section.addUnit( 2538 DebugFrame.headerBytes(dwarf), 2539 DebugFrame.trailerBytes(dwarf), 2540 dwarf, 2541 ) == unit); 2542 errdefer dwarf.debug_frame.section.popUnit(dwarf.gpa); 2543 assert(try dwarf.debug_info.section.addUnit( 2544 DebugInfo.headerBytes(dwarf), 2545 DebugInfo.trailer_bytes, 2546 dwarf, 2547 ) == unit); 2548 errdefer dwarf.debug_info.section.popUnit(dwarf.gpa); 2549 assert(try dwarf.debug_line.section.addUnit( 2550 DebugLine.headerBytes(dwarf, 5, 25), 2551 DebugLine.trailer_bytes, 2552 dwarf, 2553 ) == unit); 2554 errdefer dwarf.debug_line.section.popUnit(dwarf.gpa); 2555 assert(try dwarf.debug_loclists.section.addUnit( 2556 DebugLocLists.headerBytes(dwarf), 2557 DebugLocLists.trailer_bytes, 2558 dwarf, 2559 ) == unit); 2560 errdefer dwarf.debug_loclists.section.popUnit(dwarf.gpa); 2561 assert(try dwarf.debug_rnglists.section.addUnit( 2562 DebugRngLists.headerBytes(dwarf), 2563 DebugRngLists.trailer_bytes, 2564 dwarf, 2565 ) == unit); 2566 errdefer dwarf.debug_rnglists.section.popUnit(dwarf.gpa); 2567 } 2568 return unit; 2569 } 2570 2571 fn getUnitIfExists(dwarf: *const Dwarf, mod: *Module) ?Unit.Index { 2572 return @fromBackingInt(@intCast(dwarf.mods.getIndex(mod) orelse return null)); 2573 } 2574 2575 fn getModInfo(dwarf: *Dwarf, unit: Unit.Index) *ModInfo { 2576 return &dwarf.mods.values()[@backingInt(unit)]; 2577 } 2578 2579 fn getUnitModule(dwarf: *Dwarf, unit: Unit.Index) *Module { 2580 return dwarf.mods.keys()[@backingInt(unit)]; 2581 } 2582 2583 pub fn initWipNav( 2584 dwarf: *Dwarf, 2585 pt: Zcu.PerThread, 2586 nav_index: InternPool.Nav.Index, 2587 sym_index: link.File.SymbolId, 2588 ) link.Error!WipNav { 2589 return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) { 2590 error.OutOfMemory => error.OutOfMemory, 2591 else => |e| pt.zcu.codegenFail(nav_index, "failed to init dwarf: {s}", .{@errorName(e)}), 2592 }; 2593 } 2594 2595 fn initWipNavInner( 2596 dwarf: *Dwarf, 2597 pt: Zcu.PerThread, 2598 nav_index: InternPool.Nav.Index, 2599 sym_index: link.File.SymbolId, 2600 ) !WipNav { 2601 const zcu = pt.zcu; 2602 const ip = &zcu.intern_pool; 2603 2604 const nav = ip.getNav(nav_index); 2605 const inst_info = nav.srcInst(ip).resolveFull(ip).?; 2606 const file = zcu.fileByIndex(inst_info.file); 2607 const decl = file.zir.?.getDeclaration(inst_info.inst); 2608 log.debug("initWipNav({s}:{d}:{d} %{d} = {f})", .{ 2609 file.sub_file_path, 2610 decl.src_line + 1, 2611 decl.src_column + 1, 2612 @backingInt(inst_info.inst), 2613 nav.fqn.fmt(ip), 2614 }); 2615 2616 const mod = file.mod.?; 2617 const unit = try dwarf.getUnit(mod); 2618 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index); 2619 errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop(); 2620 if (nav_gop.found_existing) { 2621 for ([_]*Section{ 2622 &dwarf.debug_aranges.section, 2623 &dwarf.debug_info.section, 2624 &dwarf.debug_line.section, 2625 &dwarf.debug_loclists.section, 2626 &dwarf.debug_rnglists.section, 2627 }) |sec| sec.getUnit(unit).getEntry(nav_gop.value_ptr.*).clear(); 2628 } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); 2629 var wip_nav: WipNav = .{ 2630 .dwarf = dwarf, 2631 .pt = pt, 2632 .unit = unit, 2633 .entry = nav_gop.value_ptr.*, 2634 .any_children = false, 2635 .func = .none, 2636 .func_sym_index = undefined, 2637 .func_high_pc = undefined, 2638 .blocks = undefined, 2639 .cfi = undefined, 2640 .debug_frame = .init(dwarf.gpa), 2641 .debug_info = .init(dwarf.gpa), 2642 .debug_line = .init(dwarf.gpa), 2643 .debug_loclists = .init(dwarf.gpa), 2644 }; 2645 errdefer wip_nav.deinit(); 2646 2647 const nav_val = zcu.navValue(nav_index); 2648 nav_val: switch (ip.indexToKey(nav_val.toIntern())) { 2649 .@"extern" => |@"extern"| switch (@"extern".source) { 2650 .builtin => { 2651 const maybe_func_type = switch (ip.indexToKey(@"extern".ty)) { 2652 .func_type => |func_type| func_type, 2653 else => null, 2654 }; 2655 const diw = &wip_nav.debug_info.writer; 2656 try wip_nav.abbrevCode(if (maybe_func_type) |func_type| 2657 if (func_type.param_types.len > 0 or func_type.is_var_args) .builtin_extern_func else .builtin_extern_nullary_func 2658 else 2659 .builtin_extern_var); 2660 try wip_nav.refType(.fromInterned(zcu.fileRootType(inst_info.file))); 2661 try wip_nav.strp(@"extern".name.toSlice(ip)); 2662 try wip_nav.refType(.fromInterned(if (maybe_func_type) |func_type| func_type.return_type else @"extern".ty)); 2663 if (maybe_func_type) |func_type| { 2664 try wip_nav.infoAddrSym(sym_index, 0); 2665 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu))); 2666 if (func_type.param_types.len > 0 or func_type.is_var_args) { 2667 for (func_type.param_types.get(ip)) |param_type| { 2668 try wip_nav.abbrevCode(.extern_param); 2669 try wip_nav.refType(.fromInterned(param_type)); 2670 } 2671 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args); 2672 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 2673 } 2674 } else try wip_nav.infoExprLoc(.{ .addr_reloc = sym_index }); 2675 }, 2676 .syntax => switch (ip.isFunctionType(@"extern".ty)) { 2677 false => continue :nav_val .{ .undef = @"extern".ty }, 2678 true => { 2679 const func_type = ip.indexToKey(@"extern".ty).func_type; 2680 const diw = &wip_nav.debug_info.writer; 2681 try wip_nav.declCommon(if (func_type.param_types.len > 0 or func_type.is_var_args) .{ 2682 .decl = .decl_extern_func, 2683 .decl_specification = .decl_specification_func, 2684 .decl_instance = .decl_instance_extern_func, 2685 } else .{ 2686 .decl = .decl_extern_nullary_func, 2687 .decl_specification = .decl_specification_func, 2688 .decl_instance = .decl_instance_extern_nullary_func, 2689 }, &nav, inst_info.file, &decl); 2690 try wip_nav.strp(@"extern".name.toSlice(ip)); 2691 try wip_nav.refType(.fromInterned(func_type.return_type)); 2692 try wip_nav.infoAddrSym(sym_index, 0); 2693 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu))); 2694 if (func_type.param_types.len > 0 or func_type.is_var_args) { 2695 for (func_type.param_types.get(ip)) |param_type| { 2696 try wip_nav.abbrevCode(.extern_param); 2697 try wip_nav.refType(.fromInterned(param_type)); 2698 } 2699 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args); 2700 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 2701 } 2702 }, 2703 }, 2704 }, 2705 .func => |func| if (func.owner_nav != nav_index) { 2706 try wip_nav.declCommon(.{ 2707 .decl = .decl_alias, 2708 .decl_specification = .decl_specification_const, 2709 .decl_instance = .decl_instance_alias, 2710 }, &nav, inst_info.file, &decl); 2711 try wip_nav.refNav(func.owner_nav); 2712 } else { 2713 const func_type = ip.indexToKey(func.ty).func_type; 2714 wip_nav.func = nav_val.toIntern(); 2715 wip_nav.func_sym_index = sym_index; 2716 wip_nav.blocks = .empty; 2717 if (dwarf.debug_frame.header.format != .none) wip_nav.cfi = .{ 2718 .loc = 0, 2719 .cfa = dwarf.debug_frame.header.initial_instructions[0].def_cfa, 2720 }; 2721 2722 switch (dwarf.debug_frame.header.format) { 2723 .none => {}, 2724 .debug_frame, .eh_frame => |format| { 2725 const entry = dwarf.debug_frame.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry); 2726 const dfw = &wip_nav.debug_frame.writer; 2727 switch (dwarf.format) { 2728 .@"32" => try dfw.writeInt(u32, undefined, dwarf.endian), 2729 .@"64" => { 2730 try dfw.writeInt(u32, std.math.maxInt(u32), dwarf.endian); 2731 try dfw.writeInt(u64, undefined, dwarf.endian); 2732 }, 2733 } 2734 switch (format) { 2735 .none => unreachable, 2736 .debug_frame => { 2737 try entry.cross_entry_relocs.append(dwarf.gpa, .{ 2738 .source_off = @intCast(dfw.end), 2739 }); 2740 try dfw.splatByteAll(0, dwarf.sectionOffsetBytes()); 2741 try wip_nav.frameAddrSym(sym_index, 0); 2742 try dfw.splatByteAll(undefined, @backingInt(dwarf.address_size)); 2743 }, 2744 .eh_frame => { 2745 try dfw.writeInt(u32, undefined, dwarf.endian); 2746 try wip_nav.frameExternalReloc(.{ 2747 .source_off = @intCast(dfw.end), 2748 .target_sym = sym_index, 2749 }); 2750 try dfw.writeInt(u32, 0, dwarf.endian); 2751 try dfw.writeInt(u32, undefined, dwarf.endian); 2752 try dfw.writeUleb128(0); 2753 }, 2754 } 2755 }, 2756 } 2757 2758 const diw = &wip_nav.debug_info.writer; 2759 try wip_nav.declCommon(.{ 2760 .decl = .decl_func, 2761 .decl_specification = .decl_specification_func, 2762 .decl_instance = .decl_instance_func, 2763 }, &nav, inst_info.file, &decl); 2764 try wip_nav.strp(switch (decl.linkage) { 2765 .normal => nav.fqn, 2766 .@"extern", .@"export" => nav.name, 2767 }.toSlice(ip)); 2768 try wip_nav.refType(.fromInterned(func_type.return_type)); 2769 try wip_nav.infoAddrSym(sym_index, 0); 2770 wip_nav.func_high_pc = @intCast(diw.end); 2771 try diw.writeInt(u32, 0, dwarf.endian); 2772 const target = &mod.resolved_target.result; 2773 try diw.writeUleb128(switch (nav.resolved.?.@"align") { 2774 .none => target_info.defaultFunctionAlignment(target), 2775 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)), 2776 }.toByteUnits().?); 2777 try diw.writeByte(@intFromBool(decl.linkage != .normal)); 2778 try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu))); 2779 2780 const dlw = &wip_nav.debug_line.writer; 2781 try dlw.writeByte(DW.LNS.extended_op); 2782 if (dwarf.incremental()) { 2783 try dlw.writeUleb128(1 + dwarf.sectionOffsetBytes()); 2784 try dlw.writeByte(DW.LNE.ZIG_set_decl); 2785 try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{ 2786 .source_off = @intCast(dlw.end), 2787 .target_sec = .debug_info, 2788 .target_unit = wip_nav.unit, 2789 .target_entry = wip_nav.entry.toOptional(), 2790 }); 2791 try dlw.splatByteAll(0, dwarf.sectionOffsetBytes()); 2792 2793 try dlw.writeByte(DW.LNS.set_column); 2794 try dlw.writeUleb128(func.lbrace_column + 1); 2795 2796 try wip_nav.advanceLineAndPc(func.lbrace_line, 0, false); 2797 } else { 2798 try dlw.writeUleb128(1 + @backingInt(dwarf.address_size)); 2799 try dlw.writeByte(DW.LNE.set_address); 2800 try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{ 2801 .source_off = @intCast(dlw.end), 2802 .target_sym = sym_index, 2803 }); 2804 try dlw.splatByteAll(0, @backingInt(dwarf.address_size)); 2805 2806 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file); 2807 try dlw.writeByte(DW.LNS.set_file); 2808 try dlw.writeUleb128(file_gop.index); 2809 2810 try dlw.writeByte(DW.LNS.set_column); 2811 try dlw.writeUleb128(func.lbrace_column + 1); 2812 2813 try wip_nav.advanceLineAndPc(decl.src_line + func.lbrace_line, 0, false); 2814 } 2815 }, 2816 else => { 2817 const diw = &wip_nav.debug_info.writer; 2818 try wip_nav.declCommon(.{ 2819 .decl = .decl_var, 2820 .decl_specification = switch (decl.kind) { 2821 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable, 2822 .@"const" => .decl_specification_const, 2823 .@"var" => .decl_specification_var, 2824 }, 2825 .decl_instance = .decl_instance_var, 2826 }, &nav, inst_info.file, &decl); 2827 try wip_nav.strp(switch (decl.linkage) { 2828 .normal => nav.fqn, 2829 .@"extern", .@"export" => nav.name, 2830 }.toSlice(ip)); 2831 const ty: Type = nav_val.typeOf(zcu); 2832 const addr: Loc = .{ .addr_reloc = sym_index }; 2833 const loc: Loc = if (decl.is_threadlocal) loc: { 2834 const target = zcu.comp.root_mod.resolved_target.result; 2835 break :loc switch (target.cpu.arch) { 2836 .x86_64 => .{ .form_tls_address = &addr }, 2837 else => .empty, 2838 }; 2839 } else addr; 2840 switch (decl.kind) { 2841 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable, 2842 .@"const" => { 2843 const const_ty_reloc_index = try wip_nav.refForward(); 2844 try wip_nav.infoExprLoc(loc); 2845 try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse 2846 ty.abiAlignment(zcu).toByteUnits().?); 2847 try diw.writeByte(@intFromBool(decl.linkage != .normal)); 2848 wip_nav.finishForward(const_ty_reloc_index); 2849 try wip_nav.abbrevCode(.is_const); 2850 try wip_nav.refType(ty); 2851 }, 2852 .@"var" => { 2853 try wip_nav.refType(ty); 2854 try wip_nav.infoExprLoc(loc); 2855 try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse 2856 ty.abiAlignment(zcu).toByteUnits().?); 2857 try diw.writeByte(@intFromBool(decl.linkage != .normal)); 2858 }, 2859 } 2860 }, 2861 } 2862 return wip_nav; 2863 } 2864 2865 pub fn finishWipNavFunc( 2866 dwarf: *Dwarf, 2867 pt: Zcu.PerThread, 2868 nav_index: InternPool.Nav.Index, 2869 code_size: u64, 2870 wip_nav: *WipNav, 2871 ) UpdateError!void { 2872 return dwarf.finishWipNavFuncWriterError(pt, nav_index, code_size, wip_nav) catch |err| switch (err) { 2873 error.WriteFailed => error.OutOfMemory, 2874 else => |e| e, 2875 }; 2876 } 2877 fn finishWipNavFuncWriterError( 2878 dwarf: *Dwarf, 2879 pt: Zcu.PerThread, 2880 nav_index: InternPool.Nav.Index, 2881 code_size: u64, 2882 wip_nav: *WipNav, 2883 ) (UpdateError || Writer.Error)!void { 2884 const zcu = pt.zcu; 2885 const ip = &zcu.intern_pool; 2886 const nav = ip.getNav(nav_index); 2887 assert(wip_nav.func != .none); 2888 log.debug("finishWipNavFunc({f})", .{nav.fqn.fmt(ip)}); 2889 2890 { 2891 const external_relocs = &dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs; 2892 try external_relocs.append(dwarf.gpa, .{ .target_sym = wip_nav.func_sym_index }); 2893 var entry: [8 + 8]u8 = undefined; 2894 @memset(entry[0..@backingInt(dwarf.address_size)], 0); 2895 dwarf.writeInt(entry[@backingInt(dwarf.address_size)..][0..@backingInt(dwarf.address_size)], code_size); 2896 try dwarf.debug_aranges.section.replaceEntry( 2897 wip_nav.unit, 2898 wip_nav.entry, 2899 dwarf, 2900 entry[0 .. @backingInt(dwarf.address_size) * 2], 2901 ); 2902 } 2903 switch (dwarf.debug_frame.header.format) { 2904 .none => {}, 2905 .debug_frame, .eh_frame => |format| { 2906 const dfw = &wip_nav.debug_frame.writer; 2907 try dfw.splatByteAll( 2908 DW.CFA.nop, 2909 @intCast(dwarf.debug_frame.section.alignment.forward(dfw.end) - dfw.end), 2910 ); 2911 const contents = wip_nav.debug_frame.written(); 2912 try dwarf.debug_frame.section.resizeEntry(wip_nav.unit, wip_nav.entry, dwarf, @intCast(contents.len)); 2913 const unit = dwarf.debug_frame.section.getUnit(wip_nav.unit); 2914 const entry = unit.getEntry(wip_nav.entry); 2915 const unit_len = (if (entry.next.unwrap()) |next_entry| 2916 unit.getEntry(next_entry).off - entry.off 2917 else 2918 entry.len) - dwarf.unitLengthBytes(); 2919 dwarf.writeInt(contents[dwarf.unitLengthBytes() - dwarf.sectionOffsetBytes() ..][0..dwarf.sectionOffsetBytes()], unit_len); 2920 switch (format) { 2921 .none => unreachable, 2922 .debug_frame => dwarf.writeInt(contents[dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() + 2923 @backingInt(dwarf.address_size) ..][0..@backingInt(dwarf.address_size)], code_size), 2924 .eh_frame => { 2925 std.mem.writeInt( 2926 u32, 2927 contents[dwarf.unitLengthBytes()..][0..4], 2928 unit.header_len + entry.off + dwarf.unitLengthBytes(), 2929 dwarf.endian, 2930 ); 2931 std.mem.writeInt(u32, contents[dwarf.unitLengthBytes() + 4 + 4 ..][0..4], @intCast(code_size), dwarf.endian); 2932 }, 2933 } 2934 try entry.replace(unit, &dwarf.debug_frame.section, dwarf, contents); 2935 }, 2936 } 2937 { 2938 std.mem.writeInt(u32, wip_nav.debug_info.written()[wip_nav.func_high_pc..][0..4], @intCast(code_size), dwarf.endian); 2939 if (wip_nav.any_children) { 2940 const diw = &wip_nav.debug_info.writer; 2941 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 2942 } else { 2943 const abbrev_code_buf = wip_nav.debug_info.written()[0..AbbrevCode.decl_bytes]; 2944 var abbrev_code_fr: std.Io.Reader = .fixed(abbrev_code_buf); 2945 const abbrev_code: AbbrevCode = @fromBackingInt(@intCast( 2946 abbrev_code_fr.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable, 2947 )); 2948 std.leb.writeUnsignedFixed( 2949 AbbrevCode.decl_bytes, 2950 abbrev_code_buf, 2951 @intCast(try dwarf.refAbbrevCode(switch (abbrev_code) { 2952 else => unreachable, 2953 .decl_func => .decl_nullary_func, 2954 .decl_instance_func => .decl_instance_nullary_func, 2955 })), 2956 ); 2957 } 2958 } 2959 { 2960 try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.appendSlice(dwarf.gpa, &.{ 2961 .{ 2962 .source_off = 1, 2963 .target_sym = wip_nav.func_sym_index, 2964 }, 2965 .{ 2966 .source_off = 1 + @backingInt(dwarf.address_size), 2967 .target_sym = wip_nav.func_sym_index, 2968 .target_off = code_size, 2969 }, 2970 }); 2971 try dwarf.debug_rnglists.section.replaceEntry( 2972 wip_nav.unit, 2973 wip_nav.entry, 2974 dwarf, 2975 ([1]u8{DW.RLE.start_end} ++ @as([8 + 8]u8, @splat(0)))[0 .. 1 + @backingInt(dwarf.address_size) + @backingInt(dwarf.address_size)], 2976 ); 2977 } 2978 2979 try dwarf.finishWipNav(pt, nav_index, wip_nav); 2980 } 2981 2982 pub fn finishWipNav( 2983 dwarf: *Dwarf, 2984 pt: Zcu.PerThread, 2985 nav_index: InternPool.Nav.Index, 2986 wip_nav: *WipNav, 2987 ) UpdateError!void { 2988 return dwarf.finishWipNavWriterError(pt, nav_index, wip_nav) catch |err| switch (err) { 2989 error.WriteFailed => error.OutOfMemory, 2990 else => |e| e, 2991 }; 2992 } 2993 fn finishWipNavWriterError( 2994 dwarf: *Dwarf, 2995 pt: Zcu.PerThread, 2996 nav_index: InternPool.Nav.Index, 2997 wip_nav: *WipNav, 2998 ) (UpdateError || Writer.Error)!void { 2999 const zcu = pt.zcu; 3000 const ip = &zcu.intern_pool; 3001 const nav = ip.getNav(nav_index); 3002 log.debug("finishWipNav({f})", .{nav.fqn.fmt(ip)}); 3003 3004 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written()); 3005 try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.written()); 3006 try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written()); 3007 3008 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser()); 3009 } 3010 3011 pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void { 3012 return updateComptimeNavInner(dwarf, pt, nav_index) catch |err| switch (err) { 3013 error.OutOfMemory => error.OutOfMemory, 3014 else => |e| pt.zcu.codegenFail(nav_index, "failed to update dwarf: {s}", .{@errorName(e)}), 3015 }; 3016 } 3017 3018 fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { 3019 const zcu = pt.zcu; 3020 const ip = &zcu.intern_pool; 3021 3022 const nav = ip.getNav(nav_index); 3023 const inst_info = nav.srcInst(ip).resolveFull(ip).?; 3024 const nav_val: Value = .fromInterned(nav.resolved.?.value); 3025 const file = zcu.fileByIndex(inst_info.file); 3026 const decl = file.zir.?.getDeclaration(inst_info.inst); 3027 log.debug("updateComptimeNav({s}:{d}:{d} %{d} = {f})", .{ 3028 file.sub_file_path, 3029 decl.src_line + 1, 3030 decl.src_column + 1, 3031 @backingInt(inst_info.inst), 3032 nav.fqn.fmt(ip), 3033 }); 3034 3035 const is_test = switch (decl.kind) { 3036 .unnamed_test, .@"test", .decltest => true, 3037 .@"comptime", .@"const", .@"var" => false, 3038 }; 3039 if (is_test) { 3040 // This isn't actually a comptime Nav! It's a test, so it'll definitely never be referenced at comptime. 3041 return; 3042 } 3043 3044 const tag: union(enum) { 3045 alias, 3046 @"var", 3047 @"const", 3048 func: Type, 3049 func_alias: InternPool.Nav.Index, 3050 } = switch (ip.indexToKey(nav_val.toIntern())) { 3051 .int_type, 3052 .ptr_type, 3053 .array_type, 3054 .vector_type, 3055 .opt_type, 3056 .error_union_type, 3057 .anyframe_type, 3058 .simple_type, 3059 .tuple_type, 3060 .func_type, 3061 .error_set_type, 3062 .inferred_error_set_type, 3063 .spirv_type, 3064 => .alias, 3065 3066 .struct_type => tag: { 3067 const loaded_struct = ip.loadStructType(nav_val.toIntern()); 3068 if (nav_index.toOptional() == loaded_struct.name_nav) { 3069 // This Nav's entry is populated by the type, not the actual Nav. 3070 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern()); 3071 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser()); 3072 return; 3073 } 3074 break :tag .alias; 3075 }, 3076 .enum_type => tag: { 3077 const loaded_enum = ip.loadEnumType(nav_val.toIntern()); 3078 if (nav_index.toOptional() == loaded_enum.name_nav) { 3079 // This Nav's entry is populated by the type, not the actual Nav. 3080 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern()); 3081 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser()); 3082 return; 3083 } 3084 break :tag .alias; 3085 }, 3086 .union_type => tag: { 3087 const loaded_union = ip.loadUnionType(nav_val.toIntern()); 3088 if (nav_index.toOptional() == loaded_union.name_nav) { 3089 // This Nav's entry is populated by the type, not the actual Nav. 3090 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern()); 3091 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser()); 3092 return; 3093 } 3094 break :tag .alias; 3095 }, 3096 .opaque_type => tag: { 3097 const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern()); 3098 if (nav_index.toOptional() == loaded_opaque.name_nav) { 3099 // This Nav's entry is populated by the type, not the actual Nav. 3100 _ = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), nav_val.toIntern()); 3101 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser()); 3102 return; 3103 } 3104 break :tag .alias; 3105 }, 3106 3107 .undef, 3108 .simple_value, 3109 .int, 3110 .err, 3111 .error_union, 3112 .enum_literal, 3113 .enum_tag, 3114 .float, 3115 .ptr, 3116 .slice, 3117 .opt, 3118 .aggregate, 3119 .un, 3120 .bitpack, 3121 => if (nav.resolved.?.@"const") .@"const" else .@"var", 3122 3123 .@"extern" => unreachable, 3124 3125 .func => |func| tag: { 3126 if (func.owner_nav != nav_index) break :tag .{ .func_alias = func.owner_nav }; 3127 break :tag .{ .func = .fromInterned(func.ty) }; 3128 }, 3129 3130 // memoization, not types 3131 .memoized_call => unreachable, 3132 }; 3133 3134 const unit = try dwarf.getUnit(file.mod.?); 3135 3136 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index); 3137 errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop(); 3138 3139 if (nav_gop.found_existing) { 3140 if (tag == .func) switch (try dwarf.debug_info.declAbbrevCode(unit, nav_gop.value_ptr.*)) { 3141 else => unreachable, 3142 3143 .decl_nullary_func, 3144 .decl_func, 3145 .decl_instance_nullary_func, 3146 .decl_instance_func, 3147 => return, 3148 3149 .null, 3150 .decl_nullary_func_generic, 3151 .decl_func_generic, 3152 .decl_instance_nullary_func_generic, 3153 .decl_instance_func_generic, 3154 => {}, 3155 }; 3156 dwarf.debug_info.section.getUnit(unit).getEntry(nav_gop.value_ptr.*).clear(); 3157 } else { 3158 nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); 3159 } 3160 3161 var wip_nav: WipNav = .{ 3162 .dwarf = dwarf, 3163 .pt = pt, 3164 .unit = unit, 3165 .entry = nav_gop.value_ptr.*, 3166 .any_children = false, 3167 .func = .none, 3168 .func_sym_index = undefined, 3169 .func_high_pc = undefined, 3170 .blocks = undefined, 3171 .cfi = undefined, 3172 .debug_frame = .init(dwarf.gpa), 3173 .debug_info = .init(dwarf.gpa), 3174 .debug_line = .init(dwarf.gpa), 3175 .debug_loclists = .init(dwarf.gpa), 3176 }; 3177 defer wip_nav.deinit(); 3178 const diw = &wip_nav.debug_info.writer; 3179 3180 switch (tag) { 3181 .alias => { 3182 try wip_nav.declCommon(.{ 3183 .decl = .decl_alias, 3184 .decl_specification = .decl_specification_const, 3185 .decl_instance = .decl_instance_alias, 3186 }, &nav, inst_info.file, &decl); 3187 try wip_nav.refType(nav_val.toType()); 3188 }, 3189 .@"var" => { 3190 try wip_nav.declCommon(.{ 3191 .decl = .decl_var, 3192 .decl_specification = .decl_specification_var, 3193 .decl_instance = .decl_instance_var, 3194 }, &nav, inst_info.file, &decl); 3195 try wip_nav.strp(switch (decl.linkage) { 3196 .normal => nav.fqn, 3197 .@"extern", .@"export" => nav.name, 3198 }.toSlice(ip)); 3199 const nav_ty = nav_val.typeOf(zcu); 3200 try wip_nav.refType(nav_ty); 3201 try wip_nav.blockValue(nav_val); 3202 try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse 3203 nav_ty.abiAlignment(zcu).toByteUnits().?); 3204 try diw.writeByte(@intFromBool(decl.linkage != .normal)); 3205 }, 3206 .@"const" => { 3207 const nav_ty = nav_val.typeOf(zcu); 3208 const has_runtime_bits = nav_ty.hasRuntimeBits(zcu); 3209 const has_comptime_state = nav_ty.comptimeOnly(zcu); 3210 try wip_nav.declCommon(if (has_runtime_bits and has_comptime_state) .{ 3211 .decl = .decl_const_runtime_bits_comptime_state, 3212 .decl_specification = .decl_specification_const, 3213 .decl_instance = .decl_instance_const_runtime_bits_comptime_state, 3214 } else if (has_comptime_state) .{ 3215 .decl = .decl_const_comptime_state, 3216 .decl_specification = .decl_specification_const, 3217 .decl_instance = .decl_instance_const_comptime_state, 3218 } else if (has_runtime_bits) .{ 3219 .decl = .decl_const_runtime_bits, 3220 .decl_specification = .decl_specification_const, 3221 .decl_instance = .decl_instance_const_runtime_bits, 3222 } else .{ 3223 .decl = .decl_const, 3224 .decl_specification = .decl_specification_const, 3225 .decl_instance = .decl_instance_const, 3226 }, &nav, inst_info.file, &decl); 3227 try wip_nav.strp(switch (decl.linkage) { 3228 .normal => nav.fqn, 3229 .@"extern", .@"export" => nav.name, 3230 }.toSlice(ip)); 3231 const nav_ty_reloc_index = try wip_nav.refForward(); 3232 try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse 3233 nav_ty.abiAlignment(zcu).toByteUnits().?); 3234 try diw.writeByte(@intFromBool(decl.linkage != .normal)); 3235 if (has_runtime_bits) try wip_nav.blockValue(nav_val); 3236 if (has_comptime_state) try wip_nav.refValue(nav_val); 3237 wip_nav.finishForward(nav_ty_reloc_index); 3238 try wip_nav.abbrevCode(.is_const); 3239 try wip_nav.refType(nav_ty); 3240 }, 3241 .func => |func_ty| { 3242 const func_type = ip.indexToKey(func_ty.toIntern()).func_type; 3243 const is_nullary = !func_type.is_var_args and for (0..func_type.param_types.len) |param_index| { 3244 if (!func_type.paramIsComptime(std.math.cast(u5, param_index) orelse break false)) break false; 3245 } else true; 3246 try wip_nav.declCommon(if (is_nullary) .{ 3247 .decl = .decl_nullary_func_generic, 3248 .decl_specification = .decl_specification_func, 3249 .decl_instance = .decl_instance_nullary_func_generic, 3250 } else .{ 3251 .decl = .decl_func_generic, 3252 .decl_specification = .decl_specification_func, 3253 .decl_instance = .decl_instance_func_generic, 3254 }, &nav, inst_info.file, &decl); 3255 try wip_nav.refType(.fromInterned(func_type.return_type)); 3256 if (!is_nullary) { 3257 for (0..func_type.param_types.len) |param_index| { 3258 if (std.math.cast(u5, param_index)) |small_param_index| 3259 if (func_type.paramIsComptime(small_param_index)) continue; 3260 try wip_nav.abbrevCode(.func_type_param); 3261 try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index])); 3262 } 3263 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args); 3264 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3265 } 3266 }, 3267 .func_alias => |owner_nav| { 3268 try wip_nav.declCommon(.{ 3269 .decl = .decl_alias, 3270 .decl_specification = .decl_specification_const, 3271 .decl_instance = .decl_instance_alias, 3272 }, &nav, inst_info.file, &decl); 3273 try wip_nav.refNav(owner_nav); 3274 }, 3275 } 3276 try dwarf.debug_info.section.replaceEntry(unit, wip_nav.entry, dwarf, wip_nav.debug_info.written()); 3277 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser()); 3278 } 3279 3280 pub fn updateContainerType( 3281 dwarf: *Dwarf, 3282 pt: Zcu.PerThread, 3283 ty: InternPool.Index, 3284 success: bool, 3285 ) !void { 3286 try dwarf.const_pool.updateContainerType(pt, dwarf.constPoolUser(), ty, success); 3287 } 3288 /// Should only be called by the `link.ConstPool` implementation. 3289 pub fn addConst(dwarf: *Dwarf, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void { 3290 addConstInner(dwarf, pt, index, val) catch |err| switch (err) { 3291 error.OutOfMemory => |e| return e, 3292 else => |e| std.debug.panic("DWARF TODO: '{t}' while registering constant\n", .{e}), 3293 }; 3294 } 3295 fn addConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) !void { 3296 const zcu = pt.zcu; 3297 const ip = &zcu.intern_pool; 3298 3299 const unit: Unit.Index, const entry: Entry.Index = switch (ip.indexToKey(val)) { 3300 else => .{ .main, try dwarf.addCommonEntry(.main) }, 3301 .func => |func| try dwarf.getNavEntry(func.owner_nav), 3302 .@"extern" => |@"extern"| try dwarf.getNavEntry(@"extern".owner_nav), 3303 .struct_type, .union_type, .enum_type, .opaque_type => |_, tag| entry: { 3304 const name_nav = switch (tag) { 3305 .struct_type => ip.loadStructType(val).name_nav, 3306 .union_type => ip.loadUnionType(val).name_nav, 3307 .enum_type => ip.loadEnumType(val).name_nav, 3308 .opaque_type => ip.loadOpaqueType(val).name_nav, 3309 else => unreachable, 3310 }; 3311 if (name_nav.unwrap()) |nav| { 3312 break :entry try dwarf.getNavEntry(nav); 3313 } else { 3314 const zir_index = Type.fromInterned(val).typeDeclInstAllowGeneratedTag(zcu).?; 3315 const unit = try dwarf.getUnit(zcu.fileByIndex(zir_index.resolveFile(ip)).mod.?); 3316 break :entry .{ unit, try dwarf.addCommonEntry(unit) }; 3317 } 3318 }, 3319 }; 3320 3321 assert(@backingInt(index) == dwarf.values.items.len); 3322 try dwarf.values.append(dwarf.gpa, .{ unit, entry }); 3323 } 3324 /// Should only be called by the `link.ConstPool` implementation. 3325 /// 3326 /// Emits a "dummy" DIE for the given comptime-only value (which may be a type). For types, this is 3327 /// an opaque type. Otherwise, it is an undefined value of the value's type. 3328 pub fn updateConstIncomplete(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) Allocator.Error!void { 3329 updateConstIncompleteInner(dwarf, pt, debug_const_index, value_index) catch |err| switch (err) { 3330 error.OutOfMemory => |e| return e, 3331 else => |e| std.debug.panic("DWARF TODO: '{t}' while updating incomplete constant\n", .{e}), 3332 }; 3333 } 3334 fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) !void { 3335 const zcu = pt.zcu; 3336 const ip = &zcu.intern_pool; 3337 3338 const val: Value = .fromInterned(value_index); 3339 3340 switch (value_index) { 3341 .generic_poison_type => log.debug("updateValueIncomplete(anytype)", .{}), 3342 else => log.debug("updateValueIncomplete(@as({f}, {f}))", .{ 3343 val.typeOf(zcu).fmt(pt), 3344 val.fmtValue(pt), 3345 }), 3346 } 3347 3348 const unit, const entry = dwarf.values.items[@backingInt(debug_const_index)]; 3349 3350 for ([_]*Section{ 3351 &dwarf.debug_aranges.section, 3352 &dwarf.debug_aranges.section, 3353 &dwarf.debug_info.section, 3354 &dwarf.debug_line.section, 3355 &dwarf.debug_loclists.section, 3356 &dwarf.debug_rnglists.section, 3357 }) |sec| sec.getUnit(unit).getEntry(entry).clear(); 3358 3359 var wip_nav: WipNav = .{ 3360 .dwarf = dwarf, 3361 .pt = pt, 3362 .unit = unit, 3363 .entry = entry, 3364 .any_children = false, 3365 .func = .none, 3366 .func_sym_index = undefined, 3367 .func_high_pc = undefined, 3368 .blocks = undefined, 3369 .cfi = undefined, 3370 .debug_frame = .init(dwarf.gpa), 3371 .debug_info = .init(dwarf.gpa), 3372 .debug_line = .init(dwarf.gpa), 3373 .debug_loclists = .init(dwarf.gpa), 3374 }; 3375 defer wip_nav.deinit(); 3376 3377 switch (ip.indexToKey(value_index)) { 3378 // Container types still need to be valid namespaces. 3379 .struct_type => { 3380 const loaded_struct = ip.loadStructType(value_index); 3381 const root_of_file: ?Zcu.File.Index = if (loaded_struct.zir_index.resolveFull(ip)) |r| f: { 3382 if (r.inst != .main_struct_inst) break :f null; 3383 break :f r.file; 3384 } else null; 3385 if (root_of_file) |file_index| { 3386 assert(loaded_struct.name_nav == .none); 3387 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file_index); 3388 try wip_nav.abbrevCode(.empty_file); 3389 try wip_nav.debug_info.writer.writeUleb128(file_gop.index); 3390 try wip_nav.strp(loaded_struct.fqn.toSlice(ip)); 3391 } else { 3392 try dwarf.emitIncompleteContainerType( 3393 &wip_nav, 3394 loaded_struct.zir_index, 3395 loaded_struct.fqn, 3396 loaded_struct.name_nav, 3397 ); 3398 } 3399 }, 3400 .union_type => { 3401 const loaded_union = ip.loadUnionType(value_index); 3402 try dwarf.emitIncompleteContainerType( 3403 &wip_nav, 3404 loaded_union.zir_index, 3405 loaded_union.fqn, 3406 loaded_union.name_nav, 3407 ); 3408 }, 3409 .enum_type => { 3410 const loaded_enum = ip.loadEnumType(value_index); 3411 if (loaded_enum.zir_index.unwrap()) |zir_index| { 3412 try dwarf.emitIncompleteContainerType( 3413 &wip_nav, 3414 zir_index, 3415 loaded_enum.fqn, 3416 loaded_enum.name_nav, 3417 ); 3418 } else { 3419 try wip_nav.abbrevCode(.generated_empty_struct_type); 3420 try wip_nav.strp(loaded_enum.fqn.toSlice(ip)); 3421 try wip_nav.debug_info.writer.writeByte(@intFromBool(true)); 3422 } 3423 }, 3424 .opaque_type => { 3425 const loaded_opaque = ip.loadOpaqueType(value_index); 3426 try dwarf.emitIncompleteContainerType( 3427 &wip_nav, 3428 loaded_opaque.zir_index, 3429 loaded_opaque.fqn, 3430 loaded_opaque.name_nav, 3431 ); 3432 }, 3433 // Not a container type, so just emit a dummy entry. If `val` happens to be a type, we'll 3434 // emit it as if it were an opaque type so that we can name it. 3435 else => |val_key| switch (val_key.typeOf()) { 3436 .type_type => { 3437 try wip_nav.abbrevCode(.generated_empty_struct_type); 3438 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 3439 try wip_nav.debug_info.writer.writeByte(@intFromBool(true)); 3440 }, 3441 else => |ty| { 3442 try wip_nav.abbrevCode(.undefined_comptime_value); 3443 try wip_nav.refType(.fromInterned(ty)); 3444 }, 3445 }, 3446 } 3447 try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written()); 3448 try dwarf.debug_loclists.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_loclists.written()); 3449 } 3450 fn emitIncompleteContainerType( 3451 dwarf: *Dwarf, 3452 wip_nav: *WipNav, 3453 zir_index: InternPool.TrackedInst.Index, 3454 fqn: InternPool.NullTerminatedString, 3455 name_nav: InternPool.Nav.Index.Optional, 3456 ) !void { 3457 const zcu = wip_nav.pt.zcu; 3458 const ip = &zcu.intern_pool; 3459 const file = zir_index.resolveFile(ip); 3460 if (name_nav.unwrap()) |nav_index| { 3461 const nav = ip.getNav(nav_index); 3462 const decl_inst = nav.srcInst(ip).resolve(ip).?; 3463 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); 3464 try wip_nav.declCommon(.{ 3465 .decl = .decl_namespace_struct, 3466 .decl_specification = .decl_specification_const, 3467 .decl_instance = .decl_instance_namespace_struct, 3468 }, &nav, file, &decl); 3469 try wip_nav.debug_info.writer.writeByte(@intFromBool(true)); 3470 } else { 3471 const diw = &wip_nav.debug_info.writer; 3472 const file_gop = try dwarf.getModInfo(wip_nav.unit).files.getOrPut(dwarf.gpa, file); 3473 try wip_nav.abbrevCode(.empty_struct_type); 3474 try diw.writeUleb128(file_gop.index); 3475 try wip_nav.strp(fqn.toSlice(ip)); 3476 try diw.writeByte(@intFromBool(true)); 3477 } 3478 } 3479 /// Should only be called by the `link.ConstPool` implementation. 3480 /// 3481 /// Emits a DIE for the given comptime-only value (which may be a type). 3482 pub fn updateConst(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) Allocator.Error!void { 3483 updateConstInner(dwarf, pt, debug_const_index, value_index) catch |err| switch (err) { 3484 error.OutOfMemory => |e| return e, 3485 else => |e| std.debug.panic("DWARF TODO: '{t}' while updating constant\n", .{e}), 3486 }; 3487 } 3488 fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) !void { 3489 const zcu = pt.zcu; 3490 const ip = &zcu.intern_pool; 3491 3492 const val: Value = .fromInterned(value_index); 3493 3494 if (val.typeOf(zcu).toIntern() == .type_type and !val.isUndef(zcu)) { 3495 val.toType().assertHasLayout(zcu); 3496 } else { 3497 val.typeOf(zcu).assertHasLayout(zcu); 3498 } 3499 3500 if (value_index == .anyerror_type) return; // handled in `flush` instead 3501 3502 const value_ip_key = ip.indexToKey(value_index); 3503 switch (value_ip_key) { 3504 .func => return, // populated by the Nav instead (`updateComptimeNav` or `initWipNav`) 3505 .@"extern" => return, // populated by the Nav instead (`initWipNav`) 3506 else => {}, 3507 } 3508 3509 switch (value_index) { 3510 .generic_poison_type => log.debug("updateValue(anytype)", .{}), 3511 else => log.debug("updateValue(@as({f}, {f}))", .{ 3512 val.typeOf(zcu).fmt(pt), 3513 val.fmtValue(pt), 3514 }), 3515 } 3516 3517 const unit, const entry = dwarf.values.items[@backingInt(debug_const_index)]; 3518 3519 for ([_]*Section{ 3520 &dwarf.debug_aranges.section, 3521 &dwarf.debug_info.section, 3522 &dwarf.debug_line.section, 3523 &dwarf.debug_loclists.section, 3524 &dwarf.debug_rnglists.section, 3525 }) |sec| sec.getUnit(unit).getEntry(entry).clear(); 3526 3527 var wip_nav: WipNav = .{ 3528 .dwarf = dwarf, 3529 .pt = pt, 3530 .unit = unit, 3531 .entry = entry, 3532 .any_children = false, 3533 .func = .none, 3534 .func_sym_index = undefined, 3535 .func_high_pc = undefined, 3536 .blocks = undefined, 3537 .cfi = undefined, 3538 .debug_frame = .init(dwarf.gpa), 3539 .debug_info = .init(dwarf.gpa), 3540 .debug_line = .init(dwarf.gpa), 3541 .debug_loclists = .init(dwarf.gpa), 3542 }; 3543 defer wip_nav.deinit(); 3544 3545 const diw = &wip_nav.debug_info.writer; 3546 var big_int_space: Value.BigIntSpace = undefined; 3547 switch (value_ip_key) { 3548 .func => unreachable, // handled above 3549 .@"extern" => unreachable, // handled above 3550 .spirv_type => unreachable, 3551 3552 .int_type => |int_type| { 3553 try wip_nav.abbrevCode(.numeric_type); 3554 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 3555 try diw.writeByte(switch (int_type.signedness) { 3556 inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)), 3557 }); 3558 try diw.writeUleb128(int_type.bits); 3559 try diw.writeUleb128(val.toType().abiSize(zcu)); 3560 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?); 3561 }, 3562 .ptr_type => |ptr_type| switch (ptr_type.flags.size) { 3563 .one, .many, .c => { 3564 const ptr_child_type: Type = .fromInterned(ptr_type.child); 3565 try wip_nav.abbrevCode(switch (ptr_type.flags.alignment) { 3566 .none => if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type, 3567 else => if (ptr_type.sentinel == .none) .ptr_aligned_type else .ptr_aligned_sentinel_type, 3568 }); 3569 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 3570 if (ptr_type.sentinel != .none) try wip_nav.blockValue(.fromInterned(ptr_type.sentinel)); 3571 if (ptr_type.flags.alignment.toByteUnits()) |a| try diw.writeUleb128(a); 3572 try diw.writeByte(@backingInt(ptr_type.flags.address_space)); 3573 if (ptr_type.flags.is_const or ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset( 3574 .debug_info, 3575 wip_nav.unit, 3576 wip_nav.entry, 3577 @intCast(diw.end + dwarf.sectionOffsetBytes()), 3578 ) else try wip_nav.refType(ptr_child_type); 3579 if (ptr_type.flags.is_const) { 3580 try wip_nav.abbrevCode(.is_const); 3581 if (ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset( 3582 .debug_info, 3583 wip_nav.unit, 3584 wip_nav.entry, 3585 @intCast(diw.end + dwarf.sectionOffsetBytes()), 3586 ) else try wip_nav.refType(ptr_child_type); 3587 } 3588 if (ptr_type.flags.is_volatile) { 3589 try wip_nav.abbrevCode(.is_volatile); 3590 try wip_nav.refType(ptr_child_type); 3591 } 3592 }, 3593 .slice => { 3594 try wip_nav.abbrevCode(.generated_struct_type); 3595 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 3596 try diw.writeUleb128(val.toType().abiSize(zcu)); 3597 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?); 3598 try wip_nav.abbrevCode(.generated_field); 3599 try wip_nav.strp("ptr"); 3600 const ptr_field_type = val.toType().slicePtrFieldType(zcu); 3601 try wip_nav.refType(ptr_field_type); 3602 try diw.writeUleb128(0); 3603 try wip_nav.abbrevCode(.generated_field); 3604 try wip_nav.strp("len"); 3605 const len_field_type: Type = .usize; 3606 try wip_nav.refType(len_field_type); 3607 try diw.writeUleb128(len_field_type.abiAlignment(zcu).forward(ptr_field_type.abiSize(zcu))); 3608 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3609 }, 3610 }, 3611 .array_type => |array_type| { 3612 const array_child_type: Type = .fromInterned(array_type.child); 3613 try wip_nav.abbrevCode(if (array_type.sentinel == .none) .array_type else .array_sentinel_type); 3614 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 3615 if (array_type.sentinel != .none) try wip_nav.blockValue(.fromInterned(array_type.sentinel)); 3616 try wip_nav.refType(array_child_type); 3617 try wip_nav.abbrevCode(.array_len); 3618 try wip_nav.refType(.usize); 3619 try diw.writeUleb128(array_type.len); 3620 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3621 }, 3622 .vector_type => |vector_type| { 3623 try wip_nav.abbrevCode(.vector_type); 3624 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 3625 try wip_nav.refType(.fromInterned(vector_type.child)); 3626 try wip_nav.abbrevCode(.array_len); 3627 try wip_nav.refType(.usize); 3628 try diw.writeUleb128(vector_type.len); 3629 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3630 }, 3631 .opt_type => |opt_child_type_index| { 3632 const opt_child_type: Type = .fromInterned(opt_child_type_index); 3633 const opt_repr = optRepr(opt_child_type, zcu); 3634 try wip_nav.abbrevCode(.generated_union_type); 3635 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 3636 try diw.writeUleb128(val.toType().abiSize(zcu)); 3637 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?); 3638 switch (opt_repr) { 3639 .opv_null => { 3640 try wip_nav.abbrevCode(.generated_field); 3641 try wip_nav.strp("null"); 3642 try wip_nav.refType(.null); 3643 try diw.writeUleb128(0); 3644 }, 3645 .unpacked, .error_set, .pointer => { 3646 try wip_nav.abbrevCode(.tagged_union); 3647 try wip_nav.infoSectionOffset( 3648 .debug_info, 3649 wip_nav.unit, 3650 wip_nav.entry, 3651 @intCast(diw.end + dwarf.sectionOffsetBytes()), 3652 ); 3653 { 3654 try wip_nav.abbrevCode(.generated_field); 3655 try wip_nav.strp("has_value"); 3656 switch (opt_repr) { 3657 .opv_null => unreachable, 3658 .unpacked => { 3659 try wip_nav.refType(.bool); 3660 try diw.writeUleb128(if (opt_child_type.hasRuntimeBits(zcu)) 3661 opt_child_type.abiSize(zcu) 3662 else 3663 0); 3664 }, 3665 .error_set => { 3666 try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{ 3667 .signedness = .unsigned, 3668 .bits = zcu.errorSetBits(), 3669 } }))); 3670 try diw.writeUleb128(0); 3671 }, 3672 .pointer => { 3673 try wip_nav.refType(.usize); 3674 try diw.writeUleb128(0); 3675 }, 3676 } 3677 3678 try wip_nav.abbrevCode(.tagged_union_field); 3679 try diw.writeUleb128(DW.FORM.udata); 3680 try diw.writeUleb128(0); 3681 { 3682 try wip_nav.abbrevCode(.generated_field); 3683 try wip_nav.strp("null"); 3684 try wip_nav.refType(.null); 3685 try diw.writeUleb128(0); 3686 } 3687 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3688 3689 try wip_nav.abbrevCode(.tagged_union_default_field); 3690 { 3691 try wip_nav.abbrevCode(.generated_field); 3692 try wip_nav.strp("?"); 3693 try wip_nav.refType(opt_child_type); 3694 try diw.writeUleb128(0); 3695 } 3696 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3697 } 3698 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3699 }, 3700 } 3701 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3702 }, 3703 .anyframe_type => unreachable, 3704 .error_union_type => |error_union_type| { 3705 const error_union_error_set_type: Type = .fromInterned(error_union_type.error_set_type); 3706 const error_union_payload_type: Type = .fromInterned(error_union_type.payload_type); 3707 const error_union_error_set_offset, const error_union_payload_offset = switch (error_union_type.payload_type) { 3708 .generic_poison_type => .{ 0, 0 }, 3709 else => .{ 3710 codegen.errUnionErrorOffset(error_union_payload_type, zcu), 3711 codegen.errUnionPayloadOffset(error_union_payload_type, zcu), 3712 }, 3713 }; 3714 3715 try wip_nav.abbrevCode(.generated_union_type); 3716 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 3717 if (error_union_type.error_set_type != .generic_poison_type and 3718 error_union_type.payload_type != .generic_poison_type) 3719 { 3720 try diw.writeUleb128(val.toType().abiSize(zcu)); 3721 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?); 3722 } else { 3723 try diw.writeUleb128(0); 3724 try diw.writeUleb128(1); 3725 } 3726 { 3727 try wip_nav.abbrevCode(.tagged_union); 3728 try wip_nav.infoSectionOffset( 3729 .debug_info, 3730 wip_nav.unit, 3731 wip_nav.entry, 3732 @intCast(diw.end + dwarf.sectionOffsetBytes()), 3733 ); 3734 { 3735 try wip_nav.abbrevCode(.generated_field); 3736 try wip_nav.strp("is_error"); 3737 try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{ 3738 .signedness = .unsigned, 3739 .bits = zcu.errorSetBits(), 3740 } }))); 3741 try diw.writeUleb128(error_union_error_set_offset); 3742 3743 try wip_nav.abbrevCode(.tagged_union_field); 3744 try diw.writeUleb128(DW.FORM.udata); 3745 try diw.writeUleb128(0); 3746 { 3747 try wip_nav.abbrevCode(.generated_field); 3748 try wip_nav.strp("value"); 3749 try wip_nav.refType(error_union_payload_type); 3750 try diw.writeUleb128(error_union_payload_offset); 3751 } 3752 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3753 3754 try wip_nav.abbrevCode(.tagged_union_default_field); 3755 { 3756 try wip_nav.abbrevCode(.generated_field); 3757 try wip_nav.strp("error"); 3758 try wip_nav.refType(error_union_error_set_type); 3759 try diw.writeUleb128(error_union_error_set_offset); 3760 } 3761 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3762 } 3763 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3764 } 3765 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3766 }, 3767 .simple_type => |simple_type| switch (simple_type) { 3768 .f16, 3769 .f32, 3770 .f64, 3771 .f80, 3772 .f128, 3773 .usize, 3774 .isize, 3775 .c_char, 3776 .c_short, 3777 .c_ushort, 3778 .c_int, 3779 .c_uint, 3780 .c_long, 3781 .c_ulong, 3782 .c_longlong, 3783 .c_ulonglong, 3784 .c_longdouble, 3785 .bool, 3786 => { 3787 try wip_nav.abbrevCode(.numeric_type); 3788 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 3789 try diw.writeByte(if (value_index == .bool_type) 3790 DW.ATE.boolean 3791 else if (val.toType().isRuntimeFloat()) 3792 DW.ATE.float 3793 else if (val.toType().isSignedInt(zcu)) 3794 DW.ATE.signed 3795 else if (val.toType().isUnsignedInt(zcu)) 3796 DW.ATE.unsigned 3797 else 3798 unreachable); 3799 try diw.writeUleb128(val.toType().bitSize(zcu)); 3800 try diw.writeUleb128(val.toType().abiSize(zcu)); 3801 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?); 3802 }, 3803 .generic_poison => { 3804 try wip_nav.abbrevCode(.void_type); 3805 try wip_nav.strp("anytype"); 3806 }, 3807 .anyopaque, 3808 .void, 3809 .type, 3810 .comptime_int, 3811 .comptime_float, 3812 .noreturn, 3813 .null, 3814 .undefined, 3815 .enum_literal, 3816 => { 3817 try wip_nav.abbrevCode(.void_type); 3818 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 3819 }, 3820 .anyerror => unreachable, // already did early return above 3821 .adhoc_inferred_error_set => unreachable, 3822 }, 3823 .tuple_type => |tuple_type| if (tuple_type.types.len == 0) { 3824 try wip_nav.abbrevCode(.generated_empty_struct_type); 3825 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 3826 try diw.writeByte(@intFromBool(false)); 3827 } else { 3828 try wip_nav.abbrevCode(.generated_struct_type); 3829 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 3830 try diw.writeUleb128(val.toType().abiSize(zcu)); 3831 try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?); 3832 var field_byte_offset: u64 = 0; 3833 for (0..tuple_type.types.len) |field_index| { 3834 const comptime_value = tuple_type.values.get(ip)[field_index]; 3835 const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]); 3836 const has_runtime_bits, const has_comptime_state = switch (comptime_value) { 3837 .none => .{ false, false }, 3838 else => .{ field_type.hasRuntimeBits(zcu), field_type.comptimeOnly(zcu) }, 3839 }; 3840 try wip_nav.abbrevCode(if (has_comptime_state) 3841 .field_comptime_comptime_state 3842 else if (has_runtime_bits) 3843 .field_comptime_runtime_bits 3844 else if (comptime_value != .none) 3845 .field_comptime 3846 else 3847 .field); 3848 { 3849 var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined; 3850 const field_name = std.mem.print(&field_name_buf, "{d}", .{field_index}) catch unreachable; 3851 try wip_nav.strp(field_name); 3852 } 3853 try wip_nav.refType(field_type); 3854 if (comptime_value == .none) { 3855 const field_align = field_type.abiAlignment(zcu); 3856 field_byte_offset = field_align.forward(field_byte_offset); 3857 try diw.writeUleb128(field_byte_offset); 3858 try diw.writeUleb128(field_type.abiAlignment(zcu).toByteUnits().?); 3859 field_byte_offset += field_type.abiSize(zcu); 3860 } 3861 if (has_comptime_state) 3862 try wip_nav.refValue(.fromInterned(comptime_value)) 3863 else if (has_runtime_bits) 3864 try wip_nav.blockValue(.fromInterned(comptime_value)); 3865 } 3866 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3867 }, 3868 .struct_type => { 3869 const loaded_struct = ip.loadStructType(value_index); 3870 const ty = val.toType(); 3871 const file = loaded_struct.zir_index.resolveFile(ip); 3872 switch (loaded_struct.layout) { 3873 .auto, .@"extern" => { 3874 const struct_is_file: bool = if (loaded_struct.zir_index.resolve(ip)) |inst| f: { 3875 break :f inst == .main_struct_inst; 3876 } else false; 3877 if (loaded_struct.name_nav.unwrap()) |nav_index| { 3878 assert(!struct_is_file); 3879 const nav = ip.getNav(nav_index); 3880 const decl_inst = nav.srcInst(ip).resolve(ip).?; 3881 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); 3882 try wip_nav.declCommon(if (loaded_struct.field_types.len == 0) .{ 3883 .decl = .decl_namespace_struct, 3884 .decl_specification = .decl_specification_const, 3885 .decl_instance = .decl_instance_namespace_struct, 3886 } else .{ 3887 .decl = .decl_struct, 3888 .decl_specification = .decl_specification_const, 3889 .decl_instance = .decl_instance_struct, 3890 }, &nav, file, &decl); 3891 } else { 3892 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file); 3893 try wip_nav.abbrevCode(switch (loaded_struct.field_types.len) { 3894 0 => if (struct_is_file) .empty_file else .empty_struct_type, 3895 else => if (struct_is_file) .file else .struct_type, 3896 }); 3897 try diw.writeUleb128(file_gop.index); 3898 try wip_nav.strp(loaded_struct.fqn.toSlice(ip)); 3899 } 3900 if (loaded_struct.field_types.len == 0) { 3901 if (!struct_is_file) try diw.writeByte(@intFromBool(false)); 3902 } else { 3903 try diw.writeUleb128(ty.abiSize(zcu)); 3904 try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?); 3905 for (0..loaded_struct.field_types.len) |field_index| { 3906 const is_comptime = loaded_struct.field_is_comptime_bits.get(ip, field_index); 3907 // TODO: we currently don't emit information about default values for 3908 // non-`comptime` fields, because these default values are resolved at a 3909 // separate time in the compiler frontend. To emit this information, the 3910 // frontend needs to tell us when the default values are available: like 3911 // how `Zcu.PerThread.ensureTypeLayoutUpToDate` enqueues a link task to 3912 // indicate completion of the type's layout, a task should be enqueued 3913 // by `Zcu.PerThread.ensureStructDefaultsUpToDate`, and upon receiving 3914 // it we should patch the correct default field values in. 3915 const field_init: InternPool.Index = if (is_comptime) loaded_struct.field_defaults.getOrNone(ip, field_index) else .none; 3916 assert(!(is_comptime and field_init == .none)); 3917 const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); 3918 const has_runtime_bits, const has_comptime_state = switch (field_init) { 3919 .none => .{ false, false }, 3920 else => .{ 3921 field_type.hasRuntimeBits(zcu), 3922 field_type.comptimeOnly(zcu), 3923 }, 3924 }; 3925 try wip_nav.abbrevCode(if (is_comptime) 3926 if (has_comptime_state) 3927 .field_comptime_comptime_state 3928 else if (has_runtime_bits) 3929 .field_comptime_runtime_bits 3930 else 3931 .field_comptime 3932 else if (field_init != .none) 3933 if (has_comptime_state) 3934 .field_default_comptime_state 3935 else if (has_runtime_bits) 3936 .field_default_runtime_bits 3937 else 3938 .field 3939 else 3940 .field); 3941 try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip)); 3942 try wip_nav.refType(field_type); 3943 if (!is_comptime) { 3944 try diw.writeUleb128(loaded_struct.field_offsets.get(ip)[field_index]); 3945 try diw.writeUleb128(loaded_struct.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse 3946 field_type.abiAlignment(zcu).toByteUnits().?); 3947 } 3948 if (has_comptime_state) 3949 try wip_nav.refValue(.fromInterned(field_init)) 3950 else if (has_runtime_bits) 3951 try wip_nav.blockValue(.fromInterned(field_init)); 3952 } 3953 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3954 } 3955 }, 3956 .@"packed" => { 3957 const need_terminator: bool = if (loaded_struct.name_nav.unwrap()) |nav_index| t: { 3958 const nav = ip.getNav(nav_index); 3959 const decl_inst = nav.srcInst(ip).resolve(ip).?; 3960 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); 3961 try wip_nav.declCommon(.{ 3962 .decl = .decl_packed_struct, 3963 .decl_specification = .decl_specification_const, 3964 .decl_instance = .decl_instance_packed_struct, 3965 }, &nav, file, &decl); 3966 break :t true; 3967 } else t: { 3968 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file); 3969 try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type); 3970 try diw.writeUleb128(file_gop.index); 3971 try wip_nav.strp(loaded_struct.fqn.toSlice(ip)); 3972 break :t loaded_struct.field_types.len > 0; 3973 }; 3974 try wip_nav.refType(.fromInterned(loaded_struct.packed_backing_int_type)); 3975 var field_bit_offset: u16 = 0; 3976 for (0..loaded_struct.field_types.len) |field_index| { 3977 try wip_nav.abbrevCode(.packed_field); 3978 try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip)); 3979 const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); 3980 try wip_nav.refType(field_type); 3981 try diw.writeUleb128(field_bit_offset); 3982 field_bit_offset += @intCast(field_type.bitSize(zcu)); 3983 } 3984 if (need_terminator) try diw.writeUleb128(@backingInt(AbbrevCode.null)); 3985 }, 3986 } 3987 }, 3988 .union_type => { 3989 const loaded_union = ip.loadUnionType(value_index); 3990 const file = loaded_union.zir_index.resolveFile(ip); 3991 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type); 3992 switch (loaded_union.layout) { 3993 .auto, .@"extern" => { 3994 const need_terminator: bool = if (loaded_union.name_nav.unwrap()) |nav_index| t: { 3995 const nav = ip.getNav(nav_index); 3996 const decl_inst = nav.srcInst(ip).resolve(ip).?; 3997 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); 3998 try wip_nav.declCommon(.{ 3999 .decl = .decl_union, 4000 .decl_specification = .decl_specification_const, 4001 .decl_instance = .decl_instance_union, 4002 }, &nav, file, &decl); 4003 break :t true; 4004 } else t: { 4005 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file); 4006 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type); 4007 try diw.writeUleb128(file_gop.index); 4008 try wip_nav.strp(loaded_union.fqn.toSlice(ip)); 4009 break :t loaded_union.field_types.len > 0; 4010 }; 4011 const union_layout = Type.getUnionLayout(loaded_union, zcu); 4012 try diw.writeUleb128(union_layout.abi_size); 4013 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?); 4014 if (loaded_union.has_runtime_tag) { 4015 try wip_nav.abbrevCode(.tagged_union); 4016 try wip_nav.infoSectionOffset( 4017 .debug_info, 4018 wip_nav.unit, 4019 wip_nav.entry, 4020 @intCast(diw.end + dwarf.sectionOffsetBytes()), 4021 ); 4022 { 4023 try wip_nav.abbrevCode(.generated_field); 4024 try wip_nav.strp("tag"); 4025 try wip_nav.refType(.fromInterned(loaded_union.enum_tag_type)); 4026 try diw.writeUleb128(union_layout.tagOffset()); 4027 4028 for (0..loaded_union.field_types.len) |field_index| { 4029 try wip_nav.abbrevCode(.tagged_union_field); 4030 try wip_nav.enumConstValue(loaded_tag, field_index); 4031 { 4032 try wip_nav.abbrevCode(.field); 4033 try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip)); 4034 const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]); 4035 try wip_nav.refType(field_type); 4036 try diw.writeUleb128(union_layout.payloadOffset()); 4037 try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse 4038 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?); 4039 } 4040 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4041 } 4042 } 4043 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4044 } else for (0..loaded_union.field_types.len) |field_index| { 4045 try wip_nav.abbrevCode(.field); 4046 try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip)); 4047 const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]); 4048 try wip_nav.refType(field_type); 4049 try diw.writeUleb128(0); 4050 try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse 4051 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?); 4052 } 4053 if (need_terminator) try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4054 }, 4055 .@"packed" => { 4056 const need_terminator: bool = if (loaded_union.name_nav.unwrap()) |nav_index| t: { 4057 const nav = ip.getNav(nav_index); 4058 const decl_inst = nav.srcInst(ip).resolve(ip).?; 4059 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); 4060 try wip_nav.declCommon(.{ 4061 .decl = .decl_packed_union, 4062 .decl_specification = .decl_specification_const, 4063 .decl_instance = .decl_instance_packed_union, 4064 }, &nav, file, &decl); 4065 break :t true; 4066 } else t: { 4067 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file); 4068 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .packed_union_type else .empty_packed_union_type); 4069 try diw.writeUleb128(file_gop.index); 4070 try wip_nav.strp(loaded_union.fqn.toSlice(ip)); 4071 break :t loaded_union.field_types.len > 0; 4072 }; 4073 try wip_nav.refType(.fromInterned(loaded_union.packed_backing_int_type)); 4074 for (0..loaded_union.field_types.len) |field_index| { 4075 try wip_nav.abbrevCode(.packed_field); 4076 try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip)); 4077 try wip_nav.refType(.fromInterned(loaded_union.field_types.get(ip)[field_index])); 4078 try diw.writeUleb128(0); 4079 } 4080 if (need_terminator) try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4081 }, 4082 } 4083 }, 4084 .enum_type => { 4085 const loaded_enum = ip.loadEnumType(value_index); 4086 if (loaded_enum.zir_index.unwrap()) |zir_index| { 4087 assert(loaded_enum.owner_union == .none); 4088 const file = zir_index.resolveFile(ip); 4089 if (loaded_enum.name_nav.unwrap()) |nav_index| { 4090 const nav = ip.getNav(nav_index); 4091 const decl_inst = nav.srcInst(ip).resolve(ip).?; 4092 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); 4093 try wip_nav.declCommon(if (loaded_enum.field_names.len > 0) .{ 4094 .decl = .decl_enum, 4095 .decl_specification = .decl_specification_const, 4096 .decl_instance = .decl_instance_enum, 4097 } else .{ 4098 .decl = .decl_empty_enum, 4099 .decl_specification = .decl_specification_const, 4100 .decl_instance = .decl_instance_empty_enum, 4101 }, &nav, file, &decl); 4102 } else { 4103 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file); 4104 try wip_nav.abbrevCode(if (loaded_enum.field_names.len > 0) .enum_type else .empty_enum_type); 4105 try diw.writeUleb128(file_gop.index); 4106 try wip_nav.strp(loaded_enum.fqn.toSlice(ip)); 4107 } 4108 try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type)); 4109 for (0..loaded_enum.field_names.len) |field_index| { 4110 try wip_nav.abbrevCode(.enum_field); 4111 try wip_nav.enumConstValue(loaded_enum, field_index); 4112 try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip)); 4113 } 4114 if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4115 } else { 4116 assert(loaded_enum.owner_union != .none); 4117 try wip_nav.abbrevCode(if (loaded_enum.field_names.len == 0) .generated_empty_enum_type else .generated_enum_type); 4118 try wip_nav.strp(loaded_enum.fqn.toSlice(ip)); 4119 try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type)); 4120 for (0..loaded_enum.field_names.len) |field_index| { 4121 try wip_nav.abbrevCode(.enum_field); 4122 try wip_nav.enumConstValue(loaded_enum, field_index); 4123 try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip)); 4124 } 4125 if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4126 } 4127 }, 4128 .opaque_type => { 4129 const loaded_opaque = ip.loadOpaqueType(value_index); 4130 const file = loaded_opaque.zir_index.resolveFile(ip); 4131 if (loaded_opaque.name_nav.unwrap()) |nav_index| { 4132 const nav = ip.getNav(nav_index); 4133 const decl_inst = nav.srcInst(ip).resolve(ip).?; 4134 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst); 4135 try wip_nav.declCommon(.{ 4136 .decl = .decl_namespace_struct, 4137 .decl_specification = .decl_specification_const, 4138 .decl_instance = .decl_instance_namespace_struct, 4139 }, &nav, file, &decl); 4140 } else { 4141 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file); 4142 try wip_nav.abbrevCode(.empty_struct_type); 4143 try diw.writeUleb128(file_gop.index); 4144 try wip_nav.strp(loaded_opaque.fqn.toSlice(ip)); 4145 } 4146 try diw.writeByte(@intFromBool(true)); 4147 }, 4148 .func_type => |func_type| { 4149 const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args; 4150 try wip_nav.abbrevCode(if (is_nullary) .nullary_func_type else .func_type); 4151 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 4152 const cc: DW.CC = cc: { 4153 if (zcu.getTarget().cCallingConvention()) |cc| { 4154 if (@as(std.lang.CallingConvention.Tag, cc) == func_type.cc) { 4155 break :cc .normal; 4156 } 4157 } 4158 // For better or worse, we try to match what Clang emits. 4159 break :cc switch (func_type.cc) { 4160 .@"inline" => .nocall, 4161 .async, .auto, .naked => .normal, 4162 .x86_64_sysv => .LLVM_X86_64SysV, 4163 .x86_64_win => .LLVM_Win64, 4164 .x86_64_regcall_v3_sysv => .LLVM_X86RegCall, 4165 .x86_64_regcall_v4_win => .LLVM_X86RegCall, 4166 .x86_64_vectorcall => .LLVM_vectorcall, 4167 .x86_sysv, .x86_win, .x86_mingw => .normal, 4168 .x86_64_preserve_none => .LLVM_PreserveNone, 4169 .x86_stdcall => .BORLAND_stdcall, 4170 .x86_fastcall => .BORLAND_msfastcall, 4171 .x86_thiscall => .BORLAND_thiscall, 4172 .x86_thiscall_mingw => .BORLAND_thiscall, 4173 .x86_regcall_v3 => .LLVM_X86RegCall, 4174 .x86_regcall_v4_win => .LLVM_X86RegCall, 4175 .x86_vectorcall => .LLVM_vectorcall, 4176 4177 .aarch64_aapcs => .normal, 4178 .aarch64_aapcs_darwin => .normal, 4179 .aarch64_aapcs_win => .normal, 4180 .aarch64_vfabi => .LLVM_AAPCS, 4181 .aarch64_vfabi_sve => .LLVM_AAPCS, 4182 .aarch64_preserve_none => .LLVM_PreserveNone, 4183 4184 .arm_aapcs => .LLVM_AAPCS, 4185 .arm_aapcs_vfp => .LLVM_AAPCS_VFP, 4186 4187 .riscv64_lp64_v, 4188 .riscv32_ilp32_v, 4189 => .LLVM_RISCVVectorCall, 4190 4191 .m68k_rtd => .LLVM_M68kRTD, 4192 4193 .sh_renesas => .GNU_renesas_sh, 4194 4195 .amdgcn_kernel => .LLVM_OpenCLKernel, 4196 .nvptx_kernel, 4197 .spirv_kernel, 4198 => .nocall, 4199 4200 .x86_64_interrupt, 4201 .x86_interrupt, 4202 .arm_interrupt, 4203 .mips64_interrupt, 4204 .mips_interrupt, 4205 .riscv64_interrupt, 4206 .riscv32_interrupt, 4207 .sh_interrupt, 4208 .arc_interrupt, 4209 .avr_builtin, 4210 .avr_signal, 4211 .avr_interrupt, 4212 .csky_interrupt, 4213 .m68k_interrupt, 4214 .microblaze_interrupt, 4215 .msp430_interrupt, 4216 => .normal, 4217 4218 else => .nocall, 4219 }; 4220 }; 4221 try diw.writeByte(@backingInt(cc)); 4222 try wip_nav.refType(.fromInterned(func_type.return_type)); 4223 if (!is_nullary) { 4224 for (0..func_type.param_types.len) |param_index| { 4225 try wip_nav.abbrevCode(.func_type_param); 4226 try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index])); 4227 } 4228 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args); 4229 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4230 } 4231 }, 4232 .error_set_type => |error_set_type| { 4233 try wip_nav.abbrevCode(if (error_set_type.names.len == 0) .generated_empty_enum_type else .generated_enum_type); 4234 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 4235 try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{ 4236 .signedness = .unsigned, 4237 .bits = zcu.errorSetBits(), 4238 } }))); 4239 for (0..error_set_type.names.len) |field_index| { 4240 const field_name = error_set_type.names.get(ip)[field_index]; 4241 try wip_nav.abbrevCode(.enum_field); 4242 try diw.writeUleb128(DW.FORM.udata); 4243 try diw.writeUleb128(ip.getErrorValueIfExists(field_name).?); 4244 try wip_nav.strp(field_name.toSlice(ip)); 4245 } 4246 if (error_set_type.names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4247 }, 4248 .inferred_error_set_type => |func| { 4249 try wip_nav.abbrevCode(.inferred_error_set_type); 4250 try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)}); 4251 try wip_nav.refType(.fromInterned(switch (ip.funcIesResolvedUnordered(func)) { 4252 .none => .anyerror_type, 4253 else => |ies| ies, 4254 })); 4255 }, 4256 4257 .undef => |ty| { 4258 try wip_nav.abbrevCode(.undefined_comptime_value); 4259 try wip_nav.refType(.fromInterned(ty)); 4260 }, 4261 .simple_value => |simple_value| switch (simple_value) { 4262 .void => unreachable, // opv state 4263 .true, .false => unreachable, // runtime bits 4264 .@"unreachable" => unreachable, // not a value 4265 .null => { 4266 // TODO: proper representation for this 4267 try wip_nav.abbrevCode(.undefined_comptime_value); 4268 try wip_nav.refType(.null); 4269 }, 4270 }, 4271 .int => |int| { 4272 try wip_nav.abbrevCode(.comptime_value); 4273 try wip_nav.refType(.fromInterned(int.ty)); 4274 try wip_nav.bigIntConstValue(.fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu)); 4275 }, 4276 .bitpack => |bitpack| { 4277 const backing_int_val: Value = .fromInterned(bitpack.backing_int_val); 4278 try wip_nav.abbrevCode(.comptime_value); 4279 try wip_nav.refType(.fromInterned(bitpack.ty)); 4280 try wip_nav.bigIntConstValue(backing_int_val.typeOf(zcu), backing_int_val.toBigInt(&big_int_space, zcu)); 4281 }, 4282 .err => |err| { 4283 try wip_nav.abbrevCode(.comptime_value); 4284 try wip_nav.refType(.fromInterned(err.ty)); 4285 try diw.writeUleb128(DW.FORM.udata); 4286 try diw.writeUleb128(try pt.getErrorValue(err.name)); 4287 }, 4288 .error_union => |error_union| { 4289 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value); 4290 try wip_nav.refType(.fromInterned(error_union.ty)); 4291 var err_buf: [4]u8 = undefined; 4292 const err_bytes = err_buf[0..@divCeil(zcu.errorSetBits(), 8)]; 4293 dwarf.writeInt(err_bytes, switch (error_union.val) { 4294 .err_name => |err_name| try pt.getErrorValue(err_name), 4295 .payload => 0, 4296 }); 4297 { 4298 try wip_nav.abbrevCode(.comptime_value_field_runtime_bits); 4299 try wip_nav.strp("is_error"); 4300 try diw.writeUleb128(err_bytes.len); 4301 try diw.writeAll(err_bytes); 4302 } 4303 payload_field: switch (error_union.val) { 4304 .err_name => {}, 4305 .payload => |payload_val| { 4306 const payload_type: Type = .fromInterned(ip.typeOf(payload_val)); 4307 const has_runtime_bits = payload_type.hasRuntimeBits(zcu); 4308 const has_comptime_state = payload_type.comptimeOnly(zcu); 4309 try wip_nav.abbrevCode(if (has_comptime_state) 4310 .comptime_value_field_comptime_state 4311 else if (has_runtime_bits) 4312 .comptime_value_field_runtime_bits 4313 else 4314 break :payload_field); 4315 try wip_nav.strp("value"); 4316 if (has_comptime_state) 4317 try wip_nav.refValue(.fromInterned(payload_val)) 4318 else 4319 try wip_nav.blockValue(.fromInterned(payload_val)); 4320 }, 4321 } 4322 { 4323 try wip_nav.abbrevCode(.comptime_value_field_runtime_bits); 4324 try wip_nav.strp("error"); 4325 try diw.writeUleb128(err_bytes.len); 4326 try diw.writeAll(err_bytes); 4327 } 4328 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4329 }, 4330 .enum_literal => |enum_literal| { 4331 try wip_nav.abbrevCode(.comptime_value); 4332 try wip_nav.refType(.enum_literal); 4333 try diw.writeUleb128(DW.FORM.strp); 4334 try wip_nav.strp(enum_literal.toSlice(ip)); 4335 }, 4336 .enum_tag => |enum_tag| { 4337 const int = ip.indexToKey(enum_tag.int).int; 4338 try wip_nav.abbrevCode(.comptime_value); 4339 try wip_nav.refType(.fromInterned(enum_tag.ty)); 4340 try wip_nav.bigIntConstValue(.fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu)); 4341 }, 4342 .float => |float| { 4343 try wip_nav.abbrevCode(.comptime_value); 4344 try wip_nav.refType(.fromInterned(float.ty)); 4345 switch (float.storage) { 4346 .f16 => |f16_val| { 4347 try diw.writeUleb128(DW.FORM.data2); 4348 try diw.writeInt(u16, @bitCast(f16_val), dwarf.endian); 4349 }, 4350 .f32 => |f32_val| { 4351 try diw.writeUleb128(DW.FORM.data4); 4352 try diw.writeInt(u32, @bitCast(f32_val), dwarf.endian); 4353 }, 4354 .f64 => |f64_val| { 4355 try diw.writeUleb128(DW.FORM.data8); 4356 try diw.writeInt(u64, @bitCast(f64_val), dwarf.endian); 4357 }, 4358 .f80 => |f80_val| { 4359 try diw.writeUleb128(DW.FORM.block); 4360 try diw.writeUleb128(@divExact(80, 8)); 4361 try diw.writeInt(u80, @bitCast(f80_val), dwarf.endian); 4362 }, 4363 .f128 => |f128_val| { 4364 try diw.writeUleb128(DW.FORM.data16); 4365 try diw.writeInt(u128, @bitCast(f128_val), dwarf.endian); 4366 }, 4367 } 4368 }, 4369 .ptr => |ptr| { 4370 const Access = union(enum) { 4371 index: u64, 4372 field: InternPool.NullTerminatedString, 4373 synthetic_field: []const u8, 4374 tuple_index: u32, 4375 }; 4376 var zero_bit_accesses: std.ArrayList(Access) = .empty; 4377 defer zero_bit_accesses.deinit(dwarf.gpa); 4378 location: { 4379 var base_addr = ptr.base_addr; 4380 var byte_offset = ptr.byte_offset; 4381 const base_unit, const base_entry = while (true) { 4382 const base_ptr, const access: Access = base_ptr_access: switch (base_addr) { 4383 .nav => |nav_index| break try dwarf.getNavEntry(nav_index), 4384 .comptime_alloc, .comptime_field => unreachable, 4385 .uav => |uav| { 4386 const uav_ty: Type = .fromInterned(ip.typeOf(uav.val)); 4387 if (uav_ty.classify(zcu) == .one_possible_value) { 4388 try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0) 4389 .aggregate_comptime_value 4390 else 4391 .comptime_value); 4392 try wip_nav.refType(.fromInterned(ptr.ty)); 4393 try diw.writeUleb128(DW.FORM.udata); 4394 try diw.writeUleb128(ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment.toByteUnits() orelse 4395 uav_ty.abiAlignment(zcu).toByteUnits().?); 4396 break :location; 4397 } else break try wip_nav.getValueEntry(.fromInterned(uav.val)); 4398 }, 4399 .int => { 4400 try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0) 4401 .aggregate_comptime_value 4402 else 4403 .comptime_value); 4404 try wip_nav.refType(.fromInterned(ptr.ty)); 4405 try diw.writeUleb128(DW.FORM.udata); 4406 try diw.writeUleb128(byte_offset); 4407 break :location; 4408 }, 4409 .eu_payload => |eu_ptr| { 4410 const base_ptr = ip.indexToKey(eu_ptr).ptr; 4411 byte_offset += codegen.errUnionPayloadOffset(.fromInterned(ip.indexToKey( 4412 ip.indexToKey(base_ptr.ty).ptr_type.child, 4413 ).error_union_type.payload_type), zcu); 4414 break :base_ptr_access .{ base_ptr, .{ .synthetic_field = "value" } }; 4415 }, 4416 .opt_payload => |opt_ptr| .{ ip.indexToKey(opt_ptr).ptr, .{ .synthetic_field = "?" } }, 4417 .field => |field| { 4418 const base_ptr = ip.indexToKey(field.base).ptr; 4419 const agg_ty: Type = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child); 4420 break :base_ptr_access .{ 4421 base_ptr, 4422 if (agg_ty.isSlice(zcu)) .{ .synthetic_field = switch (field.index) { 4423 Value.slice_ptr_index => "ptr", 4424 Value.slice_len_index => "len", 4425 else => unreachable, 4426 } } else if (agg_ty.structFieldName(@intCast(field.index), zcu).unwrap()) |field_name| 4427 .{ .field = field_name } 4428 else 4429 .{ .tuple_index = @intCast(field.index) }, 4430 }; 4431 }, 4432 .arr_elem => |arr_elem| .{ 4433 ip.indexToKey(arr_elem.base).ptr, 4434 .{ .index = arr_elem.index }, 4435 }, 4436 }; 4437 base_addr = base_ptr.base_addr; 4438 byte_offset += base_ptr.byte_offset; 4439 if (Type.fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child).hasRuntimeBits(zcu)) 4440 assert(access != .index) 4441 else 4442 try zero_bit_accesses.append(dwarf.gpa, access); 4443 }; 4444 try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0) 4445 .aggregate_location_comptime_value 4446 else 4447 .location_comptime_value); 4448 try wip_nav.refType(.fromInterned(ptr.ty)); 4449 try wip_nav.infoExprLoc(.{ .implicit_pointer = .{ 4450 .unit = base_unit, 4451 .entry = base_entry, 4452 .offset = byte_offset, 4453 } }); 4454 } 4455 if (zero_bit_accesses.items.len > 0) { 4456 for (zero_bit_accesses.items) |access| switch (access) { 4457 .index => |index| { 4458 try wip_nav.abbrevCode(.array_index); 4459 try diw.writeUleb128(index); 4460 }, 4461 .field => |field| { 4462 try wip_nav.abbrevCode(.access); 4463 try wip_nav.strp(field.toSlice(ip)); 4464 }, 4465 .synthetic_field => |field| { 4466 try wip_nav.abbrevCode(.access); 4467 try wip_nav.strp(field); 4468 }, 4469 .tuple_index => |index| { 4470 try wip_nav.abbrevCode(.access); 4471 var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined; 4472 const field_name = std.mem.print(&field_name_buf, "{d}", .{index}) catch unreachable; 4473 try wip_nav.strp(field_name); 4474 }, 4475 }; 4476 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4477 } 4478 }, 4479 .slice => |slice| { 4480 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value); 4481 try wip_nav.refType(.fromInterned(slice.ty)); 4482 { 4483 try wip_nav.abbrevCode(.comptime_value_field_comptime_state); 4484 try wip_nav.strp("ptr"); 4485 try wip_nav.refValue(.fromInterned(slice.ptr)); 4486 } 4487 { 4488 try wip_nav.abbrevCode(.comptime_value_field_runtime_bits); 4489 try wip_nav.strp("len"); 4490 try wip_nav.blockValue(.fromInterned(slice.len)); 4491 } 4492 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4493 }, 4494 .opt => |opt| { 4495 const opt_child_type: Type = .fromInterned(ip.indexToKey(opt.ty).opt_type); 4496 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value); 4497 try wip_nav.refType(.fromInterned(opt.ty)); 4498 { 4499 try wip_nav.abbrevCode(.comptime_value_field_runtime_bits); 4500 try wip_nav.strp("has_value"); 4501 switch (optRepr(opt_child_type, zcu)) { 4502 .opv_null => try diw.writeUleb128(0), 4503 .unpacked => try wip_nav.blockValue(.makeBool(opt.val != .none)), 4504 .error_set, .pointer => try wip_nav.blockValue(.fromInterned(value_index)), 4505 } 4506 } 4507 if (opt.val != .none) child_field: { 4508 const has_runtime_bits = opt_child_type.hasRuntimeBits(zcu); 4509 const has_comptime_state = opt_child_type.comptimeOnly(zcu); 4510 try wip_nav.abbrevCode(if (has_comptime_state) 4511 .comptime_value_field_comptime_state 4512 else if (has_runtime_bits) 4513 .comptime_value_field_runtime_bits 4514 else 4515 break :child_field); 4516 try wip_nav.strp("?"); 4517 if (has_comptime_state) 4518 try wip_nav.refValue(.fromInterned(opt.val)) 4519 else 4520 try wip_nav.blockValue(.fromInterned(opt.val)); 4521 } 4522 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4523 }, 4524 .aggregate => |aggregate| { 4525 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value); 4526 try wip_nav.refType(.fromInterned(aggregate.ty)); 4527 switch (ip.indexToKey(aggregate.ty)) { 4528 .struct_type => { 4529 const loaded_struct_type = ip.loadStructType(aggregate.ty); 4530 assert(loaded_struct_type.layout == .auto); 4531 for (0..loaded_struct_type.field_types.len) |field_index| { 4532 if (loaded_struct_type.field_is_comptime_bits.get(ip, field_index)) continue; 4533 const field_type: Type = .fromInterned(loaded_struct_type.field_types.get(ip)[field_index]); 4534 const has_runtime_bits = field_type.hasRuntimeBits(zcu); 4535 const has_comptime_state = field_type.comptimeOnly(zcu); 4536 try wip_nav.abbrevCode(if (has_comptime_state) 4537 .comptime_value_field_comptime_state 4538 else if (has_runtime_bits) 4539 .comptime_value_field_runtime_bits 4540 else 4541 continue); 4542 try wip_nav.strp(loaded_struct_type.field_names.get(ip)[field_index].toSlice(ip)); 4543 const field_value: Value = .fromInterned(switch (aggregate.storage) { 4544 .bytes => unreachable, 4545 .elems => |elems| elems[field_index], 4546 .repeated_elem => |repeated_elem| repeated_elem, 4547 }); 4548 if (has_comptime_state) 4549 try wip_nav.refValue(field_value) 4550 else 4551 try wip_nav.blockValue(field_value); 4552 } 4553 }, 4554 .tuple_type => |tuple_type| for (0..tuple_type.types.len) |field_index| { 4555 if (tuple_type.values.get(ip)[field_index] != .none) continue; 4556 const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]); 4557 const has_runtime_bits = field_type.hasRuntimeBits(zcu); 4558 const has_comptime_state = field_type.comptimeOnly(zcu); 4559 try wip_nav.abbrevCode(if (has_comptime_state) 4560 .comptime_value_field_comptime_state 4561 else if (has_runtime_bits) 4562 .comptime_value_field_runtime_bits 4563 else 4564 continue); 4565 { 4566 var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined; 4567 const field_name = std.mem.print(&field_name_buf, "{d}", .{field_index}) catch unreachable; 4568 try wip_nav.strp(field_name); 4569 } 4570 const field_value: Value = .fromInterned(switch (aggregate.storage) { 4571 .bytes => unreachable, 4572 .elems => |elems| elems[field_index], 4573 .repeated_elem => |repeated_elem| repeated_elem, 4574 }); 4575 if (has_comptime_state) 4576 try wip_nav.refValue(field_value) 4577 else 4578 try wip_nav.blockValue(field_value); 4579 }, 4580 inline .array_type, .vector_type => |sequence_type| { 4581 const child_type: Type = .fromInterned(sequence_type.child); 4582 const has_runtime_bits = child_type.hasRuntimeBits(zcu); 4583 const has_comptime_state = child_type.comptimeOnly(zcu); 4584 for (switch (aggregate.storage) { 4585 .bytes => unreachable, 4586 .elems => |elems| elems, 4587 .repeated_elem => |*repeated_elem| repeated_elem[0..1], 4588 }) |elem| { 4589 try wip_nav.abbrevCode(if (has_comptime_state) 4590 .comptime_value_elem_comptime_state 4591 else if (has_runtime_bits) 4592 .comptime_value_elem_runtime_bits 4593 else 4594 break); 4595 if (has_comptime_state) 4596 try wip_nav.refValue(.fromInterned(elem)) 4597 else 4598 try wip_nav.blockValue(.fromInterned(elem)); 4599 } 4600 }, 4601 else => unreachable, 4602 } 4603 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4604 }, 4605 .un => |un| { 4606 try wip_nav.abbrevCode(.aggregate_undefined_comptime_value); 4607 try wip_nav.refType(.fromInterned(un.ty)); 4608 { 4609 const loaded_union_type = ip.loadUnionType(un.ty); 4610 assert(loaded_union_type.layout == .auto); 4611 const field_index = zcu.unionTagFieldIndex(loaded_union_type, Value.fromInterned(un.tag)).?; 4612 const field_ty: Type = .fromInterned(loaded_union_type.field_types.get(ip)[field_index]); 4613 const field_name = ip.loadEnumType(loaded_union_type.enum_tag_type).field_names.get(ip)[field_index]; 4614 const has_runtime_bits = field_ty.hasRuntimeBits(zcu); 4615 const has_comptime_state = field_ty.comptimeOnly(zcu); 4616 try wip_nav.abbrevCode(if (has_comptime_state) 4617 .comptime_value_field_comptime_state 4618 else if (has_runtime_bits) 4619 .comptime_value_field_runtime_bits 4620 else 4621 .access); 4622 try wip_nav.strp(field_name.toSlice(ip)); 4623 if (has_comptime_state) 4624 try wip_nav.refValue(.fromInterned(un.val)) 4625 else if (has_runtime_bits) 4626 try wip_nav.blockValue(.fromInterned(un.val)); 4627 } 4628 try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4629 }, 4630 4631 .memoized_call => unreachable, // not a value 4632 } 4633 try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written()); 4634 try dwarf.debug_loclists.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_loclists.written()); 4635 } 4636 4637 fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { unpacked, opv_null, error_set, pointer } { 4638 if (opt_child_type.isNoReturn(zcu)) return .opv_null; 4639 return switch (opt_child_type.toIntern()) { 4640 .anyerror_type => .error_set, 4641 else => switch (zcu.intern_pool.indexToKey(opt_child_type.toIntern())) { 4642 else => .unpacked, 4643 .error_set_type, .inferred_error_set_type => .error_set, 4644 .ptr_type => |ptr_type| if (ptr_type.flags.is_allowzero) .unpacked else .pointer, 4645 }, 4646 }; 4647 } 4648 4649 pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedInst.Index, line: u32) UpdateError!void { 4650 const comp = dwarf.bin_file.comp; 4651 const io = comp.io; 4652 const ip = &zcu.intern_pool; 4653 4654 const inst_info = zir_index.resolveFull(ip).?; 4655 if (inst_info.inst == .main_struct_inst) return; 4656 const file = zcu.fileByIndex(inst_info.file); 4657 4658 var line_buf: [4]u8 = undefined; 4659 std.mem.writeInt(u32, &line_buf, line + 1, dwarf.endian); 4660 4661 const unit = dwarf.debug_info.section.getUnit(dwarf.getUnitIfExists(file.mod.?) orelse return); 4662 const entry = unit.getEntry(dwarf.decls.get(zir_index) orelse return); 4663 try dwarf.getFile().?.writePositionalAll(io, &line_buf, dwarf.debug_info.section.off(dwarf) + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf)); 4664 } 4665 4666 pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void { 4667 _ = dwarf; 4668 _ = nav_index; 4669 } 4670 4671 fn refAbbrevCode( 4672 dwarf: *Dwarf, 4673 abbrev_code: AbbrevCode, 4674 ) (UpdateError || Writer.Error)!@typeInfo(AbbrevCode).@"enum".tag_type { 4675 assert(abbrev_code != .null); 4676 const entry: Entry.Index = @fromBackingInt(@intCast(@backingInt(abbrev_code))); 4677 if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @backingInt(abbrev_code); 4678 var debug_abbrev_aw: Writer.Allocating = .init(dwarf.gpa); 4679 defer debug_abbrev_aw.deinit(); 4680 const daw = &debug_abbrev_aw.writer; 4681 const abbrev = AbbrevCode.abbrevs.get(abbrev_code); 4682 try daw.writeUleb128(@backingInt(abbrev_code)); 4683 try daw.writeUleb128(@backingInt(abbrev.tag)); 4684 try daw.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no); 4685 for (abbrev.attrs) |*attr| inline for (attr) |info| try daw.writeUleb128(@backingInt(info)); 4686 for (0..2) |_| try daw.writeUleb128(0); 4687 try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, entry, dwarf, debug_abbrev_aw.written()); 4688 return @backingInt(abbrev_code); 4689 } 4690 4691 pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) UpdateError!void { 4692 return dwarf.flushWriterError(pt) catch |err| switch (err) { 4693 error.WriteFailed => error.OutOfMemory, 4694 else => |e| e, 4695 }; 4696 } 4697 fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (UpdateError || Writer.Error)!void { 4698 const zcu = pt.zcu; 4699 const ip = &zcu.intern_pool; 4700 const comp = dwarf.bin_file.comp; 4701 const io = comp.io; 4702 4703 // Update `anyerror` based on the finished global error set. 4704 { 4705 const index = try dwarf.const_pool.get(pt, dwarf.constPoolUser(), .anyerror_type); 4706 const unit, const entry = dwarf.values.items[@backingInt(index)]; 4707 var wip_nav: WipNav = .{ 4708 .dwarf = dwarf, 4709 .pt = pt, 4710 .unit = unit, 4711 .entry = entry, 4712 .any_children = false, 4713 .func = .none, 4714 .func_sym_index = undefined, 4715 .func_high_pc = undefined, 4716 .blocks = undefined, 4717 .cfi = undefined, 4718 .debug_frame = .init(dwarf.gpa), 4719 .debug_info = .init(dwarf.gpa), 4720 .debug_line = .init(dwarf.gpa), 4721 .debug_loclists = .init(dwarf.gpa), 4722 }; 4723 defer wip_nav.deinit(); 4724 const diw = &wip_nav.debug_info.writer; 4725 const global_error_set_names = ip.global_error_set.getNamesFromMainThread(); 4726 try wip_nav.abbrevCode(if (global_error_set_names.len == 0) .generated_empty_enum_type else .generated_enum_type); 4727 try wip_nav.strp("anyerror"); 4728 try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{ 4729 .signedness = .unsigned, 4730 .bits = zcu.errorSetBits(), 4731 } }))); 4732 for (global_error_set_names, 1..) |name, value| { 4733 try wip_nav.abbrevCode(.enum_field); 4734 try diw.writeUleb128(DW.FORM.udata); 4735 try diw.writeUleb128(value); 4736 try wip_nav.strp(name.toSlice(ip)); 4737 } 4738 if (global_error_set_names.len > 0) try diw.writeUleb128(@backingInt(AbbrevCode.null)); 4739 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written()); 4740 try dwarf.const_pool.flushPending(pt, dwarf.constPoolUser()); 4741 } 4742 4743 for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| { 4744 const root_dir_path = try mod.root.toAbsolute(&zcu.comp.dirs, dwarf.gpa); 4745 defer dwarf.gpa.free(root_dir_path); 4746 mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path); 4747 } 4748 4749 var header_aw: Writer.Allocating = .init(dwarf.gpa); 4750 defer header_aw.deinit(); 4751 const hw = &header_aw.writer; 4752 if (dwarf.debug_aranges.section.dirty) { 4753 for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| { 4754 const unit: Unit.Index = @fromBackingInt(@intCast(unit_index)); 4755 unit_ptr.clear(); 4756 try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 1); 4757 header_aw.clearRetainingCapacity(); 4758 try header_aw.ensureTotalCapacity(unit_ptr.header_len); 4759 const unit_len = (if (unit_ptr.next.unwrap()) |next_unit| 4760 dwarf.debug_aranges.section.getUnit(next_unit).off 4761 else 4762 dwarf.debug_aranges.section.len) - unit_ptr.off - dwarf.unitLengthBytes(); 4763 switch (dwarf.format) { 4764 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable, 4765 .@"64" => { 4766 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable; 4767 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable; 4768 }, 4769 } 4770 hw.writeInt(u16, 2, dwarf.endian) catch unreachable; 4771 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ 4772 .source_off = @intCast(hw.end), 4773 .target_sec = .debug_info, 4774 .target_unit = unit, 4775 }); 4776 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; 4777 hw.writeByte(@backingInt(dwarf.address_size)) catch unreachable; 4778 hw.writeByte(0) catch unreachable; 4779 hw.splatByteAll(0, unit_ptr.header_len - hw.end) catch unreachable; 4780 try unit_ptr.replaceHeader(&dwarf.debug_aranges.section, dwarf, header_aw.written()); 4781 try unit_ptr.writeTrailer(&dwarf.debug_aranges.section, dwarf); 4782 } 4783 dwarf.debug_aranges.section.dirty = false; 4784 } 4785 if (dwarf.debug_frame.section.dirty) { 4786 const target = &dwarf.bin_file.comp.root_mod.resolved_target.result; 4787 switch (dwarf.debug_frame.header.format) { 4788 .none => {}, 4789 .debug_frame => unreachable, 4790 .eh_frame => switch (target.cpu.arch) { 4791 .x86_64 => { 4792 dev.checkAny(&.{ .llvm_backend, .x86_64_backend }); 4793 const Register = @import("../codegen/x86_64/bits.zig").Register; 4794 for (dwarf.debug_frame.section.units.items) |*unit| { 4795 header_aw.clearRetainingCapacity(); 4796 try header_aw.ensureTotalCapacity(unit.header_len); 4797 const unit_len = unit.header_len - dwarf.unitLengthBytes(); 4798 switch (dwarf.format) { 4799 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable, 4800 .@"64" => { 4801 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable; 4802 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable; 4803 }, 4804 } 4805 hw.splatByteAll(0, 4) catch unreachable; 4806 hw.writeByte(1) catch unreachable; 4807 hw.writeAll("zR\x00") catch unreachable; 4808 hw.writeUleb128(dwarf.debug_frame.header.code_alignment_factor) catch unreachable; 4809 hw.writeSleb128(dwarf.debug_frame.header.data_alignment_factor) catch unreachable; 4810 hw.writeUleb128(dwarf.debug_frame.header.return_address_register) catch unreachable; 4811 hw.writeUleb128(1) catch unreachable; 4812 hw.writeByte(@bitCast(@as(DW.EH.PE, .{ .type = .sdata4, .rel = .pcrel }))) catch unreachable; 4813 hw.writeByte(DW.CFA.def_cfa_sf) catch unreachable; 4814 hw.writeUleb128(Register.rsp.dwarfNum()) catch unreachable; 4815 hw.writeSleb128(-1) catch unreachable; 4816 hw.writeByte(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum()) catch unreachable; 4817 hw.writeUleb128(1) catch unreachable; 4818 hw.splatByteAll(DW.CFA.nop, unit.header_len - hw.end) catch unreachable; 4819 try unit.replaceHeader(&dwarf.debug_frame.section, dwarf, header_aw.written()); 4820 try unit.writeTrailer(&dwarf.debug_frame.section, dwarf); 4821 } 4822 }, 4823 else => unreachable, 4824 }, 4825 } 4826 dwarf.debug_frame.section.dirty = false; 4827 } 4828 if (dwarf.debug_info.section.dirty) { 4829 for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| { 4830 const unit: Unit.Index = @fromBackingInt(@intCast(unit_index)); 4831 unit_ptr.clear(); 4832 try unit_ptr.cross_unit_relocs.ensureTotalCapacity(dwarf.gpa, 1); 4833 try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 7); 4834 header_aw.clearRetainingCapacity(); 4835 try header_aw.ensureTotalCapacity(unit_ptr.header_len); 4836 const unit_len = (if (unit_ptr.next.unwrap()) |next_unit| 4837 dwarf.debug_info.section.getUnit(next_unit).off 4838 else 4839 dwarf.debug_info.section.len) - unit_ptr.off - dwarf.unitLengthBytes(); 4840 switch (dwarf.format) { 4841 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable, 4842 .@"64" => { 4843 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable; 4844 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable; 4845 }, 4846 } 4847 hw.writeInt(u16, 5, dwarf.endian) catch unreachable; 4848 hw.writeByte(DW.UT.compile) catch unreachable; 4849 hw.writeByte(@backingInt(dwarf.address_size)) catch unreachable; 4850 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ 4851 .source_off = @intCast(hw.end), 4852 .target_sec = .debug_abbrev, 4853 .target_unit = DebugAbbrev.unit, 4854 }); 4855 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; 4856 const compile_unit_off: u32 = @intCast(hw.end); 4857 hw.writeUleb128(try dwarf.refAbbrevCode(.compile_unit)) catch unreachable; 4858 hw.writeByte(DW.LANG.Zig) catch unreachable; 4859 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ 4860 .source_off = @intCast(hw.end), 4861 .target_sec = .debug_line_str, 4862 .target_unit = StringSection.unit, 4863 .target_entry = (try dwarf.debug_line_str.addString(dwarf, "zig " ++ @import("build_options").version)).toOptional(), 4864 }); 4865 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; 4866 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ 4867 .source_off = @intCast(hw.end), 4868 .target_sec = .debug_line_str, 4869 .target_unit = StringSection.unit, 4870 .target_entry = mod_info.root_dir_path.toOptional(), 4871 }); 4872 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; 4873 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ 4874 .source_off = @intCast(hw.end), 4875 .target_sec = .debug_line_str, 4876 .target_unit = StringSection.unit, 4877 .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod.root_src_path)).toOptional(), 4878 }); 4879 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; 4880 unit_ptr.cross_unit_relocs.appendAssumeCapacity(.{ 4881 .source_off = @intCast(hw.end), 4882 .target_unit = .main, 4883 .target_off = compile_unit_off, 4884 }); 4885 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; 4886 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ 4887 .source_off = @intCast(hw.end), 4888 .target_sec = .debug_line, 4889 .target_unit = unit, 4890 }); 4891 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; 4892 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ 4893 .source_off = @intCast(hw.end), 4894 .target_sec = .debug_rnglists, 4895 .target_unit = unit, 4896 .target_off = DebugRngLists.baseOffset(dwarf), 4897 }); 4898 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; 4899 hw.writeUleb128(0) catch unreachable; 4900 hw.writeUleb128(try dwarf.refAbbrevCode(.module)) catch unreachable; 4901 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ 4902 .source_off = @intCast(hw.end), 4903 .target_sec = .debug_str, 4904 .target_unit = StringSection.unit, 4905 .target_entry = (try dwarf.debug_str.addString(dwarf, mod.fully_qualified_name)).toOptional(), 4906 }); 4907 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; 4908 hw.writeUleb128(0) catch unreachable; 4909 try unit_ptr.replaceHeader(&dwarf.debug_info.section, dwarf, header_aw.written()); 4910 try unit_ptr.writeTrailer(&dwarf.debug_info.section, dwarf); 4911 } 4912 dwarf.debug_info.section.dirty = false; 4913 } 4914 if (dwarf.debug_abbrev.section.dirty) { 4915 assert(!dwarf.debug_info.section.dirty); 4916 try dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).writeTrailer(&dwarf.debug_abbrev.section, dwarf); 4917 dwarf.debug_abbrev.section.dirty = false; 4918 } 4919 if (dwarf.debug_str.section.dirty) { 4920 const contents = dwarf.debug_str.contents.items; 4921 try dwarf.debug_str.section.resize(dwarf, contents.len); 4922 try dwarf.getFile().?.writePositionalAll(io, contents, dwarf.debug_str.section.off(dwarf)); 4923 dwarf.debug_str.section.dirty = false; 4924 } 4925 if (dwarf.debug_line.section.dirty) { 4926 for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| try unit.resizeHeader( 4927 &dwarf.debug_line.section, 4928 dwarf, 4929 DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count())), 4930 ); 4931 for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| { 4932 unit.clear(); 4933 try unit.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, mod_info.dirs.count() + 2 * (mod_info.files.count())); 4934 header_aw.clearRetainingCapacity(); 4935 try header_aw.ensureTotalCapacity(unit.header_len); 4936 const unit_len = (if (unit.next.unwrap()) |next_unit| 4937 dwarf.debug_line.section.getUnit(next_unit).off 4938 else 4939 dwarf.debug_line.section.len) - unit.off - dwarf.unitLengthBytes(); 4940 switch (dwarf.format) { 4941 .@"32" => hw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable, 4942 .@"64" => { 4943 hw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable; 4944 hw.writeInt(u64, unit_len, dwarf.endian) catch unreachable; 4945 }, 4946 } 4947 hw.writeInt(u16, 5, dwarf.endian) catch unreachable; 4948 hw.writeByte(@backingInt(dwarf.address_size)) catch unreachable; 4949 hw.writeByte(0) catch unreachable; 4950 switch (dwarf.format) { 4951 .@"32" => hw.writeInt(u32, @intCast(unit.header_len - hw.end - 4), dwarf.endian) catch unreachable, 4952 .@"64" => hw.writeInt(u64, @intCast(unit.header_len - hw.end - 8), dwarf.endian) catch unreachable, 4953 } 4954 const StandardOpcode = DeclValEnum(DW.LNS); 4955 hw.writeAll(&.{ 4956 dwarf.debug_line.header.minimum_instruction_length, 4957 dwarf.debug_line.header.maximum_operations_per_instruction, 4958 @intFromBool(dwarf.debug_line.header.default_is_stmt), 4959 @bitCast(dwarf.debug_line.header.line_base), 4960 dwarf.debug_line.header.line_range, 4961 dwarf.debug_line.header.opcode_base, 4962 }) catch unreachable; 4963 hw.writeAll(std.enums.EnumArray(StandardOpcode, u8).init(.{ 4964 .extended_op = undefined, 4965 .copy = 0, 4966 .advance_pc = 1, 4967 .advance_line = 1, 4968 .set_file = 1, 4969 .set_column = 1, 4970 .negate_stmt = 0, 4971 .set_basic_block = 0, 4972 .const_add_pc = 0, 4973 .fixed_advance_pc = 1, 4974 .set_prologue_end = 0, 4975 .set_epilogue_begin = 0, 4976 .set_isa = 1, 4977 }).values[1..dwarf.debug_line.header.opcode_base]) catch unreachable; 4978 hw.writeByte(1) catch unreachable; 4979 hw.writeUleb128(DW.LNCT.path) catch unreachable; 4980 hw.writeUleb128(DW.FORM.line_strp) catch unreachable; 4981 hw.writeUleb128(mod_info.dirs.count()) catch unreachable; 4982 for (mod_info.dirs.keys()) |dir_unit| { 4983 unit.cross_section_relocs.appendAssumeCapacity(.{ 4984 .source_off = @intCast(hw.end), 4985 .target_sec = .debug_line_str, 4986 .target_unit = StringSection.unit, 4987 .target_entry = dwarf.getModInfo(dir_unit).root_dir_path.toOptional(), 4988 }); 4989 hw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; 4990 } 4991 const dir_index_info = DebugLine.dirIndexInfo(@intCast(mod_info.dirs.count())); 4992 hw.writeByte(3) catch unreachable; 4993 hw.writeUleb128(DW.LNCT.path) catch unreachable; 4994 hw.writeUleb128(DW.FORM.line_strp) catch unreachable; 4995 hw.writeUleb128(DW.LNCT.directory_index) catch unreachable; 4996 hw.writeUleb128(@backingInt(dir_index_info.form)) catch unreachable; 4997 hw.writeUleb128(DW.LNCT.LLVM_source) catch unreachable; 4998 hw.writeUleb128(DW.FORM.line_strp) catch unreachable; 4999 hw.writeUleb128(mod_info.files.count()) catch unreachable; 5000 for (mod_info.files.keys()) |file_index| {