| // 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 |
| } |
| } |
| } |
| }) |
| } |