From 15dadee24ac02753b04465cda1bd7c6c5b163204 Mon Sep 17 00:00:00 2001 From: mae Date: Sun, 8 Feb 2026 03:09:02 -0600 Subject: [PATCH] cmd/irdump: formatted disassembly --- cmd/irdump/main.go | 9 ++- internal/pkg/asm.go | 153 +++++++++++++++++++++++++++++++------------- 2 files changed, 116 insertions(+), 46 deletions(-) diff --git a/cmd/irdump/main.go b/cmd/irdump/main.go index 8c608ab..e8faaeb 100644 --- a/cmd/irdump/main.go +++ b/cmd/irdump/main.go @@ -18,6 +18,7 @@ func main() { flagReal bool flagHeader bool flagForce bool + flagRaw bool ) c := command.New(os.Stderr, log.Printf, "irdump", func(args []string) (err error) { var input *os.File @@ -40,7 +41,7 @@ func main() { } var out string - if out, err = pkg.Disassemble(input, flagReal, flagHeader, flagForce); err != nil { + if out, err = pkg.Disassemble(input, flagReal, flagHeader, flagForce, flagRaw); err != nil { return } if _, err = output.WriteString(out); err != nil { @@ -57,12 +58,16 @@ func main() { "skip label generation; idents print real value", ).Flag( &flagHeader, - "h", command.BoolFlag(false), + "H", command.BoolFlag(false), "display artifact headers", ).Flag( &flagForce, "f", command.BoolFlag(false), "force display (skip validations)", + ).Flag( + &flagRaw, + "R", command.BoolFlag(false), + "don't format output", ) c.MustParse(os.Args[1:], func(err error) { diff --git a/internal/pkg/asm.go b/internal/pkg/asm.go index 4344d01..86fc1e4 100644 --- a/internal/pkg/asm.go +++ b/internal/pkg/asm.go @@ -8,144 +8,209 @@ import ( "strings" ) -func Disassemble(r io.Reader, real bool, showHeader bool, force bool) (s string, err error) { - var values [][2]string +type asmOutLine struct { + pos int + word int + kindData int64 + valueData []byte + indent int + kind string + value string +} + +var spacingLine = asmOutLine{ + pos: -1, + kindData: -1, + valueData: nil, + indent: 0, + kind: "", + value: "", +} + +func Disassemble(r io.Reader, real bool, showHeader bool, force bool, raw bool) (s string, err error) { + var lines []asmOutLine sb := new(strings.Builder) header := true + pos := new(int) + for err == nil { if header { var kind uint64 var size uint64 - hsb := new(strings.Builder) - - if kind, err = nextUint64(r); err != nil { + var bsize []byte + p := *pos + if _, kind, err = nextUint64(r, pos); err != nil { break } - if size, err = nextUint64(r); err != nil { + if bsize, size, err = nextUint64(r, pos); err != nil { break } + if showHeader { + lines = append(lines, asmOutLine{p, 8, int64(kind), bsize, 0, "head " + intToKind(kind), ""}) + } for i := 0; uint64(i) < size; i++ { var did Checksum var dkind uint64 - if dkind, err = nextUint64(r); err != nil { + p := *pos + if _, dkind, err = nextUint64(r, pos); err != nil { break } - if did, err = nextIdent(r); err != nil { + if _, did, err = nextIdent(r, pos); err != nil { break } - - hsb.WriteString(fmt.Sprintf("\t\t\t%s\t%s\n", intToKind(dkind), Encode(did))) + if showHeader { + lines = append(lines, asmOutLine{p, 8, int64(dkind), nil, 1, 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 { + p := *pos + if _, k, err = nextUint32(r, pos); err != nil { break } kind := IRValueKind(k) switch kind { case IRKindEnd: var a uint32 - if a, err = nextUint32(r); err != nil { + var ba []byte + if ba, a, err = nextUint32(r, pos); err != nil { break } if a&1 != 0 { var sum Checksum - if sum, err = nextIdent(r); err != nil { + if _, sum, err = nextIdent(r, pos); err != nil { break } - values = append(values, [2]string{"end", Encode(sum)}) + lines = append(lines, asmOutLine{p, 4, int64(kind), ba, 1, "end ", Encode(sum)}) } else { - values = append(values, [2]string{"end", ""}) + lines = append(lines, asmOutLine{p, 4, int64(kind), []byte{0, 0, 0, 0}, 1, "end ", ""}) } + lines = append(lines, spacingLine) header = true continue case IRKindIdent: + var a []byte // discard ancillary - if _, err = nextUint32(r); err != nil { + if a, _, err = nextUint32(r, pos); err != nil { break } var sum Checksum - if sum, err = nextIdent(r); err != nil { + if _, sum, err = nextIdent(r, pos); err != nil { break } - values = append(values, [2]string{"id", Encode(sum)}) + lines = append(lines, asmOutLine{p, 4, int64(kind), a, 1, "id ", Encode(sum)}) continue case IRKindUint32: var i uint32 - if i, err = nextUint32(r); err != nil { + var bi []byte + if bi, i, err = nextUint32(r, pos); err != nil { break } - values = append(values, [2]string{"int", strconv.FormatUint(uint64(i), 10)}) + lines = append(lines, asmOutLine{p, 4, int64(kind), bi, 1, "int ", strconv.FormatUint(uint64(i), 10)}) case IRKindString: var l uint32 - if l, err = nextUint32(r); err != nil { + var bl []byte + if bl, l, err = nextUint32(r, pos); err != nil { break } s := make([]byte, l+(wordSize-(l)%wordSize)%wordSize) - if _, err = r.Read(s); err != nil { + var n int + if n, err = r.Read(s); err != nil { break } - values = append(values, [2]string{"str", fmt.Sprintf("\"%s\"", string(s[:l]))}) + *pos = *pos + n + + lines = append(lines, asmOutLine{p, 4, int64(kind), bl, 1, "str ", strconv.Quote(string(s[:l]))}) continue default: - var i uint32 - if i, err = nextUint32(r); err != nil { + var bi []byte + if bi, _, err = nextUint32(r, pos); err != nil { break } - values = append(values, [2]string{fmt.Sprintf("$%x", uint32(kind)), strconv.FormatUint(uint64(i), 10)}) + lines = append(lines, asmOutLine{p, 4, int64(kind), bi, 1, "????", ""}) } } 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])) + for _, line := range lines { + if raw { + if line.pos != -1 { + sb.WriteString(fmt.Sprintf("%s\t%s\n", line.kind, line.value)) + } + } else { + if line.pos == -1 { + sb.WriteString("\n") + } else if line.word == 4 { + sb.WriteString(fmt.Sprintf("%06x: %04x %04x%s %s %s\n", line.pos, binary.LittleEndian.AppendUint32(nil, uint32(line.kindData)), line.valueData, headerSpacing(showHeader), line.kind, line.value)) + } else { + kind := binary.LittleEndian.AppendUint64(nil, uint64(line.kindData)) + value := line.valueData + if len(value) == 8 { + sb.WriteString(fmt.Sprintf("%06x: %04x %04x %04x %04x %s %s\n", line.pos, kind[:4], kind[4:], value[:4], value[4:], line.kind, line.value)) + } else { + sb.WriteString(fmt.Sprintf("%06x: %04x %04x %s %s\n", line.pos, kind[:4], kind[4:], line.kind, line.value)) + } + + } + } + } return sb.String(), err } -func nextUint32(r io.Reader) (uint32, error) { +func nextUint32(r io.Reader, pos *int) ([]byte, uint32, error) { i := make([]byte, 4) _, err := r.Read(i) if err != nil { - return 0, err + return i, 0, err } - return binary.LittleEndian.Uint32(i), nil + p := *pos + 4 + *pos = p + return i, binary.LittleEndian.Uint32(i), nil } -func nextUint64(r io.Reader) (uint64, error) { +func nextUint64(r io.Reader, pos *int) ([]byte, uint64, error) { i := make([]byte, 8) _, err := r.Read(i) if err != nil { - return 0, err + return i, 0, err } - return binary.LittleEndian.Uint64(i), nil + p := *pos + 8 + *pos = p + return i, binary.LittleEndian.Uint64(i), nil } -func nextIdent(r io.Reader) (Checksum, error) { +func nextIdent(r io.Reader, pos *int) ([]byte, Checksum, error) { i := make([]byte, 48) if _, err := r.Read(i); err != nil { - return Checksum{}, err + return i, Checksum{}, err } - return Checksum(i), nil + p := *pos + 48 + *pos = p + return i, Checksum(i), nil } func intToKind(i uint64) string { switch Kind(i) { case KindHTTPGet: - return "http_get" + return "http" case KindTar: - return "tar" + return "tar " case KindExec: return "exec" case KindExecNet: - return "exec_net" + return "exen" case KindFile: return "file" default: - return fmt.Sprintf("$%d", i-KindCustomOffset) + return fmt.Sprintf("$%d ", i-KindCustomOffset) } } +func headerSpacing(showHeader bool) string { + if showHeader { + return " " + } + + return "" +}