Skip to content

Instantly share code, notes, and snippets.

@grantseltzer
Last active August 10, 2023 15:55
Show Gist options
  • Save grantseltzer/7e30682b215567976298dc8a2cc4d92f to your computer and use it in GitHub Desktop.
Save grantseltzer/7e30682b215567976298dc8a2cc4d92f to your computer and use it in GitHub Desktop.
package main
import (
"debug/dwarf"
"debug/elf"
"fmt"
"io"
"log"
"os"
)
func main() {
elfFile, err := elf.Open(os.Args[1])
if err != nil {
log.Fatal(err)
}
dwarfData, err := elfFile.DWARF()
if err != nil {
log.Fatal(err)
}
entryReader := dwarfData.Reader()
typeReader := dwarfData.Reader()
readingAFunction := false
for {
// Read all entries in sequence
entry, err := entryReader.Next()
if err == io.EOF {
// We've reached the end of DWARF entries
break
}
if entryIsEmpty(entry) {
readingAFunction = false
}
// Check if this entry is a function
if entry.Tag == dwarf.TagSubprogram {
// Go through fields
for _, field := range entry.Field {
if field.Attr == dwarf.AttrName {
fmt.Printf("%s\n", field.Val.(string))
readingAFunction = true
}
}
}
if !(readingAFunction && entry.Tag == dwarf.TagFormalParameter) {
continue
}
var (
name string
typeName string
)
for _, field := range entry.Field {
if field.Attr == dwarf.AttrName {
name = field.Val.(string)
}
if field.Attr == dwarf.AttrType {
typeReader.Seek(field.Val.(dwarf.Offset))
typeEntry, err := typeReader.Next()
if err != nil {
log.Fatal(err)
}
for i := range typeEntry.Field {
if typeEntry.Field[i].Attr == dwarf.AttrName {
typeName = typeEntry.Field[i].Val.(string)
}
}
}
}
fmt.Printf("\t%s %s\n", name, typeName)
}
}
// Can use `Children` field, but there's also always a NULL/empty entry at the end of entry trees.
func entryIsEmpty(e *dwarf.Entry) bool {
return e.Children == false &&
len(e.Field) == 0 &&
e.Offset == 0 &&
e.Tag == dwarf.Tag(0)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment