Files
wazero/wasm/section.go

283 lines
6.8 KiB
Go

package wasm
import (
"errors"
"fmt"
"io"
"unicode/utf8"
"github.com/mathetake/gasm/wasm/leb128"
)
type SectionID byte
const (
SectionIDCustom SectionID = 0
SectionIDType SectionID = 1
SectionIDImport SectionID = 2
SectionIDFunction SectionID = 3
SectionIDTable SectionID = 4
SectionIDMemory SectionID = 5
SectionIDGlobal SectionID = 6
SectionIDExport SectionID = 7
SectionIDStart SectionID = 8
SectionIDElement SectionID = 9
SectionIDCode SectionID = 10
SectionIDData SectionID = 11
)
func (m *Module) readSections(r *Reader) error {
for {
b := make([]byte, 1)
if _, err := io.ReadFull(r, b); err == io.EOF {
return nil
} else if err != nil {
return fmt.Errorf("read section id: %w", err)
}
ss, _, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get size of section for id=%d: %v", SectionID(b[0]), err)
}
sectionContentStart := r.read
switch SectionID(b[0]) {
case SectionIDCustom:
err = m.readSectionCustom(r, int(ss))
case SectionIDType:
err = m.readSectionTypes(r)
case SectionIDImport:
err = m.readSectionImports(r)
case SectionIDFunction:
err = m.readSectionFunctions(r)
case SectionIDTable:
err = m.readSectionTables(r)
case SectionIDMemory:
err = m.readSectionMemories(r)
case SectionIDGlobal:
err = m.readSectionGlobals(r)
case SectionIDExport:
err = m.readSectionExports(r)
case SectionIDStart:
err = m.readSectionStart(r)
case SectionIDElement:
err = m.readSectionElement(r)
case SectionIDCode:
err = m.readSectionCodes(r)
case SectionIDData:
err = m.readSectionData(r)
default:
err = errors.New("invalid section id")
}
if err == nil && sectionContentStart+int(ss) != r.read {
err = fmt.Errorf("invalid section length: expected to be %d but got %d", ss, r.read-sectionContentStart)
}
if err != nil {
return fmt.Errorf("section ID %d: %v", b[0], err)
}
}
}
func (m *Module) readSectionCustom(r *Reader, sectionSize int) error {
nameLen, nameLenBytes, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("cannot read custom section name length")
}
nameBuf := make([]byte, nameLen)
_, err = io.ReadFull(r, nameBuf)
if err != nil {
return fmt.Errorf("cannot read custom section name: %v", err)
}
if !utf8.Valid(nameBuf) {
return fmt.Errorf("custom section name must be valid utf8")
}
contentLen := int(sectionSize) - int(nameLenBytes) - int(nameLen)
if contentLen < 0 {
return fmt.Errorf("malformed custom section %s", string(nameBuf))
}
contents := make([]byte, contentLen)
_, err = io.ReadFull(r, contents)
if err != nil {
return fmt.Errorf("cannot read custom section contents: %v", err)
}
m.CustomSections[string(nameBuf)] = contents
return nil
}
func (m *Module) readSectionTypes(r *Reader) error {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get size of vector: %v", err)
}
m.TypeSection = make([]*FunctionType, vs)
for i := range m.TypeSection {
m.TypeSection[i], err = readFunctionType(r)
if err != nil {
return fmt.Errorf("read %d-th function type: %v", i, err)
}
}
return nil
}
func (m *Module) readSectionImports(r *Reader) error {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get size of vector: %v", err)
}
m.ImportSection = make([]*ImportSegment, vs)
for i := range m.ImportSection {
m.ImportSection[i], err = readImportSegment(r)
if err != nil {
return fmt.Errorf("read import: %v", err)
}
}
return nil
}
func (m *Module) readSectionFunctions(r *Reader) error {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get size of vector: %v", err)
}
m.FunctionSection = make([]uint32, vs)
for i := range m.FunctionSection {
m.FunctionSection[i], _, err = leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get type index: %v", err)
}
}
return nil
}
func (m *Module) readSectionTables(r *Reader) error {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get size of vector: %v", err)
}
m.TableSection = make([]*TableType, vs)
for i := range m.TableSection {
m.TableSection[i], err = readTableType(r)
if err != nil {
return fmt.Errorf("read table type: %v", err)
}
}
return nil
}
func (m *Module) readSectionMemories(r *Reader) error {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get size of vector: %v", err)
}
m.MemorySection = make([]*MemoryType, vs)
for i := range m.MemorySection {
m.MemorySection[i], err = readMemoryType(r)
if err != nil {
return fmt.Errorf("read memory type: %v", err)
}
}
return nil
}
func (m *Module) readSectionGlobals(r *Reader) error {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get size of vector: %v", err)
}
m.GlobalSection = make([]*GlobalSegment, vs)
for i := range m.GlobalSection {
m.GlobalSection[i], err = readGlobalSegment(r)
if err != nil {
return fmt.Errorf("read global segment: %v ", err)
}
}
return nil
}
func (m *Module) readSectionExports(r *Reader) error {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get size of vector: %v", err)
}
m.ExportSection = make(map[string]*ExportSegment, vs)
for i := uint32(0); i < vs; i++ {
expDesc, err := readExportSegment(r)
if err != nil {
return fmt.Errorf("read export: %v", err)
}
if _, ok := m.ExportSection[expDesc.Name]; ok {
return fmt.Errorf("duplicate export name: %s", expDesc.Name)
}
m.ExportSection[expDesc.Name] = expDesc
}
return nil
}
func (m *Module) readSectionStart(r *Reader) error {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get size of vector: %v", err)
}
m.StartSection = &vs
return nil
}
func (m *Module) readSectionElement(r *Reader) error {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get size of vector: %v", err)
}
m.ElementSection = make([]*ElementSegment, vs)
for i := range m.ElementSection {
m.ElementSection[i], err = readElementSegment(r)
if err != nil {
return fmt.Errorf("read element: %v", err)
}
}
return nil
}
func (m *Module) readSectionCodes(r *Reader) error {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get size of vector: %v", err)
}
m.CodeSection = make([]*CodeSegment, vs)
for i := range m.CodeSection {
m.CodeSection[i], err = readCodeSegment(r)
if err != nil {
return fmt.Errorf("read %d-th code segment: %v", i, err)
}
}
return nil
}
func (m *Module) readSectionData(r *Reader) error {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return fmt.Errorf("get size of vector: %v", err)
}
m.DataSection = make([]*DataSegment, vs)
for i := range m.DataSection {
m.DataSection[i], err = readDataSegment(r)
if err != nil {
return fmt.Errorf("read data segment: %v", err)
}
}
return nil
}