aboutsummaryrefslogtreecommitdiff
path: root/src/debug
diff options
context:
space:
mode:
authorKatie Hockman <katie@golang.org>2020-12-14 10:03:05 -0500
committerKatie Hockman <katie@golang.org>2020-12-14 10:06:13 -0500
commit0345ede87ee12698988973884cfc0fd3d499dffd (patch)
tree7123cff141ee5661208d2f5f437b8f5252ac7f6a /src/debug
parent4651d6b267818b0e0d128a5443289717c4bb8cbc (diff)
parent0a02371b0576964e81c3b40d328db9a3ef3b031b (diff)
downloadgo-0345ede87ee12698988973884cfc0fd3d499dffd.tar.xz
[dev.fuzz] all: merge master into dev.fuzz
Change-Id: I5d8c8329ccc9d747bd81ade6b1cb7cb8ae2e94b2
Diffstat (limited to 'src/debug')
-rw-r--r--src/debug/dwarf/const.go12
-rw-r--r--src/debug/dwarf/dwarf5ranges_test.go36
-rw-r--r--src/debug/dwarf/entry.go255
-rw-r--r--src/debug/dwarf/entry_test.go42
-rw-r--r--src/debug/dwarf/line.go6
-rw-r--r--src/debug/dwarf/line_test.go8
-rw-r--r--src/debug/dwarf/open.go94
-rw-r--r--src/debug/dwarf/testdata/debug_rnglistsbin0 -> 23 bytes
-rw-r--r--src/debug/elf/elf.go223
-rw-r--r--src/debug/elf/file_test.go2
-rw-r--r--src/debug/gosym/pclntab.go95
-rw-r--r--src/debug/gosym/pclntab_test.go8
-rw-r--r--src/debug/pe/file_test.go13
13 files changed, 670 insertions, 124 deletions
diff --git a/src/debug/dwarf/const.go b/src/debug/dwarf/const.go
index b11bf90c37..c60709199b 100644
--- a/src/debug/dwarf/const.go
+++ b/src/debug/dwarf/const.go
@@ -461,3 +461,15 @@ const (
utSplitCompile = 0x05
utSplitType = 0x06
)
+
+// Opcodes for DWARFv5 debug_rnglists section.
+const (
+ rleEndOfList = 0x0
+ rleBaseAddressx = 0x1
+ rleStartxEndx = 0x2
+ rleStartxLength = 0x3
+ rleOffsetPair = 0x4
+ rleBaseAddress = 0x5
+ rleStartEnd = 0x6
+ rleStartLength = 0x7
+)
diff --git a/src/debug/dwarf/dwarf5ranges_test.go b/src/debug/dwarf/dwarf5ranges_test.go
new file mode 100644
index 0000000000..0ff1a55bc9
--- /dev/null
+++ b/src/debug/dwarf/dwarf5ranges_test.go
@@ -0,0 +1,36 @@
+// Copyright 2020 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
+
+import (
+ "encoding/binary"
+ "os"
+ "reflect"
+ "testing"
+)
+
+func TestDwarf5Ranges(t *testing.T) {
+ rngLists, err := os.ReadFile("testdata/debug_rnglists")
+ if err != nil {
+ t.Fatalf("could not read test data: %v", err)
+ }
+
+ d := &Data{}
+ d.order = binary.LittleEndian
+ if err := d.AddSection(".debug_rnglists", rngLists); err != nil {
+ t.Fatal(err)
+ }
+ ret, err := d.dwarf5Ranges(nil, 0x5fbd, 0xc, [][2]uint64{})
+ if err != nil {
+ t.Fatalf("could not read rnglist: %v", err)
+ }
+ t.Logf("%#v", ret)
+
+ tgt := [][2]uint64{{0x0000000000006712, 0x000000000000679f}, {0x00000000000067af}, {0x00000000000067b3}}
+
+ if reflect.DeepEqual(ret, tgt) {
+ t.Errorf("expected %#v got %#x", tgt, ret)
+ }
+}
diff --git a/src/debug/dwarf/entry.go b/src/debug/dwarf/entry.go
index 01f2190db7..bc05d7ef31 100644
--- a/src/debug/dwarf/entry.go
+++ b/src/debug/dwarf/entry.go
@@ -453,38 +453,28 @@ func (b *buf) entry(cu *Entry, atab abbrevTable, ubase Offset, vers int) *Entry
case formAddrx4:
off = uint64(b.uint32())
}
- if len(b.dwarf.addr) == 0 {
+ if b.dwarf.addr == nil {
b.error("DW_FORM_addrx with no .debug_addr section")
}
if b.err != nil {
return nil
}
- addrsize := b.format.addrsize()
- if addrsize == 0 {
- b.error("unknown address size for DW_FORM_addrx")
- }
- off *= uint64(addrsize)
// We have to adjust by the offset of the
// compilation unit. This won't work if the
// program uses Reader.Seek to skip over the
// unit. Not much we can do about that.
+ var addrBase int64
if cu != nil {
- cuOff, ok := cu.Val(AttrAddrBase).(int64)
- if ok {
- off += uint64(cuOff)
- }
- }
-
- if uint64(int(off)) != off {
- b.error("DW_FORM_addrx offset out of range")
+ addrBase, _ = cu.Val(AttrAddrBase).(int64)
}
- b1 := makeBuf(b.dwarf, b.format, "addr", 0, b.dwarf.addr)
- b1.skip(int(off))
- val = b1.addr()
- if b1.err != nil {
- b.err = b1.err
+ var err error
+ val, err = b.dwarf.debugAddr(uint64(addrBase), off)
+ if err != nil {
+ if b.err == nil {
+ b.err = err
+ }
return nil
}
@@ -717,6 +707,7 @@ type Reader struct {
d *Data
err error
unit int
+ lastUnit bool // set if last entry returned by Next is TagCompileUnit/TagPartialUnit
lastChildren bool // .Children of last entry returned by Next
lastSibling Offset // .Val(AttrSibling) of last entry returned by Next
cu *Entry // current compilation unit
@@ -774,13 +765,18 @@ func (r *Reader) Seek(off Offset) {
// maybeNextUnit advances to the next unit if this one is finished.
func (r *Reader) maybeNextUnit() {
for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) {
- r.unit++
- u := &r.d.unit[r.unit]
- r.b = makeBuf(r.d, u, "info", u.off, u.data)
- r.cu = nil
+ r.nextUnit()
}
}
+// nextUnit advances to the next unit.
+func (r *Reader) nextUnit() {
+ r.unit++
+ u := &r.d.unit[r.unit]
+ r.b = makeBuf(r.d, u, "info", u.off, u.data)
+ r.cu = nil
+}
+
// Next reads the next entry from the encoded entry stream.
// It returns nil, nil when it reaches the end of the section.
// It returns an error if the current offset is invalid or the data at the
@@ -799,12 +795,14 @@ func (r *Reader) Next() (*Entry, error) {
r.err = r.b.err
return nil, r.err
}
+ r.lastUnit = false
if e != nil {
r.lastChildren = e.Children
if r.lastChildren {
r.lastSibling, _ = e.Val(AttrSibling).(Offset)
}
if e.Tag == TagCompileUnit || e.Tag == TagPartialUnit {
+ r.lastUnit = true
r.cu = e
}
} else {
@@ -830,6 +828,11 @@ func (r *Reader) SkipChildren() {
return
}
+ if r.lastUnit && r.unit+1 < len(r.d.unit) {
+ r.nextUnit()
+ return
+ }
+
for {
e, err := r.Next()
if err != nil || e == nil || e.Tag == 0 {
@@ -922,53 +925,187 @@ func (d *Data) Ranges(e *Entry) ([][2]uint64, error) {
ret = append(ret, [2]uint64{low, high})
}
- ranges, rangesOK := e.Val(AttrRanges).(int64)
- if rangesOK && d.ranges != nil {
- // The initial base address is the lowpc attribute
- // of the enclosing compilation unit.
- // Although DWARF specifies the lowpc attribute,
- // comments in gdb/dwarf2read.c say that some versions
- // of GCC use the entrypc attribute, so we check that too.
- var cu *Entry
- if e.Tag == TagCompileUnit {
- cu = e
- } else {
- i := d.offsetToUnit(e.Offset)
- if i == -1 {
- return nil, errors.New("no unit for entry")
+ var u *unit
+ if uidx := d.offsetToUnit(e.Offset); uidx >= 0 && uidx < len(d.unit) {
+ u = &d.unit[uidx]
+ }
+
+ if u != nil && u.vers >= 5 && d.rngLists != nil {
+ // DWARF version 5 and later
+ field := e.AttrField(AttrRanges)
+ if field == nil {
+ return ret, nil
+ }
+ switch field.Class {
+ case ClassRangeListPtr:
+ ranges, rangesOK := field.Val.(int64)
+ if !rangesOK {
+ return ret, nil
}
- u := &d.unit[i]
- b := makeBuf(d, u, "info", u.off, u.data)
- cu = b.entry(nil, u.atable, u.base, u.vers)
- if b.err != nil {
- return nil, b.err
+ cu, base, err := d.baseAddressForEntry(e)
+ if err != nil {
+ return nil, err
}
+ return d.dwarf5Ranges(cu, base, ranges, ret)
+
+ case ClassRngList:
+ // TODO: support DW_FORM_rnglistx
+ return ret, nil
+
+ default:
+ return ret, nil
}
+ }
- var base uint64
- if cuEntry, cuEntryOK := cu.Val(AttrEntrypc).(uint64); cuEntryOK {
- base = cuEntry
- } else if cuLow, cuLowOK := cu.Val(AttrLowpc).(uint64); cuLowOK {
- base = cuLow
+ // DWARF version 2 through 4
+ ranges, rangesOK := e.Val(AttrRanges).(int64)
+ if rangesOK && d.ranges != nil {
+ _, base, err := d.baseAddressForEntry(e)
+ if err != nil {
+ return nil, err
}
+ return d.dwarf2Ranges(u, base, ranges, ret)
+ }
- u := &d.unit[d.offsetToUnit(e.Offset)]
- buf := makeBuf(d, u, "ranges", Offset(ranges), d.ranges[ranges:])
- for len(buf.data) > 0 {
- low = buf.addr()
- high = buf.addr()
+ return ret, nil
+}
- if low == 0 && high == 0 {
- break
+// baseAddressForEntry returns the initial base address to be used when
+// looking up the range list of entry e.
+// DWARF specifies that this should be the lowpc attribute of the enclosing
+// compilation unit, however comments in gdb/dwarf2read.c say that some
+// versions of GCC use the entrypc attribute, so we check that too.
+func (d *Data) baseAddressForEntry(e *Entry) (*Entry, uint64, error) {
+ var cu *Entry
+ if e.Tag == TagCompileUnit {
+ cu = e
+ } else {
+ i := d.offsetToUnit(e.Offset)
+ if i == -1 {
+ return nil, 0, errors.New("no unit for entry")
+ }
+ u := &d.unit[i]
+ b := makeBuf(d, u, "info", u.off, u.data)
+ cu = b.entry(nil, u.atable, u.base, u.vers)
+ if b.err != nil {
+ return nil, 0, b.err
+ }
+ }
+
+ if cuEntry, cuEntryOK := cu.Val(AttrEntrypc).(uint64); cuEntryOK {
+ return cu, cuEntry, nil
+ } else if cuLow, cuLowOK := cu.Val(AttrLowpc).(uint64); cuLowOK {
+ return cu, cuLow, nil
+ }
+
+ return cu, 0, nil
+}
+
+func (d *Data) dwarf2Ranges(u *unit, base uint64, ranges int64, ret [][2]uint64) ([][2]uint64, error) {
+ buf := makeBuf(d, u, "ranges", Offset(ranges), d.ranges[ranges:])
+ for len(buf.data) > 0 {
+ low := buf.addr()
+ high := buf.addr()
+
+ if low == 0 && high == 0 {
+ break
+ }
+
+ if low == ^uint64(0)>>uint((8-u.addrsize())*8) {
+ base = high
+ } else {
+ ret = append(ret, [2]uint64{base + low, base + high})
+ }
+ }
+
+ return ret, nil
+}
+
+// dwarf5Ranges interpets a debug_rnglists sequence, see DWARFv5 section
+// 2.17.3 (page 53).
+func (d *Data) dwarf5Ranges(cu *Entry, base uint64, ranges int64, ret [][2]uint64) ([][2]uint64, error) {
+ var addrBase int64
+ if cu != nil {
+ addrBase, _ = cu.Val(AttrAddrBase).(int64)
+ }
+
+ buf := makeBuf(d, d.rngLists, "rnglists", 0, d.rngLists.data)
+ buf.skip(int(ranges))
+ for {
+ opcode := buf.uint8()
+ switch opcode {
+ case rleEndOfList:
+ if buf.err != nil {
+ return nil, buf.err
}
+ return ret, nil
- if low == ^uint64(0)>>uint((8-u.addrsize())*8) {
- base = high
- } else {
- ret = append(ret, [2]uint64{base + low, base + high})
+ case rleBaseAddressx:
+ baseIdx := buf.uint()
+ var err error
+ base, err = d.debugAddr(uint64(addrBase), baseIdx)
+ if err != nil {
+ return nil, err
+ }
+
+ case rleStartxEndx:
+ startIdx := buf.uint()
+ endIdx := buf.uint()
+
+ start, err := d.debugAddr(uint64(addrBase), startIdx)
+ if err != nil {
+ return nil, err
}
+ end, err := d.debugAddr(uint64(addrBase), endIdx)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, [2]uint64{start, end})
+
+ case rleStartxLength:
+ startIdx := buf.uint()
+ len := buf.uint()
+ start, err := d.debugAddr(uint64(addrBase), startIdx)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, [2]uint64{start, start + len})
+
+ case rleOffsetPair:
+ off1 := buf.uint()
+ off2 := buf.uint()
+ ret = append(ret, [2]uint64{base + off1, base + off2})
+
+ case rleBaseAddress:
+ base = buf.addr()
+
+ case rleStartEnd:
+ start := buf.addr()
+ end := buf.addr()
+ ret = append(ret, [2]uint64{start, end})
+
+ case rleStartLength:
+ start := buf.addr()
+ len := buf.uint()
+ ret = append(ret, [2]uint64{start, start + len})
}
}
+}
- return ret, nil
+// debugAddr returns the address at idx in debug_addr
+func (d *Data) debugAddr(addrBase, idx uint64) (uint64, error) {
+ off := idx*uint64(d.addr.addrsize()) + addrBase
+
+ if uint64(int(off)) != off {
+ return 0, errors.New("offset out of range")
+ }
+
+ b := makeBuf(d, d.addr, "addr", 0, d.addr.data)
+ b.skip(int(off))
+ val := b.addr()
+ if b.err != nil {
+ return 0, b.err
+ }
+
+ return val, nil
}
diff --git a/src/debug/dwarf/entry_test.go b/src/debug/dwarf/entry_test.go
index 4c9aad21f3..2e6ee048aa 100644
--- a/src/debug/dwarf/entry_test.go
+++ b/src/debug/dwarf/entry_test.go
@@ -7,6 +7,7 @@ package dwarf_test
import (
. "debug/dwarf"
"encoding/binary"
+ "path/filepath"
"reflect"
"testing"
)
@@ -209,3 +210,44 @@ func Test64Bit(t *testing.T) {
}
}
}
+
+func TestUnitIteration(t *testing.T) {
+ // Iterate over all ELF test files we have and ensure that
+ // we get the same set of compilation units skipping (method 0)
+ // and not skipping (method 1) CU children.
+ files, err := filepath.Glob(filepath.Join("testdata", "*.elf"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, file := range files {
+ t.Run(file, func(t *testing.T) {
+ d := elfData(t, file)
+ var units [2][]interface{}
+ for method := range units {
+ for r := d.Reader(); ; {
+ ent, err := r.Next()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if ent == nil {
+ break
+ }
+ if ent.Tag == TagCompileUnit {
+ units[method] = append(units[method], ent.Val(AttrName))
+ }
+ if method == 0 {
+ if ent.Tag != TagCompileUnit {
+ t.Fatalf("found unexpected tag %v on top level", ent.Tag)
+ }
+ r.SkipChildren()
+ }
+ }
+ }
+ t.Logf("skipping CUs: %v", units[0])
+ t.Logf("not-skipping CUs: %v", units[1])
+ if !reflect.DeepEqual(units[0], units[1]) {
+ t.Fatal("set of CUs differ")
+ }
+ })
+ }
+}
diff --git a/src/debug/dwarf/line.go b/src/debug/dwarf/line.go
index 7692f05552..c4937ca7dd 100644
--- a/src/debug/dwarf/line.go
+++ b/src/debug/dwarf/line.go
@@ -814,7 +814,11 @@ func pathJoin(dirname, filename string) string {
// Drives are the same. Ignore drive on filename.
}
if !(strings.HasSuffix(dirname, "/") || strings.HasSuffix(dirname, `\`)) && dirname != "" {
- dirname += `\`
+ sep := `\`
+ if strings.HasPrefix(dirname, "/") {
+ sep = `/`
+ }
+ dirname += sep
}
return drive + dirname + filename
}
diff --git a/src/debug/dwarf/line_test.go b/src/debug/dwarf/line_test.go
index 1fd9b19b03..b13818e8b5 100644
--- a/src/debug/dwarf/line_test.go
+++ b/src/debug/dwarf/line_test.go
@@ -341,6 +341,14 @@ var joinTests = []joinTest{
{`\\host\share\`, `foo\bar`, `\\host\share\foo\bar`},
{`//host/share/`, `foo/bar`, `//host/share/foo/bar`},
+ // Note: the Go compiler currently emits DWARF line table paths
+ // with '/' instead of '\' (see issues #19784, #36495). These
+ // tests are to cover cases that might come up for Windows Go
+ // binaries.
+ {`c:/workdir/go/src/x`, `y.go`, `c:/workdir/go/src/x/y.go`},
+ {`d:/some/thing/`, `b.go`, `d:/some/thing/b.go`},
+ {`e:\blah\`, `foo.c`, `e:\blah\foo.c`},
+
// The following are "best effort". We shouldn't see relative
// base directories in DWARF, but these test that pathJoin
// doesn't fail miserably if it sees one.
diff --git a/src/debug/dwarf/open.go b/src/debug/dwarf/open.go
index 72ee64d558..617b8c56dd 100644
--- a/src/debug/dwarf/open.go
+++ b/src/debug/dwarf/open.go
@@ -7,7 +7,10 @@
// http://dwarfstd.org/doc/dwarf-2.0.0.pdf
package dwarf
-import "encoding/binary"
+import (
+ "encoding/binary"
+ "errors"
+)
// Data represents the DWARF debugging information
// loaded from an executable file (for example, an ELF or Mach-O executable).
@@ -23,9 +26,10 @@ type Data struct {
str []byte
// New sections added in DWARF 5.
- addr []byte
+ addr *debugAddr
lineStr []byte
strOffsets []byte
+ rngLists *rngLists
// parsed data
abbrevCache map[uint64]abbrevTable
@@ -36,6 +40,23 @@ type Data struct {
unit []unit
}
+// rngLists represents the contents of a debug_rnglists section (DWARFv5).
+type rngLists struct {
+ is64 bool
+ asize uint8
+ data []byte
+ ver uint16
+}
+
+// debugAddr represents the contents of a debug_addr section (DWARFv5).
+type debugAddr struct {
+ is64 bool
+ asize uint8
+ data []byte
+}
+
+var errSegmentSelector = errors.New("non-zero segment_selector size not supported")
+
// New returns a new Data object initialized from the given parameters.
// Rather than calling this function directly, clients should typically use
// the DWARF method of the File type of the appropriate package debug/elf,
@@ -108,14 +129,79 @@ func (d *Data) AddTypes(name string, types []byte) error {
// so forth. This approach is used for new DWARF sections added in
// DWARF 5 and later.
func (d *Data) AddSection(name string, contents []byte) error {
+ var err error
switch name {
case ".debug_addr":
- d.addr = contents
+ d.addr, err = d.parseAddrHeader(contents)
case ".debug_line_str":
d.lineStr = contents
case ".debug_str_offsets":
d.strOffsets = contents
+ case ".debug_rnglists":
+ d.rngLists, err = d.parseRngListsHeader(contents)
}
// Just ignore names that we don't yet support.
- return nil
+ return err
+}
+
+// parseRngListsHeader reads the header of a debug_rnglists section, see
+// DWARFv5 section 7.28 (page 242).
+func (d *Data) parseRngListsHeader(bytes []byte) (*rngLists, error) {
+ rngLists := &rngLists{data: bytes}
+
+ buf := makeBuf(d, unknownFormat{}, "rnglists", 0, bytes)
+ _, rngLists.is64 = buf.unitLength()
+
+ rngLists.ver = buf.uint16() // version
+
+ rngLists.asize = buf.uint8()
+ segsize := buf.uint8()
+ if segsize != 0 {
+ return nil, errSegmentSelector
+ }
+
+ // Header fields not read: offset_entry_count, offset table
+
+ return rngLists, nil
+}
+
+func (rngLists *rngLists) version() int {
+ return int(rngLists.ver)
+}
+
+func (rngLists *rngLists) dwarf64() (bool, bool) {
+ return rngLists.is64, true
+}
+
+func (rngLists *rngLists) addrsize() int {
+ return int(rngLists.asize)
+}
+
+// parseAddrHeader reads the header of a debug_addr section, see DWARFv5
+// section 7.27 (page 241).
+func (d *Data) parseAddrHeader(bytes []byte) (*debugAddr, error) {
+ addr := &debugAddr{data: bytes}
+
+ buf := makeBuf(d, unknownFormat{}, "addr", 0, bytes)
+ _, addr.is64 = buf.unitLength()
+
+ addr.asize = buf.uint8()
+ segsize := buf.uint8()
+ if segsize != 0 {
+ return nil, errSegmentSelector
+ }
+
+ return addr, nil
+}
+
+func (addr *debugAddr) version() int {
+ return 5
+}
+
+func (addr *debugAddr) dwarf64() (bool, bool) {
+ return addr.is64, true
+}
+
+func (addr *debugAddr) addrsize() int {
+ return int(addr.asize)
}
diff --git a/src/debug/dwarf/testdata/debug_rnglists b/src/debug/dwarf/testdata/debug_rnglists
new file mode 100644
index 0000000000..985ec6c9f2
--- /dev/null
+++ b/src/debug/dwarf/testdata/debug_rnglists
Binary files differ
diff --git a/src/debug/elf/elf.go b/src/debug/elf/elf.go
index 96a67ce732..2b777eabac 100644
--- a/src/debug/elf/elf.go
+++ b/src/debug/elf/elf.go
@@ -745,18 +745,51 @@ func (i CompressionType) GoString() string { return stringName(uint32(i), compre
type ProgType int
const (
- PT_NULL ProgType = 0 /* Unused entry. */
- PT_LOAD ProgType = 1 /* Loadable segment. */
- PT_DYNAMIC ProgType = 2 /* Dynamic linking information segment. */
- PT_INTERP ProgType = 3 /* Pathname of interpreter. */
- PT_NOTE ProgType = 4 /* Auxiliary information. */
- PT_SHLIB ProgType = 5 /* Reserved (not used). */
- PT_PHDR ProgType = 6 /* Location of program header itself. */
- PT_TLS ProgType = 7 /* Thread local storage segment */
- PT_LOOS ProgType = 0x60000000 /* First OS-specific. */
- PT_HIOS ProgType = 0x6fffffff /* Last OS-specific. */
- PT_LOPROC ProgType = 0x70000000 /* First processor-specific type. */
- PT_HIPROC ProgType = 0x7fffffff /* Last processor-specific type. */
+ PT_NULL ProgType = 0 /* Unused entry. */
+ PT_LOAD ProgType = 1 /* Loadable segment. */
+ PT_DYNAMIC ProgType = 2 /* Dynamic linking information segment. */
+ PT_INTERP ProgType = 3 /* Pathname of interpreter. */
+ PT_NOTE ProgType = 4 /* Auxiliary information. */
+ PT_SHLIB ProgType = 5 /* Reserved (not used). */
+ PT_PHDR ProgType = 6 /* Location of program header itself. */
+ PT_TLS ProgType = 7 /* Thread local storage segment */
+
+ PT_LOOS ProgType = 0x60000000 /* First OS-specific. */
+
+ PT_GNU_EH_FRAME ProgType = 0x6474e550 /* Frame unwind information */
+ PT_GNU_STACK ProgType = 0x6474e551 /* Stack flags */
+ PT_GNU_RELRO ProgType = 0x6474e552 /* Read only after relocs */
+ PT_GNU_PROPERTY ProgType = 0x6474e553 /* GNU property */
+ PT_GNU_MBIND_LO ProgType = 0x6474e555 /* Mbind segments start */
+ PT_GNU_MBIND_HI ProgType = 0x6474f554 /* Mbind segments finish */
+
+ PT_PAX_FLAGS ProgType = 0x65041580 /* PAX flags */
+
+ PT_OPENBSD_RANDOMIZE ProgType = 0x65a3dbe6 /* Random data */
+ PT_OPENBSD_WXNEEDED ProgType = 0x65a3dbe7 /* W^X violations */
+ PT_OPENBSD_BOOTDATA ProgType = 0x65a41be6 /* Boot arguments */
+
+ PT_SUNW_EH_FRAME ProgType = 0x6474e550 /* Frame unwind information */
+ PT_SUNWSTACK ProgType = 0x6ffffffb /* Stack segment */
+
+ PT_HIOS ProgType = 0x6fffffff /* Last OS-specific. */
+
+ PT_LOPROC ProgType = 0x70000000 /* First processor-specific type. */
+
+ PT_ARM_ARCHEXT ProgType = 0x70000000 /* Architecture compatibility */
+ PT_ARM_EXIDX ProgType = 0x70000001 /* Exception unwind tables */
+
+ PT_AARCH64_ARCHEXT ProgType = 0x70000000 /* Architecture compatibility */
+ PT_AARCH64_UNWIND ProgType = 0x70000001 /* Exception unwind tables */
+
+ PT_MIPS_REGINFO ProgType = 0x70000000 /* Register usage */
+ PT_MIPS_RTPROC ProgType = 0x70000001 /* Runtime procedures */
+ PT_MIPS_OPTIONS ProgType = 0x70000002 /* Options */
+ PT_MIPS_ABIFLAGS ProgType = 0x70000003 /* ABI flags */
+
+ PT_S390_PGSTE ProgType = 0x70000000 /* 4k page table size */
+
+ PT_HIPROC ProgType = 0x7fffffff /* Last processor-specific type. */
)
var ptStrings = []intName{
@@ -769,8 +802,19 @@ var ptStrings = []intName{
{6, "PT_PHDR"},
{7, "PT_TLS"},
{0x60000000, "PT_LOOS"},
+ {0x6474e550, "PT_GNU_EH_FRAME"},
+ {0x6474e551, "PT_GNU_STACK"},
+ {0x6474e552, "PT_GNU_RELRO"},
+ {0x6474e553, "PT_GNU_PROPERTY"},
+ {0x65041580, "PT_PAX_FLAGS"},
+ {0x65a3dbe6, "PT_OPENBSD_RANDOMIZE"},
+ {0x65a3dbe7, "PT_OPENBSD_WXNEEDED"},
+ {0x65a41be6, "PT_OPENBSD_BOOTDATA"},
+ {0x6ffffffb, "PT_SUNWSTACK"},
{0x6fffffff, "PT_HIOS"},
{0x70000000, "PT_LOPROC"},
+ // We don't list the processor-dependent ProgTypes,
+ // as the values overlap.
{0x7fffffff, "PT_HIPROC"},
}
@@ -837,15 +881,114 @@ const (
the interpretation of the d_un union
as follows: even == 'd_ptr', even == 'd_val'
or none */
- DT_PREINIT_ARRAY DynTag = 32 /* Address of the array of pointers to pre-initialization functions. */
- DT_PREINIT_ARRAYSZ DynTag = 33 /* Size in bytes of the array of pre-initialization functions. */
- DT_LOOS DynTag = 0x6000000d /* First OS-specific */
- DT_HIOS DynTag = 0x6ffff000 /* Last OS-specific */
- DT_VERSYM DynTag = 0x6ffffff0
- DT_VERNEED DynTag = 0x6ffffffe
- DT_VERNEEDNUM DynTag = 0x6fffffff
- DT_LOPROC DynTag = 0x70000000 /* First processor-specific type. */
- DT_HIPROC DynTag = 0x7fffffff /* Last processor-specific type. */
+ DT_PREINIT_ARRAY DynTag = 32 /* Address of the array of pointers to pre-initialization functions. */
+ DT_PREINIT_ARRAYSZ DynTag = 33 /* Size in bytes of the array of pre-initialization functions. */
+ DT_SYMTAB_SHNDX DynTag = 34 /* Address of SHT_SYMTAB_SHNDX section. */
+
+ DT_LOOS DynTag = 0x6000000d /* First OS-specific */
+ DT_HIOS DynTag = 0x6ffff000 /* Last OS-specific */
+
+ DT_VALRNGLO DynTag = 0x6ffffd00
+ DT_GNU_PRELINKED DynTag = 0x6ffffdf5
+ DT_GNU_CONFLICTSZ DynTag = 0x6ffffdf6
+ DT_GNU_LIBLISTSZ DynTag = 0x6ffffdf7
+ DT_CHECKSUM DynTag = 0x6ffffdf8
+ DT_PLTPADSZ DynTag = 0x6ffffdf9
+ DT_MOVEENT DynTag = 0x6ffffdfa
+ DT_MOVESZ DynTag = 0x6ffffdfb
+ DT_FEATURE DynTag = 0x6ffffdfc
+ DT_POSFLAG_1 DynTag = 0x6ffffdfd
+ DT_SYMINSZ DynTag = 0x6ffffdfe
+ DT_SYMINENT DynTag = 0x6ffffdff
+ DT_VALRNGHI DynTag = 0x6ffffdff
+
+ DT_ADDRRNGLO DynTag = 0x6ffffe00
+ DT_GNU_HASH DynTag = 0x6ffffef5
+ DT_TLSDESC_PLT DynTag = 0x6ffffef6
+ DT_TLSDESC_GOT DynTag = 0x6ffffef7
+ DT_GNU_CONFLICT DynTag = 0x6ffffef8
+ DT_GNU_LIBLIST DynTag = 0x6ffffef9
+ DT_CONFIG DynTag = 0x6ffffefa
+ DT_DEPAUDIT DynTag = 0x6ffffefb
+ DT_AUDIT DynTag = 0x6ffffefc
+ DT_PLTPAD DynTag = 0x6ffffefd
+ DT_MOVETAB DynTag = 0x6ffffefe
+ DT_SYMINFO DynTag = 0x6ffffeff
+ DT_ADDRRNGHI DynTag = 0x6ffffeff
+
+ DT_VERSYM DynTag = 0x6ffffff0
+ DT_RELACOUNT DynTag = 0x6ffffff9
+ DT_RELCOUNT DynTag = 0x6ffffffa
+ DT_FLAGS_1 DynTag = 0x6ffffffb
+ DT_VERDEF DynTag = 0x6ffffffc
+ DT_VERDEFNUM DynTag = 0x6ffffffd
+ DT_VERNEED DynTag = 0x6ffffffe
+ DT_VERNEEDNUM DynTag = 0x6fffffff
+
+ DT_LOPROC DynTag = 0x70000000 /* First processor-specific type. */
+
+ DT_MIPS_RLD_VERSION DynTag = 0x70000001
+ DT_MIPS_TIME_STAMP DynTag = 0x70000002
+ DT_MIPS_ICHECKSUM DynTag = 0x70000003
+ DT_MIPS_IVERSION DynTag = 0x70000004
+ DT_MIPS_FLAGS DynTag = 0x70000005
+ DT_MIPS_BASE_ADDRESS DynTag = 0x70000006
+ DT_MIPS_MSYM DynTag = 0x70000007
+ DT_MIPS_CONFLICT DynTag = 0x70000008
+ DT_MIPS_LIBLIST DynTag = 0x70000009
+ DT_MIPS_LOCAL_GOTNO DynTag = 0x7000000a
+ DT_MIPS_CONFLICTNO DynTag = 0x7000000b
+ DT_MIPS_LIBLISTNO DynTag = 0x70000010
+ DT_MIPS_SYMTABNO DynTag = 0x70000011
+ DT_MIPS_UNREFEXTNO DynTag = 0x70000012
+ DT_MIPS_GOTSYM DynTag = 0x70000013
+ DT_MIPS_HIPAGENO DynTag = 0x70000014
+ DT_MIPS_RLD_MAP DynTag = 0x70000016
+ DT_MIPS_DELTA_CLASS DynTag = 0x70000017
+ DT_MIPS_DELTA_CLASS_NO DynTag = 0x70000018
+ DT_MIPS_DELTA_INSTANCE DynTag = 0x70000019
+ DT_MIPS_DELTA_INSTANCE_NO DynTag = 0x7000001a
+ DT_MIPS_DELTA_RELOC DynTag = 0x7000001b
+ DT_MIPS_DELTA_RELOC_NO DynTag = 0x7000001c
+ DT_MIPS_DELTA_SYM DynTag = 0x7000001d
+ DT_MIPS_DELTA_SYM_NO DynTag = 0x7000001e
+ DT_MIPS_DELTA_CLASSSYM DynTag = 0x70000020
+ DT_MIPS_DELTA_CLASSSYM_NO DynTag = 0x70000021
+ DT_MIPS_CXX_FLAGS DynTag = 0x70000022
+ DT_MIPS_PIXIE_INIT DynTag = 0x70000023
+ DT_MIPS_SYMBOL_LIB DynTag = 0x70000024
+ DT_MIPS_LOCALPAGE_GOTIDX DynTag = 0x70000025
+ DT_MIPS_LOCAL_GOTIDX DynTag = 0x70000026
+ DT_MIPS_HIDDEN_GOTIDX DynTag = 0x70000027
+ DT_MIPS_PROTECTED_GOTIDX DynTag = 0x70000028
+ DT_MIPS_OPTIONS DynTag = 0x70000029
+ DT_MIPS_INTERFACE DynTag = 0x7000002a
+ DT_MIPS_DYNSTR_ALIGN DynTag = 0x7000002b
+ DT_MIPS_INTERFACE_SIZE DynTag = 0x7000002c
+ DT_MIPS_RLD_TEXT_RESOLVE_ADDR DynTag = 0x7000002d
+ DT_MIPS_PERF_SUFFIX DynTag = 0x7000002e
+ DT_MIPS_COMPACT_SIZE DynTag = 0x7000002f
+ DT_MIPS_GP_VALUE DynTag = 0x70000030
+ DT_MIPS_AUX_DYNAMIC DynTag = 0x70000031
+ DT_MIPS_PLTGOT DynTag = 0x70000032
+ DT_MIPS_RWPLT DynTag = 0x70000034
+ DT_MIPS_RLD_MAP_REL DynTag = 0x70000035
+
+ DT_PPC_GOT DynTag = 0x70000000
+ DT_PPC_OPT DynTag = 0x70000001
+
+ DT_PPC64_GLINK DynTag = 0x70000000
+ DT_PPC64_OPD DynTag = 0x70000001
+ DT_PPC64_OPDSZ DynTag = 0x70000002
+ DT_PPC64_OPT DynTag = 0x70000003
+
+ DT_SPARC_REGISTER DynTag = 0x70000001
+
+ DT_AUXILIARY DynTag = 0x7ffffffd
+ DT_USED DynTag = 0x7ffffffe
+ DT_FILTER DynTag = 0x7fffffff
+
+ DT_HIPROC DynTag = 0x7fffffff /* Last processor-specific type. */
)
var dtStrings = []intName{
@@ -883,13 +1026,49 @@ var dtStrings = []intName{
{32, "DT_ENCODING"},
{32, "DT_PREINIT_ARRAY"},
{33, "DT_PREINIT_ARRAYSZ"},
+ {34, "DT_SYMTAB_SHNDX"},
{0x6000000d, "DT_LOOS"},
{0x6ffff000, "DT_HIOS"},
+ {0x6ffffd00, "DT_VALRNGLO"},
+ {0x6ffffdf5, "DT_GNU_PRELINKED"},
+ {0x6ffffdf6, "DT_GNU_CONFLICTSZ"},
+ {0x6ffffdf7, "DT_GNU_LIBLISTSZ"},
+ {0x6ffffdf8, "DT_CHECKSUM"},
+ {0x6ffffdf9, "DT_PLTPADSZ"},
+ {0x6ffffdfa, "DT_MOVEENT"},
+ {0x6ffffdfb, "DT_MOVESZ"},
+ {0x6ffffdfc, "DT_FEATURE"},
+ {0x6ffffdfd, "DT_POSFLAG_1"},
+ {0x6ffffdfe, "DT_SYMINSZ"},
+ {0x6ffffdff, "DT_SYMINENT"},
+ {0x6ffffdff, "DT_VALRNGHI"},
+ {0x6ffffe00, "DT_ADDRRNGLO"},
+ {0x6ffffef5, "DT_GNU_HASH"},
+ {0x6ffffef6, "DT_TLSDESC_PLT"},
+ {0x6ffffef7, "DT_TLSDESC_GOT"},
+ {0x6ffffef8, "DT_GNU_CONFLICT"},
+ {0x6ffffef9, "DT_GNU_LIBLIST"},
+ {0x6ffffefa, "DT_CONFIG"},
+ {0x6ffffefb, "DT_DEPAUDIT"},
+ {0x6ffffefc, "DT_AUDIT"},
+ {0x6ffffefd, "DT_PLTPAD"},
+ {0x6ffffefe, "DT_MOVETAB"},
+ {0x6ffffeff, "DT_SYMINFO"},
+ {0x6ffffeff, "DT_ADDRRNGHI"},
{0x6ffffff0, "DT_VERSYM"},
+ {0x6ffffff9, "DT_RELACOUNT"},
+ {0x6ffffffa, "DT_RELCOUNT"},
+ {0x6ffffffb, "DT_FLAGS_1"},
+ {0x6ffffffc, "DT_VERDEF"},
+ {0x6ffffffd, "DT_VERDEFNUM"},
{0x6ffffffe, "DT_VERNEED"},
{0x6fffffff, "DT_VERNEEDNUM"},
{0x70000000, "DT_LOPROC"},
- {0x7fffffff, "DT_HIPROC"},
+ // We don't list the processor-dependent DynTags,
+ // as the values overlap.
+ {0x7ffffffd, "DT_AUXILIARY"},
+ {0x7ffffffe, "DT_USED"},
+ {0x7fffffff, "DT_FILTER"},
}
func (i DynTag) String() string { return stringName(uint32(i), dtStrings, false) }
diff --git a/src/debug/elf/file_test.go b/src/debug/elf/file_test.go
index 24948e696a..4c6fdeece9 100644
--- a/src/debug/elf/file_test.go
+++ b/src/debug/elf/file_test.go
@@ -899,7 +899,7 @@ func TestCompressedSection(t *testing.T) {
func TestNoSectionOverlaps(t *testing.T) {
// Ensure cmd/link outputs sections without overlaps.
switch runtime.GOOS {
- case "aix", "android", "darwin", "js", "plan9", "windows":
+ case "aix", "android", "darwin", "ios", "js", "plan9", "windows":
t.Skipf("cmd/link doesn't produce ELF binaries on %s", runtime.GOOS)
}
_ = net.ResolveIPAddr // force dynamic linkage
diff --git a/src/debug/gosym/pclntab.go b/src/debug/gosym/pclntab.go
index e5c50520fc..a72f9847d7 100644
--- a/src/debug/gosym/pclntab.go
+++ b/src/debug/gosym/pclntab.go
@@ -53,14 +53,19 @@ type LineTable struct {
quantum uint32
ptrsize uint32
funcnametab []byte
+ cutab []byte
funcdata []byte
functab []byte
nfunctab uint32
filetab []byte
+ pctab []byte // points to the pctables.
nfiletab uint32
- fileMap map[string]uint32
funcNames map[uint32]string // cache the function names
strings map[uint32]string // interned substrings of Data, keyed by offset
+ // fileMap varies depending on the version of the object file.
+ // For ver12, it maps the name to the index in the file table.
+ // For ver116, it maps the name to the offset in filetab.
+ fileMap map[string]uint32
}
// NOTE(rsc): This is wrong for GOARCH=arm, which uses a quantum of 4,
@@ -223,22 +228,26 @@ func (t *LineTable) parsePclnTab() {
switch possibleVersion {
case ver116:
t.nfunctab = uint32(t.uintptr(t.Data[8:]))
- offset := t.uintptr(t.Data[8+t.ptrsize:])
+ t.nfiletab = uint32(t.uintptr(t.Data[8+t.ptrsize:]))
+ offset := t.uintptr(t.Data[8+2*t.ptrsize:])
t.funcnametab = t.Data[offset:]
- offset = t.uintptr(t.Data[8+2*t.ptrsize:])
+ offset = t.uintptr(t.Data[8+3*t.ptrsize:])
+ t.cutab = t.Data[offset:]
+ offset = t.uintptr(t.Data[8+4*t.ptrsize:])
+ t.filetab = t.Data[offset:]
+ offset = t.uintptr(t.Data[8+5*t.ptrsize:])
+ t.pctab = t.Data[offset:]
+ offset = t.uintptr(t.Data[8+6*t.ptrsize:])
t.funcdata = t.Data[offset:]
t.functab = t.Data[offset:]
functabsize := t.nfunctab*2*t.ptrsize + t.ptrsize
- fileoff := t.binary.Uint32(t.functab[functabsize:])
- t.filetab = t.functab[fileoff:]
t.functab = t.functab[:functabsize]
- t.nfiletab = t.binary.Uint32(t.filetab)
- t.filetab = t.filetab[:t.nfiletab*4]
case ver12:
t.nfunctab = uint32(t.uintptr(t.Data[8:]))
t.funcdata = t.Data
t.funcnametab = t.Data
t.functab = t.Data[8+t.ptrsize:]
+ t.pctab = t.Data
functabsize := t.nfunctab*2*t.ptrsize + t.ptrsize
fileoff := t.binary.Uint32(t.functab[functabsize:])
t.functab = t.functab[:functabsize]
@@ -330,17 +339,22 @@ func (t *LineTable) funcName(off uint32) string {
return s
}
-// string returns a Go string found at off.
-func (t *LineTable) string(off uint32) string {
+// stringFrom returns a Go string found at off from a position.
+func (t *LineTable) stringFrom(arr []byte, off uint32) string {
if s, ok := t.strings[off]; ok {
return s
}
- i := bytes.IndexByte(t.funcdata[off:], 0)
- s := string(t.funcdata[off : off+uint32(i)])
+ i := bytes.IndexByte(arr[off:], 0)
+ s := string(arr[off : off+uint32(i)])
t.strings[off] = s
return s
}
+// string returns a Go string found at off.
+func (t *LineTable) string(off uint32) string {
+ return t.stringFrom(t.funcdata, off)
+}
+
// step advances to the next pc, value pair in the encoded table.
func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool {
uvdelta := t.readvarint(p)
@@ -363,7 +377,7 @@ func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool {
// off is the offset to the beginning of the pc-value table,
// and entry is the start PC for the corresponding function.
func (t *LineTable) pcvalue(off uint32, entry, targetpc uint64) int32 {
- p := t.funcdata[off:]
+ p := t.pctab[off:]
val := int32(-1)
pc := entry
@@ -381,21 +395,25 @@ func (t *LineTable) pcvalue(off uint32, entry, targetpc uint64) int32 {
// to file number. Since most functions come from a single file, these
// are usually short and quick to scan. If a file match is found, then the
// code goes to the expense of looking for a simultaneous line number match.
-func (t *LineTable) findFileLine(entry uint64, filetab, linetab uint32, filenum, line int32) uint64 {
+func (t *LineTable) findFileLine(entry uint64, filetab, linetab uint32, filenum, line int32, cutab []byte) uint64 {
if filetab == 0 || linetab == 0 {
return 0
}
- fp := t.funcdata[filetab:]
- fl := t.funcdata[linetab:]
+ fp := t.pctab[filetab:]
+ fl := t.pctab[linetab:]
fileVal := int32(-1)
filePC := entry
lineVal := int32(-1)
linePC := entry
fileStartPC := filePC
for t.step(&fp, &filePC, &fileVal, filePC == entry) {
- if fileVal == filenum && fileStartPC < filePC {
- // fileVal is in effect starting at fileStartPC up to
+ fileIndex := fileVal
+ if t.version == ver116 {
+ fileIndex = int32(t.binary.Uint32(cutab[fileVal*4:]))
+ }
+ if fileIndex == filenum && fileStartPC < filePC {
+ // fileIndex is in effect starting at fileStartPC up to
// but not including filePC, and it's the file we want.
// Run the PC table looking for a matching line number
// or until we reach filePC.
@@ -450,13 +468,24 @@ func (t *LineTable) go12PCToFile(pc uint64) (file string) {
entry := t.uintptr(f)
filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
fno := t.pcvalue(filetab, entry, pc)
- if fno <= 0 {
+ if t.version == ver12 {
+ if fno <= 0 {
+ return ""
+ }
+ return t.string(t.binary.Uint32(t.filetab[4*fno:]))
+ }
+ // Go ≥ 1.16
+ if fno < 0 { // 0 is valid for ≥ 1.16
return ""
}
- return t.string(t.binary.Uint32(t.filetab[4*fno:]))
+ cuoff := t.binary.Uint32(f[t.ptrsize+7*4:])
+ if fnoff := t.binary.Uint32(t.cutab[(cuoff+uint32(fno))*4:]); fnoff != ^uint32(0) {
+ return t.stringFrom(t.filetab, fnoff)
+ }
+ return ""
}
-// go12LineToPC maps a (file, line) pair to a program counter for the Go 1.2 pcln table.
+// go12LineToPC maps a (file, line) pair to a program counter for the Go 1.2/1.16 pcln table.
func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) {
defer func() {
if recover() != nil {
@@ -465,20 +494,25 @@ func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) {
}()
t.initFileMap()
- filenum := t.fileMap[file]
- if filenum == 0 {
+ filenum, ok := t.fileMap[file]
+ if !ok {
return 0
}
// Scan all functions.
// If this turns out to be a bottleneck, we could build a map[int32][]int32
// mapping file number to a list of functions with code from that file.
+ var cutab []byte
for i := uint32(0); i < t.nfunctab; i++ {
f := t.funcdata[t.uintptr(t.functab[2*t.ptrsize*i+t.ptrsize:]):]
entry := t.uintptr(f)
filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
linetab := t.binary.Uint32(f[t.ptrsize+5*4:])
- pc := t.findFileLine(entry, filetab, linetab, int32(filenum), int32(line))
+ if t.version == ver116 {
+ cuoff := t.binary.Uint32(f[t.ptrsize+7*4:]) * 4
+ cutab = t.cutab[cuoff:]
+ }
+ pc := t.findFileLine(entry, filetab, linetab, int32(filenum), int32(line), cutab)
if pc != 0 {
return pc
}
@@ -496,9 +530,18 @@ func (t *LineTable) initFileMap() {
}
m := make(map[string]uint32)
- for i := uint32(1); i < t.nfiletab; i++ {
- s := t.string(t.binary.Uint32(t.filetab[4*i:]))
- m[s] = i
+ if t.version == ver12 {
+ for i := uint32(1); i < t.nfiletab; i++ {
+ s := t.string(t.binary.Uint32(t.filetab[4*i:]))
+ m[s] = i
+ }
+ } else {
+ var pos uint32
+ for i := uint32(0); i < t.nfiletab; i++ {
+ s := t.stringFrom(t.filetab, pos)
+ m[s] = pos
+ pos += uint32(len(s) + 1)
+ }
}
t.fileMap = m
}
diff --git a/src/debug/gosym/pclntab_test.go b/src/debug/gosym/pclntab_test.go
index 33772c7813..7347139b5d 100644
--- a/src/debug/gosym/pclntab_test.go
+++ b/src/debug/gosym/pclntab_test.go
@@ -9,7 +9,7 @@ import (
"compress/gzip"
"debug/elf"
"internal/testenv"
- "io/ioutil"
+ "io"
"os"
"os/exec"
"path/filepath"
@@ -30,7 +30,7 @@ func dotest(t *testing.T) {
t.Skipf("skipping on non-AMD64 system %s", runtime.GOARCH)
}
var err error
- pclineTempDir, err = ioutil.TempDir("", "pclinetest")
+ pclineTempDir, err = os.MkdirTemp("", "pclinetest")
if err != nil {
t.Fatal(err)
}
@@ -277,7 +277,7 @@ func TestPCLine(t *testing.T) {
// }
// [END]
func Test115PclnParsing(t *testing.T) {
- zippedDat, err := ioutil.ReadFile("testdata/pcln115.gz")
+ zippedDat, err := os.ReadFile("testdata/pcln115.gz")
if err != nil {
t.Fatal(err)
}
@@ -287,7 +287,7 @@ func Test115PclnParsing(t *testing.T) {
t.Fatal(err)
}
var dat []byte
- dat, err = ioutil.ReadAll(gzReader)
+ dat, err = io.ReadAll(gzReader)
if err != nil {
t.Fatal(err)
}
diff --git a/src/debug/pe/file_test.go b/src/debug/pe/file_test.go
index d96cd30904..58deff1450 100644
--- a/src/debug/pe/file_test.go
+++ b/src/debug/pe/file_test.go
@@ -8,7 +8,6 @@ import (
"bytes"
"debug/dwarf"
"internal/testenv"
- "io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -354,7 +353,7 @@ func testDWARF(t *testing.T, linktype int) {
}
testenv.MustHaveGoRun(t)
- tmpdir, err := ioutil.TempDir("", "TestDWARF")
+ tmpdir, err := os.MkdirTemp("", "TestDWARF")
if err != nil {
t.Fatal(err)
}
@@ -473,7 +472,7 @@ func TestBSSHasZeros(t *testing.T) {
t.Skip("skipping test: gcc is missing")
}
- tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros")
+ tmpdir, err := os.MkdirTemp("", "TestBSSHasZeros")
if err != nil {
t.Fatal(err)
}
@@ -492,7 +491,7 @@ main(void)
return 0;
}
`
- err = ioutil.WriteFile(srcpath, []byte(src), 0644)
+ err = os.WriteFile(srcpath, []byte(src), 0644)
if err != nil {
t.Fatal(err)
}
@@ -597,14 +596,14 @@ func TestBuildingWindowsGUI(t *testing.T) {
if runtime.GOOS != "windows" {
t.Skip("skipping windows only test")
}
- tmpdir, err := ioutil.TempDir("", "TestBuildingWindowsGUI")
+ tmpdir, err := os.MkdirTemp("", "TestBuildingWindowsGUI")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "a.go")
- err = ioutil.WriteFile(src, []byte(`package main; func main() {}`), 0644)
+ err = os.WriteFile(src, []byte(`package main; func main() {}`), 0644)
if err != nil {
t.Fatal(err)
}
@@ -684,7 +683,7 @@ func TestInvalidOptionalHeaderMagic(t *testing.T) {
func TestImportedSymbolsNoPanicMissingOptionalHeader(t *testing.T) {
// https://golang.org/issue/30250
// ImportedSymbols shouldn't panic if optional headers is missing
- data, err := ioutil.ReadFile("testdata/gcc-amd64-mingw-obj")
+ data, err := os.ReadFile("testdata/gcc-amd64-mingw-obj")
if err != nil {
t.Fatal(err)
}