Commit b28aa1f1 authored by David du Colombier's avatar David du Colombier Committed by Brad Fitzpatrick

debug/plan9obj: cleanup api

- Don't export Prog structure.
- Remove ProgHeader and ExecTable structures.
- Add Magic, Bss and Entry fields in FileHeader.
- Replace ?_MAGIC variables with constants.
- Ignore final EOF from ReadAt.
- Improve documentation.

Fixes #7989.

LGTM=rsc
R=rsc, bradfitz
CC=golang-codereviews
https://golang.org/cl/91400044
parent 294f9b88
...@@ -13,9 +13,12 @@ import ( ...@@ -13,9 +13,12 @@ import (
"os" "os"
) )
// A FileHeader represents an Plan 9 a.out file header. // A FileHeader represents a Plan 9 a.out file header.
type FileHeader struct { type FileHeader struct {
Ptrsz int Magic uint32
Bss uint32
Entry uint64
PtrSize int
} }
// A File represents an open Plan 9 a.out file. // A File represents an open Plan 9 a.out file.
...@@ -25,13 +28,16 @@ type File struct { ...@@ -25,13 +28,16 @@ type File struct {
closer io.Closer closer io.Closer
} }
// A SectionHeader represents a single Plan 9 a.out section header.
// This structure doesn't exist on-disk, but eases navigation
// through the object file.
type SectionHeader struct { type SectionHeader struct {
Name string Name string
Size uint32 Size uint32
Offset uint32 Offset uint32
} }
// A Section represents a single section in an Plan 9 a.out file. // A Section represents a single section in a Plan 9 a.out file.
type Section struct { type Section struct {
SectionHeader SectionHeader
...@@ -49,41 +55,15 @@ type Section struct { ...@@ -49,41 +55,15 @@ type Section struct {
func (s *Section) Data() ([]byte, error) { func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size()) dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0) n, err := s.sr.ReadAt(dat, 0)
if n == len(dat) {
err = nil
}
return dat[0:n], err return dat[0:n], err
} }
// Open returns a new ReadSeeker reading the Plan 9 a.out section. // 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) } 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. // A Symbol represents an entry in a Plan 9 a.out symbol table section.
type Sym struct { type Sym struct {
Value uint64 Value uint64
...@@ -95,13 +75,15 @@ type Sym struct { ...@@ -95,13 +75,15 @@ type Sym struct {
* Plan 9 a.out reader * Plan 9 a.out reader
*/ */
type FormatError struct { // formatError is returned by some operations if the data does
// not have the correct format for an object file.
type formatError struct {
off int off int
msg string msg string
val interface{} val interface{}
} }
func (e *FormatError) Error() string { func (e *formatError) Error() string {
msg := e.msg msg := e.msg
if e.val != nil { if e.val != nil {
msg += fmt.Sprintf(" '%v'", e.val) msg += fmt.Sprintf(" '%v'", e.val)
...@@ -110,7 +92,7 @@ func (e *FormatError) Error() string { ...@@ -110,7 +92,7 @@ func (e *FormatError) Error() string {
return msg return msg
} }
// Open opens the named file using os.Open and prepares it for use as an Plan 9 a.out binary. // Open opens the named file using os.Open and prepares it for use as a Plan 9 a.out binary.
func Open(name string) (*File, error) { func Open(name string) (*File, error) {
f, err := os.Open(name) f, err := os.Open(name)
if err != nil { if err != nil {
...@@ -137,16 +119,16 @@ func (f *File) Close() error { ...@@ -137,16 +119,16 @@ func (f *File) Close() error {
return err return err
} }
func parseMagic(magic [4]byte) (*ExecTable, error) { func parseMagic(magic []byte) (uint32, error) {
for _, e := range exectab { m := binary.BigEndian.Uint32(magic)
if string(magic[:]) == e.Magic { switch m {
return &e, nil case Magic386, MagicAMD64, MagicARM:
} return m, nil
} }
return nil, &FormatError{0, "bad magic number", magic[:]} return 0, &formatError{0, "bad magic number", magic}
} }
// NewFile creates a new File for accessing an Plan 9 binary in an underlying reader. // NewFile creates a new File for accessing a Plan 9 binary in an underlying reader.
// The Plan 9 binary is expected to start at position 0 in the ReaderAt. // The Plan 9 binary is expected to start at position 0 in the ReaderAt.
func NewFile(r io.ReaderAt) (*File, error) { func NewFile(r io.ReaderAt) (*File, error) {
sr := io.NewSectionReader(r, 0, 1<<63-1) sr := io.NewSectionReader(r, 0, 1<<63-1)
...@@ -155,34 +137,31 @@ func NewFile(r io.ReaderAt) (*File, error) { ...@@ -155,34 +137,31 @@ func NewFile(r io.ReaderAt) (*File, error) {
if _, err := r.ReadAt(magic[:], 0); err != nil { if _, err := r.ReadAt(magic[:], 0); err != nil {
return nil, err return nil, err
} }
mp, err := parseMagic(magic) _, err := parseMagic(magic[:])
if err != nil { if err != nil {
return nil, err return nil, err
} }
f := &File{FileHeader{mp.Ptrsz}, nil, nil}
ph := new(prog) ph := new(prog)
if err := binary.Read(sr, binary.BigEndian, ph); err != nil { if err := binary.Read(sr, binary.BigEndian, ph); err != nil {
return nil, err return nil, err
} }
p := new(Prog) f := &File{FileHeader: FileHeader{
p.ProgHeader = ProgHeader{
Magic: ph.Magic, Magic: ph.Magic,
Text: ph.Text,
Data: ph.Data,
Bss: ph.Bss, Bss: ph.Bss,
Syms: ph.Syms,
Entry: uint64(ph.Entry), Entry: uint64(ph.Entry),
Spsz: ph.Spsz, PtrSize: 4,
Pcsz: ph.Pcsz, }}
}
hdrSize := 4 * 8
if mp.Ptrsz == 8 { if ph.Magic&Magic64 != 0 {
if err := binary.Read(sr, binary.BigEndian, &p.Entry); err != nil { if err := binary.Read(sr, binary.BigEndian, &f.Entry); err != nil {
return nil, err return nil, err
} }
f.PtrSize = 8
hdrSize += 8
} }
var sects = []struct { var sects = []struct {
...@@ -198,7 +177,7 @@ func NewFile(r io.ReaderAt) (*File, error) { ...@@ -198,7 +177,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
f.Sections = make([]*Section, 5) f.Sections = make([]*Section, 5)
off := mp.Hsize off := uint32(hdrSize)
for i, sect := range sects { for i, sect := range sects {
s := new(Section) s := new(Section)
...@@ -208,7 +187,7 @@ func NewFile(r io.ReaderAt) (*File, error) { ...@@ -208,7 +187,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
Offset: off, Offset: off,
} }
off += sect.size off += sect.size
s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size)) s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
s.ReaderAt = s.sr s.ReaderAt = s.sr
f.Sections[i] = s f.Sections[i] = s
} }
...@@ -223,7 +202,7 @@ func walksymtab(data []byte, ptrsz int, fn func(sym) error) error { ...@@ -223,7 +202,7 @@ func walksymtab(data []byte, ptrsz int, fn func(sym) error) error {
for len(p) >= 4 { for len(p) >= 4 {
// Symbol type, value. // Symbol type, value.
if len(p) < ptrsz { if len(p) < ptrsz {
return &FormatError{len(data), "unexpected EOF", nil} return &formatError{len(data), "unexpected EOF", nil}
} }
// fixed-width value // fixed-width value
if ptrsz == 8 { if ptrsz == 8 {
...@@ -259,7 +238,7 @@ func walksymtab(data []byte, ptrsz int, fn func(sym) error) error { ...@@ -259,7 +238,7 @@ func walksymtab(data []byte, ptrsz int, fn func(sym) error) error {
} }
} }
if len(p) < i+nnul { if len(p) < i+nnul {
return &FormatError{len(data), "unexpected EOF", nil} return &formatError{len(data), "unexpected EOF", nil}
} }
s.name = p[0:i] s.name = p[0:i]
i += nnul i += nnul
...@@ -298,7 +277,7 @@ func newTable(symtab []byte, ptrsz int) ([]Sym, error) { ...@@ -298,7 +277,7 @@ func newTable(symtab []byte, ptrsz int) ([]Sym, error) {
eltIdx := binary.BigEndian.Uint16(s.name[i : i+2]) eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
elt, ok := fname[eltIdx] elt, ok := fname[eltIdx]
if !ok { if !ok {
return &FormatError{-1, "bad filename code", eltIdx} return &formatError{-1, "bad filename code", eltIdx}
} }
if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' { if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
ts.Name += "/" ts.Name += "/"
...@@ -331,7 +310,7 @@ func (f *File) Symbols() ([]Sym, error) { ...@@ -331,7 +310,7 @@ func (f *File) Symbols() ([]Sym, error) {
return nil, errors.New("cannot load symbol section") return nil, errors.New("cannot load symbol section")
} }
return newTable(symtab, f.Ptrsz) return newTable(symtab, f.PtrSize)
} }
// Section returns a section with the given name, or nil if no such // Section returns a section with the given name, or nil if no such
......
...@@ -18,7 +18,7 @@ type fileTest struct { ...@@ -18,7 +18,7 @@ type fileTest struct {
var fileTests = []fileTest{ var fileTests = []fileTest{
{ {
"testdata/386-plan9-exec", "testdata/386-plan9-exec",
FileHeader{4}, FileHeader{Magic386, 0x324, 0x14, 4},
[]*SectionHeader{ []*SectionHeader{
{"text", 0x4c5f, 0x20}, {"text", 0x4c5f, 0x20},
{"data", 0x94c, 0x4c7f}, {"data", 0x94c, 0x4c7f},
...@@ -29,7 +29,7 @@ var fileTests = []fileTest{ ...@@ -29,7 +29,7 @@ var fileTests = []fileTest{
}, },
{ {
"testdata/amd64-plan9-exec", "testdata/amd64-plan9-exec",
FileHeader{8}, FileHeader{MagicAMD64, 0x618, 0x13, 8},
[]*SectionHeader{ []*SectionHeader{
{"text", 0x4213, 0x28}, {"text", 0x4213, 0x28},
{"data", 0xa80, 0x423b}, {"data", 0xa80, 0x423b},
......
...@@ -8,11 +8,6 @@ ...@@ -8,11 +8,6 @@
package plan9obj package plan9obj
import (
"bytes"
"encoding/binary"
)
// Plan 9 Program header. // Plan 9 Program header.
type prog struct { type prog struct {
Magic uint32 /* magic number */ Magic uint32 /* magic number */
...@@ -33,59 +28,9 @@ type sym struct { ...@@ -33,59 +28,9 @@ type sym struct {
} }
const ( const (
hsize = 4 * 8 Magic64 = 0x8000 // 64-bit expanded header
_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 ( Magic386 = (4*11+0)*11 + 7
_A_MAGIC = magic(0, 8) /* 68020 (retired) */ MagicAMD64 = (4*26+0)*26 + 7 + Magic64
_I_MAGIC = magic(0, 11) /* intel 386 */ MagicARM = (4*20+0)*20 + 7
_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},
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment