cmd/irdump: basic disassembler

This commit is contained in:
mae
2026-02-08 00:30:43 -06:00
parent c60762fe85
commit 58431161b5
2 changed files with 166 additions and 12 deletions

View File

@@ -1,13 +1,12 @@
package main
import (
"bytes"
"errors"
"io"
"log"
"os"
"hakurei.app/command"
"hakurei.app/internal/pkg"
)
func main() {
@@ -17,10 +16,12 @@ func main() {
var (
flagOutput string
flagReal bool
flagHeader bool
flagForce bool
)
c := command.New(os.Stderr, log.Printf, "irdump", func(args []string) (err error) {
var input *os.File
if len(args) < 1 {
if len(args) != 1 {
return errors.New("irdump requires 1 argument")
}
if input, err = os.Open(args[0]); err != nil {
@@ -38,12 +39,8 @@ func main() {
}
}
inputData := bytes.NewBuffer(nil)
if _, err = io.Copy(inputData, input); err != nil {
return
}
var out string
if out, err = Disassemble(inputData.Bytes(), flagReal); err != nil {
if out, err = pkg.Disassemble(input, flagReal, flagHeader, flagForce); err != nil {
return
}
if _, err = output.WriteString(out); err != nil {
@@ -57,12 +54,18 @@ func main() {
).Flag(
&flagReal,
"r", command.BoolFlag(false),
"skip label generation; idents print real value")
"skip label generation; idents print real value",
).Flag(
&flagHeader,
"h", command.BoolFlag(false),
"display artifact headers",
).Flag(
&flagForce,
"f", command.BoolFlag(false),
"force display (skip validations)",
)
c.MustParse(os.Args[1:], func(err error) {
log.Fatal(err)
})
}
func Disassemble(ir []byte, real bool) (string, error) {
return "hello world", nil
}

151
internal/pkg/asm.go Normal file
View File

@@ -0,0 +1,151 @@
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)
}
}