From 58431161b5fea93aef2794368a288bd3e1b34257 Mon Sep 17 00:00:00 2001 From: mae Date: Sun, 8 Feb 2026 00:30:43 -0600 Subject: [PATCH] cmd/irdump: basic disassembler --- cmd/irdump/main.go | 27 ++++---- internal/pkg/asm.go | 151 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 12 deletions(-) create mode 100644 internal/pkg/asm.go diff --git a/cmd/irdump/main.go b/cmd/irdump/main.go index 432590f..8c608ab 100644 --- a/cmd/irdump/main.go +++ b/cmd/irdump/main.go @@ -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 -} diff --git a/internal/pkg/asm.go b/internal/pkg/asm.go new file mode 100644 index 0000000..4344d01 --- /dev/null +++ b/internal/pkg/asm.go @@ -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) + } +}