| // Copyright 2026 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package dwarf_test | |
| import ( | |
| "debug/dwarf" | |
| "debug/elf" | |
| "debug/macho" | |
| "os" | |
| "path/filepath" | |
| "strings" | |
| "testing" | |
| ) | |
| func FuzzReader(f *testing.F) { | |
| if testing.Short() { | |
| f.Skip("Skipping in short mode") | |
| } | |
| dwarfSuffix := func(name string) string { | |
| switch { | |
| // ELF prefixes, see dwarfSuffix in debug/elf.DWARF | |
| case strings.HasPrefix(name, ".debug_"): | |
| return name[7:] | |
| case strings.HasPrefix(name, ".zdebug_"): | |
| return name[8:] | |
| // machO prefixes, see dwarfSuffix in debug/macho.DWARF | |
| case strings.HasPrefix(name, "__debug_"): | |
| return name[8:] | |
| case strings.HasPrefix(name, "__zdebug_"): | |
| return name[9:] | |
| default: | |
| return "" | |
| } | |
| } | |
| testdata, err := os.ReadDir("testdata") | |
| if err != nil { | |
| f.Fatalf("failed to read testdata directory: %s", err) | |
| } | |
| for _, de := range testdata { | |
| if de.IsDir() { | |
| continue | |
| } | |
| var abbrev, info, line []byte | |
| ext := filepath.Ext(de.Name()) | |
| name := filepath.Join("testdata", de.Name()) | |
| switch { | |
| case strings.HasPrefix(ext, ".elf"): | |
| e, err := elf.Open(name) | |
| if err != nil { | |
| f.Fatal(err) | |
| } | |
| for _, s := range e.Sections { | |
| switch dwarfSuffix(s.Name) { | |
| case "abbrev": | |
| abbrev, _ = s.Data() | |
| case "info": | |
| info, _ = s.Data() | |
| case "line": | |
| line, _ = s.Data() | |
| } | |
| } | |
| case strings.HasPrefix(ext, ".macho"): | |
| m, err := macho.Open(name) | |
| if err != nil { | |
| f.Fatal(err) | |
| } | |
| for _, s := range m.Sections { | |
| switch dwarfSuffix(s.Name) { | |
| case "abbrev": | |
| abbrev, _ = s.Data() | |
| case "info": | |
| info, _ = s.Data() | |
| case "line": | |
| line, _ = s.Data() | |
| } | |
| } | |
| default: | |
| continue | |
| } | |
| if len(abbrev) > 0 || len(info) > 0 || len(line) > 0 { | |
| f.Add(abbrev, info, line) | |
| } | |
| } | |
| // A DWARF 4 compile unit with a line program containing a | |
| // DW_LNS_set_file instruction with a file index of math.MaxUint64. | |
| f.Add( | |
| []byte{ | |
| 1, 0x11, 0, | |
| 0x10, 0x17, | |
| 0, 0, | |
| 0, | |
| }, | |
| []byte{ | |
| 0x0c, 0, 0, 0, | |
| 4, 0, | |
| 0, 0, 0, 0, | |
| 8, | |
| 1, | |
| 0, 0, 0, 0, | |
| }, | |
| []byte{ | |
| 0x25, 0, 0, 0, | |
| 4, 0, | |
| 0x14, 0, 0, 0, | |
| 1, 1, 1, 0, 1, 13, | |
| 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, | |
| 0, 0, | |
| 4, | |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1, | |
| }, | |
| ) | |
| f.Fuzz(func(t *testing.T, abbrev, info, line []byte) { | |
| d, err := dwarf.New(abbrev, nil, nil, info, line, nil, nil, nil) | |
| if err != nil { | |
| return | |
| } | |
| r := d.Reader() | |
| for { | |
| e, err := r.Next() | |
| if err != nil || e == nil { | |
| return | |
| } | |
| if e.Tag != dwarf.TagCompileUnit { | |
| continue | |
| } | |
| lr, err := d.LineReader(e) | |
| if err != nil || lr == nil { | |
| continue | |
| } | |
| var lineEntry dwarf.LineEntry | |
| for { | |
| if err := lr.Next(&lineEntry); err != nil { | |
| break | |
| } | |
| } | |
| } | |
| }) | |
| } |