diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-06-06 22:37:27 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-06-06 22:37:27 +0000 |
commit | a756a05a63c16e653903ee8078d9760185cab545 (patch) | |
tree | 2bc668fae9bf96f9a3988e0b0a16685bde8c4f0b /libgo/go/debug | |
parent | b9f71945eda675b307727a5d1b8455887ee30fee (diff) | |
download | gcc-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')
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 Binary files differnew file mode 100644 index 00000000000..3d5a5a1b162 --- /dev/null +++ b/libgo/go/debug/dwarf/testdata/typedef.elf4 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 Binary files differnew file mode 100644 index 00000000000..7efd19300b2 --- /dev/null +++ b/libgo/go/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec 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 Binary files differnew file mode 100644 index 00000000000..748e83f8e6a --- /dev/null +++ b/libgo/go/debug/plan9obj/testdata/386-plan9-exec diff --git a/libgo/go/debug/plan9obj/testdata/amd64-plan9-exec b/libgo/go/debug/plan9obj/testdata/amd64-plan9-exec Binary files differnew file mode 100644 index 00000000000..3e257dd8ffc --- /dev/null +++ b/libgo/go/debug/plan9obj/testdata/amd64-plan9-exec 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"); +} |