Files
hakurei/internal/pkg/asm.go
2026-02-08 03:09:19 -06:00

152 lines
3.2 KiB
Go

package pkg
import (
"encoding/binary"
"fmt"
"io"
"strconv"
"strings"
)
func Disassemble(r io.Reader, real bool, showHeader bool, force bool) (s string, err error) {
var values [][2]string
sb := new(strings.Builder)
header := true
for err == nil {
if header {
var kind uint64
var size uint64
hsb := new(strings.Builder)
if kind, err = nextUint64(r); err != nil {
break
}
if size, err = nextUint64(r); err != nil {
break
}
for i := 0; uint64(i) < size; i++ {
var did Checksum
var dkind uint64
if dkind, err = nextUint64(r); err != nil {
break
}
if did, err = nextIdent(r); err != nil {
break
}
hsb.WriteString(fmt.Sprintf("\t\t\t%s\t%s\n", intToKind(dkind), Encode(did)))
}
header = false
if showHeader {
values = append(values, [2]string{"head", fmt.Sprintf("%s [\n%s]", intToKind(kind), hsb.String())})
}
}
var k uint32
if k, err = nextUint32(r); err != nil {
break
}
kind := IRValueKind(k)
switch kind {
case IRKindEnd:
var a uint32
if a, err = nextUint32(r); err != nil {
break
}
if a&1 != 0 {
var sum Checksum
if sum, err = nextIdent(r); err != nil {
break
}
values = append(values, [2]string{"end", Encode(sum)})
} else {
values = append(values, [2]string{"end", ""})
}
header = true
continue
case IRKindIdent:
// discard ancillary
if _, err = nextUint32(r); err != nil {
break
}
var sum Checksum
if sum, err = nextIdent(r); err != nil {
break
}
values = append(values, [2]string{"id", Encode(sum)})
continue
case IRKindUint32:
var i uint32
if i, err = nextUint32(r); err != nil {
break
}
values = append(values, [2]string{"int", strconv.FormatUint(uint64(i), 10)})
case IRKindString:
var l uint32
if l, err = nextUint32(r); err != nil {
break
}
s := make([]byte, l+(wordSize-(l)%wordSize)%wordSize)
if _, err = r.Read(s); err != nil {
break
}
values = append(values, [2]string{"str", fmt.Sprintf("\"%s\"", string(s[:l]))})
continue
default:
var i uint32
if i, err = nextUint32(r); err != nil {
break
}
values = append(values, [2]string{fmt.Sprintf("$%x", uint32(kind)), strconv.FormatUint(uint64(i), 10)})
}
}
if err != io.EOF {
return
}
err = nil
for i := 0; i < len(values); i++ {
sb.WriteString(fmt.Sprintf("%s\t\t%s\n", values[i][0], values[i][1]))
}
return sb.String(), err
}
func nextUint32(r io.Reader) (uint32, error) {
i := make([]byte, 4)
_, err := r.Read(i)
if err != nil {
return 0, err
}
return binary.LittleEndian.Uint32(i), nil
}
func nextUint64(r io.Reader) (uint64, error) {
i := make([]byte, 8)
_, err := r.Read(i)
if err != nil {
return 0, err
}
return binary.LittleEndian.Uint64(i), nil
}
func nextIdent(r io.Reader) (Checksum, error) {
i := make([]byte, 48)
if _, err := r.Read(i); err != nil {
return Checksum{}, err
}
return Checksum(i), nil
}
func intToKind(i uint64) string {
switch Kind(i) {
case KindHTTPGet:
return "http_get"
case KindTar:
return "tar"
case KindExec:
return "exec"
case KindExecNet:
return "exec_net"
case KindFile:
return "file"
default:
return fmt.Sprintf("$%d", i-KindCustomOffset)
}
}