Files
gasm-sdk/asm/elf_dwarf_sections.go
T

120 lines
3.3 KiB
Go

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: BSD-3-Clause
package asm
// dwarfELFSections holds the laid-out DWARF sections ready for inclusion
// in an ELF file.
type dwarfELFSections struct {
abbrevOff, abbrevSize int
infoOff, infoSize int
lineOff, lineSize int
lineStrOff, lineStrSize int
frameOff, frameSize int
// Relocations for .debug_info address references.
infoRelocs []elfDwarfReloc
// Relocations for .debug_line address references.
lineRelocs []elfDwarfReloc
}
type elfDwarfReloc struct {
off uint64
sym int // symbol index in .symtab
addend int64
}
// appendDWARFSections generates and appends DWARF5 debug sections to the ELF
// output. It returns the section offsets/sizes and relocations for the caller
// to emit section headers and relocation records.
//
// symIdx maps function names to their .symtab indices (needed for relocations
// against .text symbols). The map uses objectName format (pkg.name); the
// DWARF code uses bare function names, so we build a reverse lookup.
func appendDWARFSections(out *[]byte, img *Image, srcFile string, symIdx map[string]int, align func(int)) *dwarfELFSections {
// Build a lookup from bare function name to symbol index.
nameToIdx := make(map[string]int, len(symIdx))
for name, idx := range symIdx {
// Strip package prefix: "pkg.name" → "name".
if i := len(name) - 1; i >= 0 {
for j := len(name) - 1; j >= 0; j-- {
if name[j] == '.' {
nameToIdx[name[j+1:]] = idx
break
}
}
}
nameToIdx[name] = idx
}
ds := emitDWARF(img, srcFile)
if ds == nil || len(ds.debugAbbrev) == 0 {
return nil
}
result := &dwarfELFSections{}
// .debug_abbrev
align(1)
result.abbrevOff = len(*out)
result.abbrevSize = len(ds.debugAbbrev)
*out = append(*out, ds.debugAbbrev...)
// .debug_line_str
align(1)
result.lineStrOff = len(*out)
result.lineStrSize = len(ds.debugLineStr)
*out = append(*out, ds.debugLineStr...)
// .debug_line
align(1)
result.lineOff = len(*out)
result.lineSize = len(ds.debugLine)
lineBase := len(*out)
*out = append(*out, ds.debugLine...)
// Patch .debug_line relocations: replace placeholder addresses with
// actual .text offsets via symbol lookup.
for _, dr := range ds.lineRelocs {
if idx, ok := nameToIdx[dr.name]; ok {
result.lineRelocs = append(result.lineRelocs, elfDwarfReloc{
off: uint64(lineBase) + dr.off,
sym: idx,
addend: dr.addend,
})
}
}
// .debug_info
align(1)
result.infoOff = len(*out)
result.infoSize = len(ds.debugInfo)
infoBase := len(*out)
*out = append(*out, ds.debugInfo...)
// .debug_frame
if len(ds.debugFrame) > 0 {
align(1)
result.frameOff = len(*out)
result.frameSize = len(ds.debugFrame)
*out = append(*out, ds.debugFrame...)
}
// Patch .debug_info relocations.
for _, dr := range ds.infoRelocs {
if idx, ok := nameToIdx[dr.name]; ok {
result.infoRelocs = append(result.infoRelocs, elfDwarfReloc{
off: uint64(infoBase) + dr.off,
sym: idx,
addend: dr.addend,
})
}
}
return result
}
// dwarfSectionNames returns the DWARF section names for the string table.
var dwarfSectionNames = []string{
".debug_abbrev", ".debug_info", ".debug_line", ".debug_line_str",
".debug_frame", ".rela.debug_info", ".rela.debug_line",
}