Skip to content

Commit

Permalink
sym: add support for overlay symbol
Browse files Browse the repository at this point in the history
  • Loading branch information
mewmew committed Jul 5, 2018
0 parents commit 9ca85fc
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sym
20 changes: 20 additions & 0 deletions cmd/sym_dump/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package main

import (
"flag"
"fmt"
"log"

"github.com/sanctuary/sym"
)

func main() {
flag.Parse()
for _, path := range flag.Args() {
f, err := sym.ParseFile(path)
fmt.Println(f)
if err != nil {
log.Fatalf("%+v", err)
}
}
}
11 changes: 11 additions & 0 deletions kind.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package sym

//go:generate stringer -linecomment -type Kind

// Kind specifies the kind of a symbol.
type Kind uint8

// Symbol kinds.
const (
KindOverlay Kind = 0x98 // overlay
)
17 changes: 17 additions & 0 deletions kind_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

112 changes: 112 additions & 0 deletions sym.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Package sym provides access to Playstation 1 symbol files (*.SYM).
package sym

import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
"io"
"os"
"strings"

"github.com/lunixbochs/struc"
"github.com/pkg/errors"
)

// A File is PS1 symbol file.
type File struct {
// File header.
Hdr *FileHeader
// Symbols.
Syms []*Symbol
}

// String returns the string representation of the symbol file.
func (f *File) String() string {
buf := &strings.Builder{}
offset := 0
buf.WriteString(f.Hdr.String())
offset += binary.Size(*f.Hdr)
for _, sym := range f.Syms {
fmt.Fprintf(buf, "%06x: %s\n", offset, sym)
offset += sym.Size()
}
return buf.String()
}

// A FileHeader is a PS1 symbol file header.
type FileHeader struct {
// File signature; MND.
Signature [3]byte `struc:"[3]byte"`
// File format version.
Version uint8 `struc:"uint8,little"`
// Target unit.
TargetUnit uint32 `struc:"uint32,little"`
}

// String returns the string representation of the symbol file header.
func (hdr *FileHeader) String() string {
const format = `
Header : %s version %d
Target unit %d
`
return fmt.Sprintf(format, hdr.Signature, hdr.Version, hdr.TargetUnit)
}

// ParseFile parses the given PS1 symbol file.
func ParseFile(path string) (*File, error) {
f, err := os.Open(path)
if err != nil {
return nil, errors.WithStack(err)
}
defer f.Close()
return Parse(f)
}

// ParseBytes parses the given PS1 symbol file, reading from b.
func ParseBytes(b []byte) (*File, error) {
return Parse(bytes.NewReader(b))
}

// Parse parses the given PS1 symbol file, reading from r.
func Parse(r io.Reader) (*File, error) {
// Parse file header.
f := &File{}
br := bufio.NewReader(r)
hdr, err := parseFileHeader(br)
if err != nil {
return nil, errors.WithStack(err)
}
f.Hdr = hdr

// Parse symbols.
for {
sym, err := parseSymbol(br)
if err != nil {
if errors.Cause(err) == io.EOF {
break
}
return f, errors.WithStack(err)
}
f.Syms = append(f.Syms, sym)
}

return f, nil
}

// parseFileHeader parses and returns a PS1 symbol file header.
func parseFileHeader(r io.Reader) (*FileHeader, error) {
hdr := &FileHeader{}
if err := struc.Unpack(r, &hdr); err != nil {
return nil, errors.WithStack(err)
}
// Verify Smacker signature.
switch string(hdr.Signature[:]) {
case "MND":
// valid signature.
default:
return nil, errors.Errorf(`invalid SYM signature; expected "MND", got %q`, hdr.Signature)
}
return hdr, nil
}
114 changes: 114 additions & 0 deletions symbol.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package sym

import (
"encoding/binary"
"fmt"
"io"

"github.com/lunixbochs/struc"
"github.com/pkg/errors"
)

// A Symbol is a PS1 symbol.
type Symbol struct {
// Symbol header.
Hdr *SymbolHeader
// Symbol body.
Body SymbolBody
}

// String returns the string representation of the symbol.
func (sym *Symbol) String() string {
return fmt.Sprintf("%v %v", sym.Hdr, sym.Body)
}

// Size returns the size of the symbol in bytes.
func (sym *Symbol) Size() int {
return binary.Size(*sym.Hdr) + sym.Body.Size()
}

// A SymbolHeader is a PS1 symbol header.
type SymbolHeader struct {
// Address or value of symbol.
Value uint32 `struc:"uint32,little"`
// Symbol kind; specifies type of symbol body.
Kind Kind `struc:"uint8,little"`
}

// String returns the string representation of the symbol header.
func (hdr *SymbolHeader) String() string {
return fmt.Sprintf("$%08x %v", hdr.Value, hdr.Kind)
}

// SymbolBody is the sum-type of all symbol bodies.
type SymbolBody interface {
// Size returns the size of the symbol body in bytes.
Size() int
}

// parseSymbol parses and returns a PS1 symbol.
func parseSymbol(r io.Reader) (*Symbol, error) {
// Parse symbol header.
sym := &Symbol{}
hdr, err := parseSymbolHeader(r)
if err != nil {
return nil, errors.WithStack(err)
}
sym.Hdr = hdr

// Parse symbol body.
body, err := parseSymbolBody(r, hdr.Kind)
if err != nil {
return sym, errors.WithStack(err)
}
sym.Body = body

return sym, nil
}

// parseSymbolHeader parses and returns a PS1 symbol header.
func parseSymbolHeader(r io.Reader) (*SymbolHeader, error) {
hdr := &SymbolHeader{}
if err := struc.Unpack(r, &hdr); err != nil {
return nil, errors.WithStack(err)
}
return hdr, nil
}

// parseSymbolBody parses and returns a PS1 symbol body.
func parseSymbolBody(r io.Reader, kind Kind) (SymbolBody, error) {
parse := func(body SymbolBody) (SymbolBody, error) {
if err := struc.Unpack(r, body); err != nil {
return nil, errors.WithStack(err)
}
return body, nil
}
switch kind {
case KindOverlay:
return parse(&Overlay{})
default:
return nil, errors.Errorf("support for symbol kind 0x%02X not yet implemented", uint8(kind))
}
}

// An Overlay specifies the length and id of an file overlay (e.g. a shared
// library).
//
// Value of the symbol header specifies the base address at which the overlay is
// loaded.
type Overlay struct {
// Overlay length in bytes.
Length uint32 `struc:"uint32,little"`
// Overlay ID.
ID uint32 `struc:"uint32,little"`
}

// String returns the string representation of the overlay symbol.
func (body *Overlay) String() string {
return fmt.Sprintf("length $%08x id $%x", body.Length, body.ID)
}

// Size returns the size of the symbol body in bytes.
func (body *Overlay) Size() int {
return binary.Size(*body)
}

0 comments on commit 9ca85fc

Please sign in to comment.