summaryrefslogtreecommitdiff
path: root/libgo/go/debug
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2014-06-06 22:37:27 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2014-06-06 22:37:27 +0000
commita756a05a63c16e653903ee8078d9760185cab545 (patch)
tree2bc668fae9bf96f9a3988e0b0a16685bde8c4f0b /libgo/go/debug
parentb9f71945eda675b307727a5d1b8455887ee30fee (diff)
downloadgcc-a756a05a63c16e653903ee8078d9760185cab545.tar.gz
libgo: Merge to master revision 19184.
The next revision, 19185, renames several runtime files, and will be handled in a separate change. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@211328 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/debug')
-rw-r--r--libgo/go/debug/dwarf/const.go31
-rw-r--r--libgo/go/debug/dwarf/entry.go12
-rw-r--r--libgo/go/debug/dwarf/open.go10
-rw-r--r--libgo/go/debug/dwarf/testdata/typedef.elf4bin0 -> 9496 bytes
-rw-r--r--libgo/go/debug/dwarf/type.go75
-rw-r--r--libgo/go/debug/dwarf/type_test.go2
-rw-r--r--libgo/go/debug/dwarf/typeunit.go166
-rw-r--r--libgo/go/debug/dwarf/unit.go2
-rw-r--r--libgo/go/debug/elf/elf_test.go2
-rw-r--r--libgo/go/debug/elf/file.go48
-rw-r--r--libgo/go/debug/elf/testdata/hello.c7
-rw-r--r--libgo/go/debug/goobj/read.go50
-rw-r--r--libgo/go/debug/gosym/pclntab.go27
-rw-r--r--libgo/go/debug/gosym/symtab.go7
-rw-r--r--libgo/go/debug/macho/fat.go146
-rw-r--r--libgo/go/debug/macho/file.go20
-rw-r--r--libgo/go/debug/macho/file_test.go43
-rw-r--r--libgo/go/debug/macho/macho.go13
-rw-r--r--libgo/go/debug/macho/testdata/fat-gcc-386-amd64-darwin-execbin0 -> 28992 bytes
-rw-r--r--libgo/go/debug/pe/file.go21
-rw-r--r--libgo/go/debug/plan9obj/file.go346
-rw-r--r--libgo/go/debug/plan9obj/file_test.go81
-rw-r--r--libgo/go/debug/plan9obj/plan9obj.go91
-rw-r--r--libgo/go/debug/plan9obj/testdata/386-plan9-execbin0 -> 37232 bytes
-rw-r--r--libgo/go/debug/plan9obj/testdata/amd64-plan9-execbin0 -> 34279 bytes
-rw-r--r--libgo/go/debug/plan9obj/testdata/hello.c8
26 files changed, 1146 insertions, 62 deletions
diff --git a/libgo/go/debug/dwarf/const.go b/libgo/go/debug/dwarf/const.go
index 68503c742f6..2aa0c270ff2 100644
--- a/libgo/go/debug/dwarf/const.go
+++ b/libgo/go/debug/dwarf/const.go
@@ -207,6 +207,7 @@ const (
formRef8 format = 0x14
formRefUdata format = 0x15
formIndirect format = 0x16
+ // The following are new in DWARF 4.
formSecOffset format = 0x17
formExprloc format = 0x18
formFlagPresent format = 0x19
@@ -264,15 +265,22 @@ const (
TagVariantPart Tag = 0x33
TagVariable Tag = 0x34
TagVolatileType Tag = 0x35
- TagDwarfProcedure Tag = 0x36
- TagRestrictType Tag = 0x37
- TagInterfaceType Tag = 0x38
- TagNamespace Tag = 0x39
- TagImportedModule Tag = 0x3A
- TagUnspecifiedType Tag = 0x3B
- TagPartialUnit Tag = 0x3C
- TagImportedUnit Tag = 0x3D
- TagMutableType Tag = 0x3E
+ // The following are new in DWARF 3.
+ TagDwarfProcedure Tag = 0x36
+ TagRestrictType Tag = 0x37
+ TagInterfaceType Tag = 0x38
+ TagNamespace Tag = 0x39
+ TagImportedModule Tag = 0x3A
+ TagUnspecifiedType Tag = 0x3B
+ TagPartialUnit Tag = 0x3C
+ TagImportedUnit Tag = 0x3D
+ TagMutableType Tag = 0x3E // Later removed from DWARF.
+ TagCondition Tag = 0x3F
+ TagSharedType Tag = 0x40
+ // The following are new in DWARF 4.
+ TagTypeUnit Tag = 0x41
+ TagRvalueReferenceType Tag = 0x42
+ TagTemplateAlias Tag = 0x43
)
var tagNames = [...]string{
@@ -332,6 +340,11 @@ var tagNames = [...]string{
TagPartialUnit: "PartialUnit",
TagImportedUnit: "ImportedUnit",
TagMutableType: "MutableType",
+ TagCondition: "Condition",
+ TagSharedType: "SharedType",
+ TagTypeUnit: "TypeUnit",
+ TagRvalueReferenceType: "RvalueReferenceType",
+ TagTemplateAlias: "TemplateAlias",
}
func (t Tag) String() string {
diff --git a/libgo/go/debug/dwarf/entry.go b/libgo/go/debug/dwarf/entry.go
index e0d3229fb49..1772221633f 100644
--- a/libgo/go/debug/dwarf/entry.go
+++ b/libgo/go/debug/dwarf/entry.go
@@ -396,3 +396,15 @@ func (r *Reader) SkipChildren() {
}
}
}
+
+// clone returns a copy of the reader. This is used by the typeReader
+// interface.
+func (r *Reader) clone() typeReader {
+ return r.d.Reader()
+}
+
+// offset returns the current buffer offset. This is used by the
+// typeReader interface.
+func (r *Reader) offset() Offset {
+ return r.b.off
+}
diff --git a/libgo/go/debug/dwarf/open.go b/libgo/go/debug/dwarf/open.go
index 75798925296..c1b3f37aca9 100644
--- a/libgo/go/debug/dwarf/open.go
+++ b/libgo/go/debug/dwarf/open.go
@@ -26,6 +26,7 @@ type Data struct {
abbrevCache map[uint32]abbrevTable
order binary.ByteOrder
typeCache map[Offset]Type
+ typeSigs map[uint64]*typeUnit
unit []unit
}
@@ -49,6 +50,7 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
str: str,
abbrevCache: make(map[uint32]abbrevTable),
typeCache: make(map[Offset]Type),
+ typeSigs: make(map[uint64]*typeUnit),
}
// Sniff .debug_info to figure out byte order.
@@ -75,3 +77,11 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
d.unit = u
return d, nil
}
+
+// AddTypes will add one .debug_types section to the DWARF data. A
+// typical object with DWARF version 4 debug info will have multiple
+// .debug_types sections. The name is used for error reporting only,
+// and serves to distinguish one .debug_types section from another.
+func (d *Data) AddTypes(name string, types []byte) error {
+ return d.parseTypes(name, types)
+}
diff --git a/libgo/go/debug/dwarf/testdata/typedef.elf4 b/libgo/go/debug/dwarf/testdata/typedef.elf4
new file mode 100644
index 00000000000..3d5a5a1b162
--- /dev/null
+++ b/libgo/go/debug/dwarf/testdata/typedef.elf4
Binary files differ
diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go
index 1fbae6c144e..68866d0b7bf 100644
--- a/libgo/go/debug/dwarf/type.go
+++ b/libgo/go/debug/dwarf/type.go
@@ -251,23 +251,37 @@ func (t *TypedefType) String() string { return t.Name }
func (t *TypedefType) Size() int64 { return t.Type.Size() }
+// typeReader is used to read from either the info section or the
+// types section.
+type typeReader interface {
+ Seek(Offset)
+ Next() (*Entry, error)
+ clone() typeReader
+ offset() Offset
+}
+
+// Type reads the type at off in the DWARF ``info'' section.
func (d *Data) Type(off Offset) (Type, error) {
- if t, ok := d.typeCache[off]; ok {
+ return d.readType("info", d.Reader(), off, d.typeCache)
+}
+
+// readType reads a type from r at off of name using and updating a
+// type cache.
+func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type) (Type, error) {
+ if t, ok := typeCache[off]; ok {
return t, nil
}
-
- r := d.Reader()
r.Seek(off)
e, err := r.Next()
if err != nil {
return nil, err
}
if e == nil || e.Offset != off {
- return nil, DecodeError{"info", off, "no type at offset"}
+ return nil, DecodeError{name, off, "no type at offset"}
}
// Parse type from Entry.
- // Must always set d.typeCache[off] before calling
+ // Must always set typeCache[off] before calling
// d.Type recursively, to handle circular types correctly.
var typ Type
@@ -290,7 +304,7 @@ func (d *Data) Type(off Offset) (Type, error) {
return nil
}
if kid == nil {
- err = DecodeError{"info", r.b.off, "unexpected end of DWARF entries"}
+ err = DecodeError{name, r.offset(), "unexpected end of DWARF entries"}
return nil
}
if kid.Tag == 0 {
@@ -313,15 +327,21 @@ func (d *Data) Type(off Offset) (Type, error) {
// Get Type referred to by Entry's AttrType field.
// Set err if error happens. Not having a type is an error.
typeOf := func(e *Entry) Type {
- toff, ok := e.Val(AttrType).(Offset)
- if !ok {
+ tval := e.Val(AttrType)
+ var t Type
+ switch toff := tval.(type) {
+ case Offset:
+ if t, err = d.readType(name, r.clone(), toff, typeCache); err != nil {
+ return nil
+ }
+ case uint64:
+ if t, err = d.sigToType(toff); err != nil {
+ return nil
+ }
+ default:
// It appears that no Type means "void".
return new(VoidType)
}
- var t Type
- if t, err = d.Type(toff); err != nil {
- return nil
- }
return t
}
@@ -337,7 +357,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// dimensions are in left to right order.
t := new(ArrayType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
if t.Type = typeOf(e); err != nil {
goto Error
}
@@ -363,7 +383,7 @@ func (d *Data) Type(off Offset) (Type, error) {
}
ndim++
case TagEnumerationType:
- err = DecodeError{"info", kid.Offset, "cannot handle enumeration type as array bound"}
+ err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"}
goto Error
}
}
@@ -383,12 +403,12 @@ func (d *Data) Type(off Offset) (Type, error) {
name, _ := e.Val(AttrName).(string)
enc, ok := e.Val(AttrEncoding).(int64)
if !ok {
- err = DecodeError{"info", e.Offset, "missing encoding attribute for " + name}
+ err = DecodeError{name, e.Offset, "missing encoding attribute for " + name}
goto Error
}
switch enc {
default:
- err = DecodeError{"info", e.Offset, "unrecognized encoding attribute value"}
+ err = DecodeError{name, e.Offset, "unrecognized encoding attribute value"}
goto Error
case encAddress:
@@ -408,7 +428,7 @@ func (d *Data) Type(off Offset) (Type, error) {
case encUnsignedChar:
typ = new(UcharType)
}
- d.typeCache[off] = typ
+ typeCache[off] = typ
t := typ.(interface {
Basic() *BasicType
}).Basic()
@@ -433,7 +453,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// There is much more to handle C++, all ignored for now.
t := new(StructType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
switch e.Tag {
case TagClassType:
t.Kind = "class"
@@ -453,12 +473,13 @@ func (d *Data) Type(off Offset) (Type, error) {
if f.Type = typeOf(kid); err != nil {
goto Error
}
- if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
+ switch loc := kid.Val(AttrDataMemberLoc).(type) {
+ case []byte:
// TODO: Should have original compilation
// unit here, not unknownFormat.
b := makeBuf(d, unknownFormat{}, "location", 0, loc)
if b.uint8() != opPlusUconst {
- err = DecodeError{"info", kid.Offset, "unexpected opcode"}
+ err = DecodeError{name, kid.Offset, "unexpected opcode"}
goto Error
}
f.ByteOffset = int64(b.uint())
@@ -466,6 +487,8 @@ func (d *Data) Type(off Offset) (Type, error) {
err = b.err
goto Error
}
+ case int64:
+ f.ByteOffset = loc
}
haveBitOffset := false
@@ -502,7 +525,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// AttrType: subtype
t := new(QualType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
if t.Type = typeOf(e); err != nil {
goto Error
}
@@ -526,7 +549,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// AttrConstValue: value of constant
t := new(EnumType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
t.EnumName, _ = e.Val(AttrName).(string)
t.Val = make([]*EnumValue, 0, 8)
for kid := next(); kid != nil; kid = next() {
@@ -552,7 +575,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// AttrAddrClass: address class [ignored]
t := new(PtrType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
if e.Val(AttrType) == nil {
t.Type = &VoidType{}
break
@@ -571,7 +594,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// TagUnspecifiedParameter: final ...
t := new(FuncType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
if t.ReturnType = typeOf(e); err != nil {
goto Error
}
@@ -598,7 +621,7 @@ func (d *Data) Type(off Offset) (Type, error) {
// AttrType: type definition [required]
t := new(TypedefType)
typ = t
- d.typeCache[off] = t
+ typeCache[off] = t
t.Name, _ = e.Val(AttrName).(string)
t.Type = typeOf(e)
}
@@ -620,7 +643,7 @@ Error:
// If the parse fails, take the type out of the cache
// so that the next call with this offset doesn't hit
// the cache and return success.
- delete(d.typeCache, off)
+ delete(typeCache, off)
return nil, err
}
diff --git a/libgo/go/debug/dwarf/type_test.go b/libgo/go/debug/dwarf/type_test.go
index b5b255f6f4a..2cb85e74bb2 100644
--- a/libgo/go/debug/dwarf/type_test.go
+++ b/libgo/go/debug/dwarf/type_test.go
@@ -73,6 +73,8 @@ func TestTypedefsMachO(t *testing.T) {
testTypedefs(t, machoData(t, "testdata/typedef.macho"), "macho")
}
+func TestTypedefsELFDwarf4(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf4"), "elf") }
+
func testTypedefs(t *testing.T, d *Data, kind string) {
r := d.Reader()
seen := make(map[string]bool)
diff --git a/libgo/go/debug/dwarf/typeunit.go b/libgo/go/debug/dwarf/typeunit.go
new file mode 100644
index 00000000000..3fd1c9973e5
--- /dev/null
+++ b/libgo/go/debug/dwarf/typeunit.go
@@ -0,0 +1,166 @@
+// Copyright 2012 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 (
+ "fmt"
+ "strconv"
+)
+
+// Parse the type units stored in a DWARF4 .debug_types section. Each
+// type unit defines a single primary type and an 8-byte signature.
+// Other sections may then use formRefSig8 to refer to the type.
+
+// The typeUnit format is a single type with a signature. It holds
+// the same data as a compilation unit.
+type typeUnit struct {
+ unit
+ toff Offset // Offset to signature type within data.
+ name string // Name of .debug_type section.
+ cache Type // Cache the type, nil to start.
+}
+
+// Parse a .debug_types section.
+func (d *Data) parseTypes(name string, types []byte) error {
+ b := makeBuf(d, unknownFormat{}, name, 0, types)
+ for len(b.data) > 0 {
+ base := b.off
+ dwarf64 := false
+ n := b.uint32()
+ if n == 0xffffffff {
+ n64 := b.uint64()
+ if n64 != uint64(uint32(n64)) {
+ b.error("type unit length overflow")
+ return b.err
+ }
+ n = uint32(n64)
+ dwarf64 = true
+ }
+ hdroff := b.off
+ vers := b.uint16()
+ if vers != 4 {
+ b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
+ return b.err
+ }
+ var ao uint32
+ if !dwarf64 {
+ ao = b.uint32()
+ } else {
+ ao64 := b.uint64()
+ if ao64 != uint64(uint32(ao64)) {
+ b.error("type unit abbrev offset overflow")
+ return b.err
+ }
+ ao = uint32(ao64)
+ }
+ atable, err := d.parseAbbrev(ao)
+ if err != nil {
+ return err
+ }
+ asize := b.uint8()
+ sig := b.uint64()
+
+ var toff uint32
+ if !dwarf64 {
+ toff = b.uint32()
+ } else {
+ to64 := b.uint64()
+ if to64 != uint64(uint32(to64)) {
+ b.error("type unit type offset overflow")
+ return b.err
+ }
+ toff = uint32(to64)
+ }
+
+ boff := b.off
+ d.typeSigs[sig] = &typeUnit{
+ unit: unit{
+ base: base,
+ off: boff,
+ data: b.bytes(int(Offset(n) - (b.off - hdroff))),
+ atable: atable,
+ asize: int(asize),
+ vers: int(vers),
+ is64: dwarf64,
+ },
+ toff: Offset(toff),
+ name: name,
+ }
+ if b.err != nil {
+ return b.err
+ }
+ }
+ return nil
+}
+
+// Return the type for a type signature.
+func (d *Data) sigToType(sig uint64) (Type, error) {
+ tu := d.typeSigs[sig]
+ if tu == nil {
+ return nil, fmt.Errorf("no type unit with signature %v", sig)
+ }
+ if tu.cache != nil {
+ return tu.cache, nil
+ }
+
+ b := makeBuf(d, tu, tu.name, tu.off, tu.data)
+ r := &typeUnitReader{d: d, tu: tu, b: b}
+ t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type))
+ if err != nil {
+ return nil, err
+ }
+
+ tu.cache = t
+ return t, nil
+}
+
+// typeUnitReader is a typeReader for a tagTypeUnit.
+type typeUnitReader struct {
+ d *Data
+ tu *typeUnit
+ b buf
+ err error
+}
+
+// Seek to a new position in the type unit.
+func (tur *typeUnitReader) Seek(off Offset) {
+ tur.err = nil
+ doff := off - tur.tu.off
+ if doff < 0 || doff >= Offset(len(tur.tu.data)) {
+ tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data))
+ return
+ }
+ tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
+}
+
+// Next reads the next Entry from the type unit.
+func (tur *typeUnitReader) Next() (*Entry, error) {
+ if tur.err != nil {
+ return nil, tur.err
+ }
+ if len(tur.tu.data) == 0 {
+ return nil, nil
+ }
+ e := tur.b.entry(tur.tu.atable, tur.tu.base)
+ if tur.b.err != nil {
+ tur.err = tur.b.err
+ return nil, tur.err
+ }
+ return e, nil
+}
+
+// clone returns a new reader for the type unit.
+func (tur *typeUnitReader) clone() typeReader {
+ return &typeUnitReader{
+ d: tur.d,
+ tu: tur.tu,
+ b: makeBuf(tur.d, tur.tu, tur.tu.name, tur.tu.off, tur.tu.data),
+ }
+}
+
+// offset returns the current offset.
+func (tur *typeUnitReader) offset() Offset {
+ return tur.b.off
+}
diff --git a/libgo/go/debug/dwarf/unit.go b/libgo/go/debug/dwarf/unit.go
index 8e09298a8b4..be6093519d5 100644
--- a/libgo/go/debug/dwarf/unit.go
+++ b/libgo/go/debug/dwarf/unit.go
@@ -76,7 +76,7 @@ func (d *Data) parseUnits() ([]unit, error) {
n = uint32(b.uint64())
}
vers := b.uint16()
- if vers < 2 || vers > 4 {
+ if vers != 2 && vers != 3 && vers != 4 {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
diff --git a/libgo/go/debug/elf/elf_test.go b/libgo/go/debug/elf/elf_test.go
index 67b961b5c6c..e3c51bb717b 100644
--- a/libgo/go/debug/elf/elf_test.go
+++ b/libgo/go/debug/elf/elf_test.go
@@ -43,7 +43,7 @@ func TestNames(t *testing.T) {
for i, tt := range nameTests {
s := fmt.Sprint(tt.val)
if s != tt.str {
- t.Errorf("#%d: want %q have %q", i, s, tt.str)
+ t.Errorf("#%d: Sprint(%d) = %q, want %q", i, tt.val, s, tt.str)
}
}
}
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go
index 8023eb0a0b7..a98b469b330 100644
--- a/libgo/go/debug/elf/file.go
+++ b/libgo/go/debug/elf/file.go
@@ -76,6 +76,9 @@ type Section struct {
func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
return dat[0:n], err
}
@@ -412,7 +415,7 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
if err != nil {
return nil, nil, errors.New("cannot load symbol section")
}
- symtab := bytes.NewBuffer(data)
+ symtab := bytes.NewReader(data)
if symtab.Len()%Sym32Size != 0 {
return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
}
@@ -455,7 +458,7 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
if err != nil {
return nil, nil, errors.New("cannot load symbol section")
}
- symtab := bytes.NewBuffer(data)
+ symtab := bytes.NewReader(data)
if symtab.Len()%Sym64Size != 0 {
return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
}
@@ -533,7 +536,7 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
return err
}
- b := bytes.NewBuffer(rels)
+ b := bytes.NewReader(rels)
var rela Rela64
for b.Len() > 0 {
@@ -601,7 +604,44 @@ func (f *File) DWARF() (*dwarf.Data, error) {
}
abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
- return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
+ d, err := dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
+ if err != nil {
+ return nil, err
+ }
+
+ // Look for DWARF4 .debug_types sections.
+ for i, s := range f.Sections {
+ if s.Name == ".debug_types" {
+ b, err := s.Data()
+ if err != nil && uint64(len(b)) < s.Size {
+ return nil, err
+ }
+
+ for _, r := range f.Sections {
+ if r.Type != SHT_RELA && r.Type != SHT_REL {
+ continue
+ }
+ if int(r.Info) != i {
+ continue
+ }
+ rd, err := r.Data()
+ if err != nil {
+ return nil, err
+ }
+ err = f.applyRelocations(b, rd)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ return d, nil
}
// Symbols returns the symbol table for f.
diff --git a/libgo/go/debug/elf/testdata/hello.c b/libgo/go/debug/elf/testdata/hello.c
new file mode 100644
index 00000000000..34d9ee79234
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+main(int argc, char *argv[])
+{
+ printf("hello, world\n");
+}
diff --git a/libgo/go/debug/goobj/read.go b/libgo/go/debug/goobj/read.go
index 3338c411dc3..f65abb6c273 100644
--- a/libgo/go/debug/goobj/read.go
+++ b/libgo/go/debug/goobj/read.go
@@ -72,6 +72,49 @@ const (
SHOSTOBJ
)
+var symKindStrings = []string{
+ SBSS: "SBSS",
+ SCONST: "SCONST",
+ SDATA: "SDATA",
+ SDYNIMPORT: "SDYNIMPORT",
+ SELFROSECT: "SELFROSECT",
+ SELFRXSECT: "SELFRXSECT",
+ SELFSECT: "SELFSECT",
+ SFILE: "SFILE",
+ SFILEPATH: "SFILEPATH",
+ SFUNCTAB: "SFUNCTAB",
+ SGOFUNC: "SGOFUNC",
+ SGOSTRING: "SGOSTRING",
+ SHOSTOBJ: "SHOSTOBJ",
+ SINITARR: "SINITARR",
+ SMACHO: "SMACHO",
+ SMACHOGOT: "SMACHOGOT",
+ SMACHOINDIRECTGOT: "SMACHOINDIRECTGOT",
+ SMACHOINDIRECTPLT: "SMACHOINDIRECTPLT",
+ SMACHOPLT: "SMACHOPLT",
+ SMACHOSYMSTR: "SMACHOSYMSTR",
+ SMACHOSYMTAB: "SMACHOSYMTAB",
+ SNOPTRBSS: "SNOPTRBSS",
+ SNOPTRDATA: "SNOPTRDATA",
+ SPCLNTAB: "SPCLNTAB",
+ SRODATA: "SRODATA",
+ SSTRING: "SSTRING",
+ SSYMTAB: "SSYMTAB",
+ STEXT: "STEXT",
+ STLSBSS: "STLSBSS",
+ STYPE: "STYPE",
+ STYPELINK: "STYPELINK",
+ SWINDOWS: "SWINDOWS",
+ SXREF: "SXREF",
+}
+
+func (k SymKind) String() string {
+ if k < 0 || int(k) >= len(symKindStrings) {
+ return fmt.Sprintf("SymKind(%d)", k)
+ }
+ return symKindStrings[k]
+}
+
// A Sym is a named symbol in an object file.
type Sym struct {
SymID // symbol identifier (name and version)
@@ -98,6 +141,13 @@ type SymID struct {
Version int
}
+func (s SymID) String() string {
+ if s.Version == 0 {
+ return s.Name
+ }
+ return fmt.Sprintf("%s<%d>", s.Name, s.Version)
+}
+
// A Data is a reference to data stored in an object file.
// It records the offset and size of the data, so that a client can
// read the data only if necessary.
diff --git a/libgo/go/debug/gosym/pclntab.go b/libgo/go/debug/gosym/pclntab.go
index 3e6a8046b3e..6620aefb053 100644
--- a/libgo/go/debug/gosym/pclntab.go
+++ b/libgo/go/debug/gosym/pclntab.go
@@ -196,6 +196,33 @@ func (t *LineTable) go12Init() {
t.go12 = 1 // so far so good
}
+// go12Funcs returns a slice of Funcs derived from the Go 1.2 pcln table.
+func (t *LineTable) go12Funcs() []Func {
+ // Assume it is malformed and return nil on error.
+ defer func() {
+ recover()
+ }()
+
+ n := len(t.functab) / int(t.ptrsize) / 2
+ funcs := make([]Func, n)
+ for i := range funcs {
+ f := &funcs[i]
+ f.Entry = uint64(t.uintptr(t.functab[2*i*int(t.ptrsize):]))
+ f.End = uint64(t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):]))
+ info := t.Data[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
+ f.LineTable = t
+ f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
+ f.Sym = &Sym{
+ Value: f.Entry,
+ Type: 'T',
+ Name: t.string(t.binary.Uint32(info[t.ptrsize:])),
+ GoType: 0,
+ Func: f,
+ }
+ }
+ return funcs
+}
+
// findFunc returns the func corresponding to the given program counter.
func (t *LineTable) findFunc(pc uint64) []byte {
if pc < t.uintptr(t.functab) || pc >= t.uintptr(t.functab[len(t.functab)-int(t.ptrsize):]) {
diff --git a/libgo/go/debug/gosym/symtab.go b/libgo/go/debug/gosym/symtab.go
index 9ab05bac2f7..3864e3cb4fa 100644
--- a/libgo/go/debug/gosym/symtab.go
+++ b/libgo/go/debug/gosym/symtab.go
@@ -129,6 +129,9 @@ var (
)
func walksymtab(data []byte, fn func(sym) error) error {
+ if len(data) == 0 { // missing symtab is okay
+ return nil
+ }
var order binary.ByteOrder = binary.BigEndian
newTable := false
switch {
@@ -455,6 +458,10 @@ func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
i = end - 1 // loop will i++
}
}
+
+ if t.go12line != nil && nf == 0 {
+ t.Funcs = t.go12line.go12Funcs()
+ }
if obj != nil {
obj.Funcs = t.Funcs[lastf:]
}
diff --git a/libgo/go/debug/macho/fat.go b/libgo/go/debug/macho/fat.go
new file mode 100644
index 00000000000..93b8315263c
--- /dev/null
+++ b/libgo/go/debug/macho/fat.go
@@ -0,0 +1,146 @@
+// Copyright 2014 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 macho
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+)
+
+// A FatFile is a Mach-O universal binary that contains at least one architecture.
+type FatFile struct {
+ Magic uint32
+ Arches []FatArch
+ closer io.Closer
+}
+
+// A FatArchHeader represents a fat header for a specific image architecture.
+type FatArchHeader struct {
+ Cpu Cpu
+ SubCpu uint32
+ Offset uint32
+ Size uint32
+ Align uint32
+}
+
+const fatArchHeaderSize = 5 * 4
+
+// A FatArch is a Mach-O File inside a FatFile.
+type FatArch struct {
+ FatArchHeader
+ *File
+}
+
+// ErrNotFat is returned from NewFatFile or OpenFat when the file is not a
+// universal binary but may be a thin binary, based on its magic number.
+var ErrNotFat = &FormatError{0, "not a fat Mach-O file", nil}
+
+// NewFatFile creates a new FatFile for accessing all the Mach-O images in a
+// universal binary. The Mach-O binary is expected to start at position 0 in
+// the ReaderAt.
+func NewFatFile(r io.ReaderAt) (*FatFile, error) {
+ var ff FatFile
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+
+ // Read the fat_header struct, which is always in big endian.
+ // Start with the magic number.
+ err := binary.Read(sr, binary.BigEndian, &ff.Magic)
+ if err != nil {
+ return nil, &FormatError{0, "error reading magic number", nil}
+ } else if ff.Magic != MagicFat {
+ // See if this is a Mach-O file via its magic number. The magic
+ // must be converted to little endian first though.
+ var buf [4]byte
+ binary.BigEndian.PutUint32(buf[:], ff.Magic)
+ leMagic := binary.LittleEndian.Uint32(buf[:])
+ if leMagic == Magic32 || leMagic == Magic64 {
+ return nil, ErrNotFat
+ } else {
+ return nil, &FormatError{0, "invalid magic number", nil}
+ }
+ }
+ offset := int64(4)
+
+ // Read the number of FatArchHeaders that come after the fat_header.
+ var narch uint32
+ err = binary.Read(sr, binary.BigEndian, &narch)
+ if err != nil {
+ return nil, &FormatError{offset, "invalid fat_header", nil}
+ }
+ offset += 4
+
+ if narch < 1 {
+ return nil, &FormatError{offset, "file contains no images", nil}
+ }
+
+ // Combine the Cpu and SubCpu (both uint32) into a uint64 to make sure
+ // there are not duplicate architectures.
+ seenArches := make(map[uint64]bool, narch)
+ // Make sure that all images are for the same MH_ type.
+ var machoType Type
+
+ // Following the fat_header comes narch fat_arch structs that index
+ // Mach-O images further in the file.
+ ff.Arches = make([]FatArch, narch)
+ for i := uint32(0); i < narch; i++ {
+ fa := &ff.Arches[i]
+ err = binary.Read(sr, binary.BigEndian, &fa.FatArchHeader)
+ if err != nil {
+ return nil, &FormatError{offset, "invalid fat_arch header", nil}
+ }
+ offset += fatArchHeaderSize
+
+ fr := io.NewSectionReader(r, int64(fa.Offset), int64(fa.Size))
+ fa.File, err = NewFile(fr)
+ if err != nil {
+ return nil, err
+ }
+
+ // Make sure the architecture for this image is not duplicate.
+ seenArch := (uint64(fa.Cpu) << 32) | uint64(fa.SubCpu)
+ if o, k := seenArches[seenArch]; o || k {
+ return nil, &FormatError{offset, fmt.Sprintf("duplicate architecture cpu=%v, subcpu=%#x", fa.Cpu, fa.SubCpu), nil}
+ }
+ seenArches[seenArch] = true
+
+ // Make sure the Mach-O type matches that of the first image.
+ if i == 0 {
+ machoType = fa.Type
+ } else {
+ if fa.Type != machoType {
+ return nil, &FormatError{offset, fmt.Sprintf("Mach-O type for architecture #%d (type=%#x) does not match first (type=%#x)", i, fa.Type, machoType), nil}
+ }
+ }
+ }
+
+ return &ff, nil
+}
+
+// OpenFat opens the named file using os.Open and prepares it for use as a Mach-O
+// universal binary.
+func OpenFat(name string) (ff *FatFile, err error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ ff, err = NewFatFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return
+}
+
+func (ff *FatFile) Close() error {
+ var err error
+ if ff.closer != nil {
+ err = ff.closer.Close()
+ ff.closer = nil
+ }
+ return err
+}
diff --git a/libgo/go/debug/macho/file.go b/libgo/go/debug/macho/file.go
index 9d912e7a087..ed9b2a69120 100644
--- a/libgo/go/debug/macho/file.go
+++ b/libgo/go/debug/macho/file.go
@@ -74,6 +74,9 @@ type Segment struct {
func (s *Segment) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
return dat[0:n], err
}
@@ -109,6 +112,9 @@ type Section struct {
func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
return dat[0:n], err
}
@@ -246,7 +252,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdDylib:
var hdr DylibCmd
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &hdr); err != nil {
return nil, err
}
@@ -263,7 +269,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdSymtab:
var hdr SymtabCmd
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &hdr); err != nil {
return nil, err
}
@@ -290,7 +296,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdDysymtab:
var hdr DysymtabCmd
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &hdr); err != nil {
return nil, err
}
@@ -299,7 +305,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
return nil, err
}
x := make([]uint32, hdr.Nindirectsyms)
- if err := binary.Read(bytes.NewBuffer(dat), bo, x); err != nil {
+ if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil {
return nil, err
}
st := new(Dysymtab)
@@ -311,7 +317,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdSegment:
var seg32 Segment32
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &seg32); err != nil {
return nil, err
}
@@ -349,7 +355,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
case LoadCmdSegment64:
var seg64 Segment64
- b := bytes.NewBuffer(cmddat)
+ b := bytes.NewReader(cmddat)
if err := binary.Read(b, bo, &seg64); err != nil {
return nil, err
}
@@ -396,7 +402,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {
bo := f.ByteOrder
symtab := make([]Symbol, hdr.Nsyms)
- b := bytes.NewBuffer(symdat)
+ b := bytes.NewReader(symdat)
for i := range symtab {
var n Nlist64
if f.Magic == Magic64 {
diff --git a/libgo/go/debug/macho/file_test.go b/libgo/go/debug/macho/file_test.go
index 640225b3291..0de9184c227 100644
--- a/libgo/go/debug/macho/file_test.go
+++ b/libgo/go/debug/macho/file_test.go
@@ -165,3 +165,46 @@ func TestOpenFailure(t *testing.T) {
t.Errorf("open %s: succeeded unexpectedly", filename)
}
}
+
+func TestOpenFat(t *testing.T) {
+ ff, err := OpenFat("testdata/fat-gcc-386-amd64-darwin-exec")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if ff.Magic != MagicFat {
+ t.Errorf("OpenFat: got magic number %#x, want %#x", ff.Magic, MagicFat)
+ }
+ if len(ff.Arches) != 2 {
+ t.Errorf("OpenFat: got %d architectures, want 2", len(ff.Arches))
+ }
+
+ for i := range ff.Arches {
+ arch := &ff.Arches[i]
+ ftArch := &fileTests[i]
+
+ if arch.Cpu != ftArch.hdr.Cpu || arch.SubCpu != ftArch.hdr.SubCpu {
+ t.Error("OpenFat: architecture #%d got cpu=%#x subtype=%#x, expected cpu=%#x, subtype=%#x", i, arch.Cpu, arch.SubCpu, ftArch.hdr.Cpu, ftArch.hdr.SubCpu)
+ }
+
+ if !reflect.DeepEqual(arch.FileHeader, ftArch.hdr) {
+ t.Errorf("OpenFat header:\n\tgot %#v\n\twant %#v\n", arch.FileHeader, ftArch.hdr)
+ }
+ }
+}
+
+func TestOpenFatFailure(t *testing.T) {
+ filename := "file.go" // not a Mach-O file
+ if _, err := OpenFat(filename); err == nil {
+ t.Errorf("OpenFat %s: succeeded unexpectedly", filename)
+ }
+
+ filename = "testdata/gcc-386-darwin-exec" // not a fat Mach-O
+ ff, err := OpenFat(filename)
+ if err != ErrNotFat {
+ t.Errorf("OpenFat %s: got %v, want ErrNotFat", err)
+ }
+ if ff != nil {
+ t.Errorf("OpenFat %s: got %v, want nil", ff)
+ }
+}
diff --git a/libgo/go/debug/macho/macho.go b/libgo/go/debug/macho/macho.go
index bc14226c565..09f4d0ec91c 100644
--- a/libgo/go/debug/macho/macho.go
+++ b/libgo/go/debug/macho/macho.go
@@ -26,16 +26,19 @@ const (
)
const (
- Magic32 uint32 = 0xfeedface
- Magic64 uint32 = 0xfeedfacf
+ Magic32 uint32 = 0xfeedface
+ Magic64 uint32 = 0xfeedfacf
+ MagicFat uint32 = 0xcafebabe
)
-// A Type is a Mach-O file type, either an object or an executable.
+// A Type is the Mach-O file type, e.g. an object file, executable, or dynamic library.
type Type uint32
const (
- TypeObj Type = 1
- TypeExec Type = 2
+ TypeObj Type = 1
+ TypeExec Type = 2
+ TypeDylib Type = 6
+ TypeBundle Type = 8
)
// A Cpu is a Mach-O cpu type.
diff --git a/libgo/go/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec b/libgo/go/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec
new file mode 100644
index 00000000000..7efd19300b2
--- /dev/null
+++ b/libgo/go/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec
Binary files differ
diff --git a/libgo/go/debug/pe/file.go b/libgo/go/debug/pe/file.go
index f521566efa7..d0005bacf38 100644
--- a/libgo/go/debug/pe/file.go
+++ b/libgo/go/debug/pe/file.go
@@ -72,6 +72,9 @@ type ImportDirectory struct {
func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
return dat[0:n], err
}
@@ -213,15 +216,15 @@ func NewFile(r io.ReaderAt) (*File, error) {
s := new(Section)
s.SectionHeader = SectionHeader{
Name: name,
- VirtualSize: uint32(sh.VirtualSize),
- VirtualAddress: uint32(sh.VirtualAddress),
- Size: uint32(sh.SizeOfRawData),
- Offset: uint32(sh.PointerToRawData),
- PointerToRelocations: uint32(sh.PointerToRelocations),
- PointerToLineNumbers: uint32(sh.PointerToLineNumbers),
- NumberOfRelocations: uint16(sh.NumberOfRelocations),
- NumberOfLineNumbers: uint16(sh.NumberOfLineNumbers),
- Characteristics: uint32(sh.Characteristics),
+ VirtualSize: sh.VirtualSize,
+ VirtualAddress: sh.VirtualAddress,
+ Size: sh.SizeOfRawData,
+ Offset: sh.PointerToRawData,
+ PointerToRelocations: sh.PointerToRelocations,
+ PointerToLineNumbers: sh.PointerToLineNumbers,
+ NumberOfRelocations: sh.NumberOfRelocations,
+ NumberOfLineNumbers: sh.NumberOfLineNumbers,
+ Characteristics: sh.Characteristics,
}
s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
s.ReaderAt = s.sr
diff --git a/libgo/go/debug/plan9obj/file.go b/libgo/go/debug/plan9obj/file.go
new file mode 100644
index 00000000000..a4c95a92a5c
--- /dev/null
+++ b/libgo/go/debug/plan9obj/file.go
@@ -0,0 +1,346 @@
+// Copyright 2014 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 plan9obj implements access to Plan 9 a.out object files.
+package plan9obj
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+)
+
+// A FileHeader represents an Plan 9 a.out file header.
+type FileHeader struct {
+ Ptrsz int
+}
+
+// A File represents an open Plan 9 a.out file.
+type File struct {
+ FileHeader
+ Sections []*Section
+ closer io.Closer
+}
+
+type SectionHeader struct {
+ Name string
+ Size uint32
+ Offset uint32
+}
+
+// A Section represents a single section in an Plan 9 a.out file.
+type Section struct {
+ SectionHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the Plan 9 a.out section.
+func (s *Section) Data() ([]byte, error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the Plan 9 a.out section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+// A ProgHeader represents a single Plan 9 a.out program header.
+type ProgHeader struct {
+ Magic uint32
+ Text uint32
+ Data uint32
+ Bss uint32
+ Syms uint32
+ Entry uint64
+ Spsz uint32
+ Pcsz uint32
+}
+
+// A Prog represents the program header in an Plan 9 a.out binary.
+type Prog struct {
+ ProgHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Open returns a new ReadSeeker reading the Plan 9 a.out program body.
+func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
+
+// A Symbol represents an entry in a Plan 9 a.out symbol table section.
+type Sym struct {
+ Value uint64
+ Type rune
+ Name string
+}
+
+/*
+ * Plan 9 a.out reader
+ */
+
+type FormatError struct {
+ off int
+ msg string
+ val interface{}
+}
+
+func (e *FormatError) Error() string {
+ msg := e.msg
+ if e.val != nil {
+ msg += fmt.Sprintf(" '%v'", e.val)
+ }
+ msg += fmt.Sprintf(" in record at byte %#x", e.off)
+ return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as an Plan 9 a.out binary.
+func Open(name string) (*File, error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ ff, err := NewFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() error {
+ var err error
+ if f.closer != nil {
+ err = f.closer.Close()
+ f.closer = nil
+ }
+ return err
+}
+
+func parseMagic(magic [4]byte) (*ExecTable, error) {
+ for _, e := range exectab {
+ if string(magic[:]) == e.Magic {
+ return &e, nil
+ }
+ }
+ return nil, &FormatError{0, "bad magic number", magic[:]}
+}
+
+// NewFile creates a new File for accessing an Plan 9 binary in an underlying reader.
+// The Plan 9 binary is expected to start at position 0 in the ReaderAt.
+func NewFile(r io.ReaderAt) (*File, error) {
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+ // Read and decode Plan 9 magic
+ var magic [4]byte
+ if _, err := r.ReadAt(magic[:], 0); err != nil {
+ return nil, err
+ }
+ mp, err := parseMagic(magic)
+ if err != nil {
+ return nil, err
+ }
+
+ f := &File{FileHeader{mp.Ptrsz}, nil, nil}
+
+ ph := new(prog)
+ if err := binary.Read(sr, binary.BigEndian, ph); err != nil {
+ return nil, err
+ }
+
+ p := new(Prog)
+ p.ProgHeader = ProgHeader{
+ Magic: ph.Magic,
+ Text: ph.Text,
+ Data: ph.Data,
+ Bss: ph.Bss,
+ Syms: ph.Syms,
+ Entry: uint64(ph.Entry),
+ Spsz: ph.Spsz,
+ Pcsz: ph.Pcsz,
+ }
+
+ if mp.Ptrsz == 8 {
+ if err := binary.Read(sr, binary.BigEndian, &p.Entry); err != nil {
+ return nil, err
+ }
+ }
+
+ var sects = []struct {
+ name string
+ size uint32
+ }{
+ {"text", ph.Text},
+ {"data", ph.Data},
+ {"syms", ph.Syms},
+ {"spsz", ph.Spsz},
+ {"pcsz", ph.Pcsz},
+ }
+
+ f.Sections = make([]*Section, 5)
+
+ off := mp.Hsize
+
+ for i, sect := range sects {
+ s := new(Section)
+ s.SectionHeader = SectionHeader{
+ Name: sect.name,
+ Size: sect.size,
+ Offset: off,
+ }
+ off += sect.size
+ s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
+ s.ReaderAt = s.sr
+ f.Sections[i] = s
+ }
+
+ return f, nil
+}
+
+func walksymtab(data []byte, ptrsz int, fn func(sym) error) error {
+ var order binary.ByteOrder = binary.BigEndian
+ var s sym
+ p := data
+ for len(p) >= 4 {
+ // Symbol type, value.
+ if len(p) < ptrsz {
+ return &FormatError{len(data), "unexpected EOF", nil}
+ }
+ // fixed-width value
+ if ptrsz == 8 {
+ s.value = order.Uint64(p[0:8])
+ p = p[8:]
+ } else {
+ s.value = uint64(order.Uint32(p[0:4]))
+ p = p[4:]
+ }
+
+ var typ byte
+ typ = p[0] & 0x7F
+ s.typ = typ
+ p = p[1:]
+
+ // Name.
+ var i int
+ var nnul int
+ for i = 0; i < len(p); i++ {
+ if p[i] == 0 {
+ nnul = 1
+ break
+ }
+ }
+ switch typ {
+ case 'z', 'Z':
+ p = p[i+nnul:]
+ for i = 0; i+2 <= len(p); i += 2 {
+ if p[i] == 0 && p[i+1] == 0 {
+ nnul = 2
+ break
+ }
+ }
+ }
+ if len(p) < i+nnul {
+ return &FormatError{len(data), "unexpected EOF", nil}
+ }
+ s.name = p[0:i]
+ i += nnul
+ p = p[i:]
+
+ fn(s)
+ }
+ return nil
+}
+
+// NewTable decodes the Go symbol table in data,
+// returning an in-memory representation.
+func newTable(symtab []byte, ptrsz int) ([]Sym, error) {
+ var n int
+ err := walksymtab(symtab, ptrsz, func(s sym) error {
+ n++
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ fname := make(map[uint16]string)
+ syms := make([]Sym, 0, n)
+ err = walksymtab(symtab, ptrsz, func(s sym) error {
+ n := len(syms)
+ syms = syms[0 : n+1]
+ ts := &syms[n]
+ ts.Type = rune(s.typ)
+ ts.Value = s.value
+ switch s.typ {
+ default:
+ ts.Name = string(s.name[:])
+ case 'z', 'Z':
+ for i := 0; i < len(s.name); i += 2 {
+ eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
+ elt, ok := fname[eltIdx]
+ if !ok {
+ return &FormatError{-1, "bad filename code", eltIdx}
+ }
+ if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
+ ts.Name += "/"
+ }
+ ts.Name += elt
+ }
+ }
+ switch s.typ {
+ case 'f':
+ fname[uint16(s.value)] = ts.Name
+ }
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return syms, nil
+}
+
+// Symbols returns the symbol table for f.
+func (f *File) Symbols() ([]Sym, error) {
+ symtabSection := f.Section("syms")
+ if symtabSection == nil {
+ return nil, errors.New("no symbol section")
+ }
+
+ symtab, err := symtabSection.Data()
+ if err != nil {
+ return nil, errors.New("cannot load symbol section")
+ }
+
+ return newTable(symtab, f.Ptrsz)
+}
+
+// Section returns a section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+ for _, s := range f.Sections {
+ if s.Name == name {
+ return s
+ }
+ }
+ return nil
+}
diff --git a/libgo/go/debug/plan9obj/file_test.go b/libgo/go/debug/plan9obj/file_test.go
new file mode 100644
index 00000000000..cc1db409295
--- /dev/null
+++ b/libgo/go/debug/plan9obj/file_test.go
@@ -0,0 +1,81 @@
+// Copyright 2014 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 plan9obj
+
+import (
+ "reflect"
+ "testing"
+)
+
+type fileTest struct {
+ file string
+ hdr FileHeader
+ sections []*SectionHeader
+}
+
+var fileTests = []fileTest{
+ {
+ "testdata/386-plan9-exec",
+ FileHeader{4},
+ []*SectionHeader{
+ {"text", 0x4c5f, 0x20},
+ {"data", 0x94c, 0x4c7f},
+ {"syms", 0x2c2b, 0x55cb},
+ {"spsz", 0x0, 0x81f6},
+ {"pcsz", 0xf7a, 0x81f6},
+ },
+ },
+ {
+ "testdata/amd64-plan9-exec",
+ FileHeader{8},
+ []*SectionHeader{
+ {"text", 0x4213, 0x28},
+ {"data", 0xa80, 0x423b},
+ {"syms", 0x2c8c, 0x4cbb},
+ {"spsz", 0x0, 0x7947},
+ {"pcsz", 0xca0, 0x7947},
+ },
+ },
+}
+
+func TestOpen(t *testing.T) {
+ for i := range fileTests {
+ tt := &fileTests[i]
+
+ f, err := Open(tt.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+ continue
+ }
+
+ for i, sh := range f.Sections {
+ if i >= len(tt.sections) {
+ break
+ }
+ have := &sh.SectionHeader
+ want := tt.sections[i]
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+ }
+ }
+ tn := len(tt.sections)
+ fn := len(f.Sections)
+ if tn != fn {
+ t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+ }
+ }
+}
+
+func TestOpenFailure(t *testing.T) {
+ filename := "file.go" // not a Plan 9 a.out file
+ _, err := Open(filename) // don't crash
+ if err == nil {
+ t.Errorf("open %s: succeeded unexpectedly", filename)
+ }
+}
diff --git a/libgo/go/debug/plan9obj/plan9obj.go b/libgo/go/debug/plan9obj/plan9obj.go
new file mode 100644
index 00000000000..4e3b08f4164
--- /dev/null
+++ b/libgo/go/debug/plan9obj/plan9obj.go
@@ -0,0 +1,91 @@
+// Copyright 2014 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.
+
+/*
+ * Plan 9 a.out constants and data structures
+ */
+
+package plan9obj
+
+import (
+ "bytes"
+ "encoding/binary"
+)
+
+// Plan 9 Program header.
+type prog struct {
+ Magic uint32 /* magic number */
+ Text uint32 /* size of text segment */
+ Data uint32 /* size of initialized data */
+ Bss uint32 /* size of uninitialized data */
+ Syms uint32 /* size of symbol table */
+ Entry uint32 /* entry point */
+ Spsz uint32 /* size of pc/sp offset table */
+ Pcsz uint32 /* size of pc/line number table */
+}
+
+// Plan 9 symbol table entries.
+type sym struct {
+ value uint64
+ typ byte
+ name []byte
+}
+
+const (
+ hsize = 4 * 8
+ _HDR_MAGIC = 0x00008000 /* header expansion */
+)
+
+func magic(f, b int) string {
+ buf := new(bytes.Buffer)
+ var i uint32 = uint32((f) | ((((4 * (b)) + 0) * (b)) + 7))
+ binary.Write(buf, binary.BigEndian, i)
+ return string(buf.Bytes())
+}
+
+var (
+ _A_MAGIC = magic(0, 8) /* 68020 (retired) */
+ _I_MAGIC = magic(0, 11) /* intel 386 */
+ _J_MAGIC = magic(0, 12) /* intel 960 (retired) */
+ _K_MAGIC = magic(0, 13) /* sparc */
+ _V_MAGIC = magic(0, 16) /* mips 3000 BE */
+ _X_MAGIC = magic(0, 17) /* att dsp 3210 (retired) */
+ _M_MAGIC = magic(0, 18) /* mips 4000 BE */
+ _D_MAGIC = magic(0, 19) /* amd 29000 (retired) */
+ _E_MAGIC = magic(0, 20) /* arm */
+ _Q_MAGIC = magic(0, 21) /* powerpc */
+ _N_MAGIC = magic(0, 22) /* mips 4000 LE */
+ _L_MAGIC = magic(0, 23) /* dec alpha (retired) */
+ _P_MAGIC = magic(0, 24) /* mips 3000 LE */
+ _U_MAGIC = magic(0, 25) /* sparc64 (retired) */
+ _S_MAGIC = magic(_HDR_MAGIC, 26) /* amd64 */
+ _T_MAGIC = magic(_HDR_MAGIC, 27) /* powerpc64 */
+ _R_MAGIC = magic(_HDR_MAGIC, 28) /* arm64 */
+)
+
+type ExecTable struct {
+ Magic string
+ Ptrsz int
+ Hsize uint32
+}
+
+var exectab = []ExecTable{
+ {_A_MAGIC, 4, hsize},
+ {_I_MAGIC, 4, hsize},
+ {_J_MAGIC, 4, hsize},
+ {_K_MAGIC, 4, hsize},
+ {_V_MAGIC, 4, hsize},
+ {_X_MAGIC, 4, hsize},
+ {_M_MAGIC, 4, hsize},
+ {_D_MAGIC, 4, hsize},
+ {_E_MAGIC, 4, hsize},
+ {_Q_MAGIC, 4, hsize},
+ {_N_MAGIC, 4, hsize},
+ {_L_MAGIC, 4, hsize},
+ {_P_MAGIC, 4, hsize},
+ {_U_MAGIC, 4, hsize},
+ {_S_MAGIC, 8, hsize + 8},
+ {_T_MAGIC, 8, hsize + 8},
+ {_R_MAGIC, 8, hsize + 8},
+}
diff --git a/libgo/go/debug/plan9obj/testdata/386-plan9-exec b/libgo/go/debug/plan9obj/testdata/386-plan9-exec
new file mode 100644
index 00000000000..748e83f8e6a
--- /dev/null
+++ b/libgo/go/debug/plan9obj/testdata/386-plan9-exec
Binary files differ
diff --git a/libgo/go/debug/plan9obj/testdata/amd64-plan9-exec b/libgo/go/debug/plan9obj/testdata/amd64-plan9-exec
new file mode 100644
index 00000000000..3e257dd8ffc
--- /dev/null
+++ b/libgo/go/debug/plan9obj/testdata/amd64-plan9-exec
Binary files differ
diff --git a/libgo/go/debug/plan9obj/testdata/hello.c b/libgo/go/debug/plan9obj/testdata/hello.c
new file mode 100644
index 00000000000..c0d633e29f0
--- /dev/null
+++ b/libgo/go/debug/plan9obj/testdata/hello.c
@@ -0,0 +1,8 @@
+#include <u.h>
+#include <libc.h>
+
+void
+main(void)
+{
+ print("hello, world\n");
+}