141 lines
2.8 KiB
Go
141 lines
2.8 KiB
Go
package wasmobj
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/tetratelabs/wabin/binary"
|
|
"github.com/tetratelabs/wabin/wasm"
|
|
|
|
"loov.dev/lensm/internal/disasm"
|
|
)
|
|
|
|
var _ disasm.File = (*File)(nil)
|
|
var _ disasm.Func = (*Func)(nil)
|
|
|
|
// File contains information about the object file.
|
|
type File struct {
|
|
module *wasm.Module
|
|
|
|
funcs []disasm.Func
|
|
}
|
|
|
|
func (file *File) Funcs() []disasm.Func { return file.funcs }
|
|
|
|
// Func contains information about the executable.
|
|
type Func struct {
|
|
obj *File
|
|
index wasm.Index
|
|
name string
|
|
code *wasm.Code
|
|
sortName string
|
|
}
|
|
|
|
func (fn *Func) Name() string { return fn.name }
|
|
|
|
func (file *File) Close() error {
|
|
return nil
|
|
}
|
|
|
|
func Load(path string) (*File, error) {
|
|
obj := &File{}
|
|
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
module, err := binary.DecodeModule(data, wasm.CoreFeaturesV2)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
obj.module = module
|
|
|
|
for i, fnname := range module.NameSection.FunctionNames {
|
|
code := module.CodeSection[i]
|
|
sym := &Func{
|
|
obj: obj,
|
|
index: fnname.Index,
|
|
name: fnname.Name,
|
|
code: code,
|
|
sortName: strings.ToLower(fnname.Name),
|
|
}
|
|
obj.funcs = append(obj.funcs, sym)
|
|
}
|
|
|
|
sort.SliceStable(obj.funcs, func(i, k int) bool {
|
|
return strings.ToLower(obj.funcs[i].Name()) < strings.ToLower(obj.funcs[k].Name())
|
|
})
|
|
|
|
return obj, nil
|
|
}
|
|
|
|
func (fn *Func) Load(opts disasm.Options) (*disasm.Code, error) {
|
|
return fn.obj.LoadCode(fn, opts), nil
|
|
}
|
|
|
|
func (file *File) LoadCode(fn *Func, opts disasm.Options) *disasm.Code {
|
|
code := &disasm.Code{
|
|
Name: fn.name,
|
|
}
|
|
|
|
// TODO: https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-instr
|
|
|
|
for i, b := range fn.code.Body {
|
|
code.Insts = append(code.Insts, disasm.Inst{
|
|
PC: uint64(i),
|
|
Text: fmt.Sprintf("BYTE 0x%02x", b),
|
|
})
|
|
}
|
|
return code
|
|
}
|
|
|
|
/*
|
|
func (file *File) LoadCode(fn *Func, opts disasm.Options) *disasm.Code {
|
|
dis, err := wasmdisasm.NewDisassembly(*fn.fn, file.module)
|
|
if err != nil {
|
|
return &disasm.Code{Name: err.Error()}
|
|
}
|
|
|
|
code := &disasm.Code{
|
|
Name: fn.fn.Name,
|
|
}
|
|
|
|
for i, ix := range dis.Code {
|
|
code.Insts = append(code.Insts, file.toInstr(dis, i, ix))
|
|
}
|
|
|
|
return code
|
|
}
|
|
func (file *File) toInstr(dis *wasmdisasm.Disassembly, i int, ix wasmdisasm.Instr) disasm.Inst {
|
|
inst := disasm.Inst{
|
|
PC: uint64(i),
|
|
Text: ix.Op.Name + " " + file.immediatesToString(ix.Immediates),
|
|
}
|
|
|
|
switch ix.Op.Code {
|
|
case operators.Call:
|
|
target := ix.Immediates[0].(uint32)
|
|
fn := file.module.FunctionIndexSpace[target]
|
|
inst.Text = ix.Op.Name + " " + fn.Name
|
|
inst.Call = fn.Name
|
|
|
|
// TODO: figure out ix.Branches and ix.Block.IfElseIndex (similar)
|
|
default:
|
|
|
|
}
|
|
|
|
return inst
|
|
}
|
|
|
|
func (file *File) immediatesToString(xs []interface{}) string {
|
|
var str strings.Builder
|
|
for _, im := range xs {
|
|
fmt.Fprintf(&str, " %v", im)
|
|
}
|
|
return str.String()
|
|
}
|
|
*/
|