tl;dr: - Linux debugging works - macOS running works, debugging doesn't.
83 lines
2.1 KiB
Go
83 lines
2.1 KiB
Go
// Command dwarfcu lists the DWARF compile units of Mach-O and ELF files.
|
|
//
|
|
// It reads the compressed DWARF sections the Go linker produces,
|
|
// which some platform tools, like macOS dwarfdump, do not decode.
|
|
// Use it to check that a host program and its plugins carry debug information:
|
|
//
|
|
// go run ./tools/dwarfcu cmd/demo plugins/foo/foo.so
|
|
package main
|
|
|
|
import (
|
|
"debug/dwarf"
|
|
"debug/elf"
|
|
"debug/macho"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// modulePath is this repository's module, whose plugins the tool reports.
|
|
const modulePath = "code.osinet.fr/fgm/go_plugin_demo"
|
|
|
|
func compileUnits(d *dwarf.Data) ([]string, error) {
|
|
var cus []string
|
|
r := d.Reader()
|
|
for {
|
|
e, err := r.Next()
|
|
if err != nil {
|
|
return cus, err
|
|
}
|
|
if e == nil {
|
|
return cus, nil
|
|
}
|
|
if e.Tag == dwarf.TagCompileUnit {
|
|
if name, ok := e.Val(dwarf.AttrName).(string); ok {
|
|
cus = append(cus, name)
|
|
}
|
|
r.SkipChildren()
|
|
}
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
status := 0
|
|
for _, path := range os.Args[1:] {
|
|
d, err := openDWARF(path)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
|
|
status = 1
|
|
continue
|
|
}
|
|
cus, err := compileUnits(d)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "%s: reading DWARF: %v\n", path, err)
|
|
status = 1
|
|
}
|
|
// The shared package only declares a type, so it has no unit of its own:
|
|
// the demo's code is in main and in each plugin.
|
|
// A plugin built by package keeps its import path,
|
|
// while one built from a file list is named plugin/unnamed-<hash>.
|
|
var own []string
|
|
for _, cu := range cus {
|
|
if cu == "main" || strings.HasPrefix(cu, modulePath+"/") || strings.HasPrefix(cu, "plugin/unnamed-") {
|
|
own = append(own, cu)
|
|
}
|
|
}
|
|
fmt.Printf("%s: %d compile units, own: %v\n", path, len(cus), own)
|
|
}
|
|
os.Exit(status)
|
|
}
|
|
|
|
// openDWARF tries Mach-O first, then ELF, so the tool reads macOS and Linux builds alike.
|
|
func openDWARF(path string) (*dwarf.Data, error) {
|
|
if f, err := macho.Open(path); err == nil {
|
|
defer f.Close()
|
|
return f.DWARF()
|
|
}
|
|
f, err := elf.Open(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("neither Mach-O nor ELF: %w", err)
|
|
}
|
|
defer f.Close()
|
|
return f.DWARF()
|
|
}
|