Skip to content

Commit 5e01085

Browse files
committed
WIP: x64_*,arm64: Add decoders
1 parent 2a8104d commit 5e01085

File tree

7 files changed

+190
-7
lines changed

7 files changed

+190
-7
lines changed

format/all/all.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
_ "github.com/wader/fq/format/icc"
2121
_ "github.com/wader/fq/format/id3"
2222
_ "github.com/wader/fq/format/inet"
23+
_ "github.com/wader/fq/format/isa"
2324
_ "github.com/wader/fq/format/jpeg"
2425
_ "github.com/wader/fq/format/json"
2526
_ "github.com/wader/fq/format/macho"

format/elf/elf.go

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,20 @@ import (
1616
"github.com/wader/fq/pkg/scalar"
1717
)
1818

19+
var x86_64Format decode.Group
20+
var arm64Format decode.Group
21+
1922
func init() {
2023
registry.MustRegister(decode.Format{
2124
Name: format.ELF,
2225
Description: "Executable and Linkable Format",
2326
Groups: []string{format.PROBE},
2427
DecodeFn: elfDecode,
28+
Dependencies: []decode.Dependency{
29+
// TODO: x86_32?
30+
{Names: []string{format.X86_64}, Group: &x86_64Format},
31+
{Names: []string{format.ARM64}, Group: &arm64Format},
32+
},
2533
})
2634
}
2735

@@ -131,6 +139,15 @@ var machineNames = scalar.UToScalar{
131139
0x101: {Sym: "wdc_65C816", Description: "WDC 65C816"},
132140
}
133141

142+
var machineToFormatFn = map[int]func(d *decode.D, base uint64, symLookup func(uint64) (string, uint64)){
143+
EM_X86_64: func(d *decode.D, base uint64, symLookup func(uint64) (string, uint64)) {
144+
d.Format(x86_64Format, format.X86_64In{Base: int64(base), SymLookup: symLookup})
145+
},
146+
EM_ARM64: func(d *decode.D, base uint64, symLookup func(uint64) (string, uint64)) {
147+
d.Format(arm64Format, format.ARM64In{Base: int64(base), SymLookup: symLookup})
148+
},
149+
}
150+
134151
var phTypeNames = scalar.URangeToScalar{
135152
{Range: [2]uint64{0x00000000, 0x00000000}, S: scalar.S{Sym: "null", Description: "Unused element"}},
136153
{Range: [2]uint64{0x00000001, 0x00000001}, S: scalar.S{Sym: "load", Description: "Loadable segment"}},
@@ -767,6 +784,8 @@ func elfDecodeDynamicTags(d *decode.D, ec elfContext, dc dynamicContext) {
767784
}
768785

769786
func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
787+
var execInstr bool
788+
770789
shFlags := func(d *decode.D, archBits int) {
771790
d.FieldStruct("flags", func(d *decode.D) {
772791
if d.Endian == decode.LittleEndian {
@@ -775,7 +794,7 @@ func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
775794
d.FieldBool("strings")
776795
d.FieldBool("merge")
777796
d.FieldU1("unused0")
778-
d.FieldBool("execinstr")
797+
execInstr = d.FieldBool("execinstr")
779798
d.FieldBool("alloc")
780799
d.FieldBool("write")
781800
d.FieldBool("tls")
@@ -805,13 +824,14 @@ func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
805824
d.FieldBool("strings")
806825
d.FieldBool("merge")
807826
d.FieldU1("unused2")
808-
d.FieldBool("execinstr")
827+
execInstr = d.FieldBool("execinstr")
809828
d.FieldBool("alloc")
810829
d.FieldBool("write")
811830
}
812831
})
813832
}
814833

834+
var addr uint64
815835
var offset int64
816836
var size int64
817837
var entSize int64
@@ -822,7 +842,7 @@ func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
822842
d.FieldU32("name", strTable(ec.strTabMap[STRTAB_SHSTRTAB]))
823843
typ = d.FieldU32("type", sectionHeaderTypeMap, scalar.Hex)
824844
shFlags(d, ec.archBits)
825-
d.FieldU("addr", ec.archBits, scalar.Hex)
845+
addr = d.FieldU("addr", ec.archBits, scalar.Hex)
826846
offset = int64(d.FieldU("offset", ec.archBits)) * 8
827847
size = int64(d.FieldU32("size", scalar.Hex) * 8)
828848
d.FieldU32("link")
@@ -833,7 +853,7 @@ func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
833853
d.FieldU32("name", strTable(ec.strTabMap[STRTAB_SHSTRTAB]))
834854
typ = d.FieldU32("type", sectionHeaderTypeMap, scalar.Hex)
835855
shFlags(d, ec.archBits)
836-
d.FieldU("addr", ec.archBits, scalar.Hex)
856+
addr = d.FieldU("addr", ec.archBits, scalar.Hex)
837857
offset = int64(d.FieldU("offset", ec.archBits, scalar.Hex) * 8)
838858
size = int64(d.FieldU64("size") * 8)
839859
d.FieldU32("link")
@@ -866,9 +886,34 @@ func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
866886
elfDecodeSymbolTable(d, ec, int(size/entSize), ec.strTabMap[STRTAB_DYNSTR])
867887
})
868888
case SHT_PROGBITS:
869-
// TODO: name progbits?
870-
// TODO: decode opcodes
871-
d.FieldRawLen("data", size)
889+
// TODO: verify this, seems to result in strange relative addresses
890+
symLookup := func(symAddr uint64) (string, uint64) {
891+
var best *symbol
892+
893+
for _, sh := range ec.sections {
894+
for i, s := range sh.symbols {
895+
if symAddr >= s.value && (best == nil || symAddr-s.value < best.value-s.value) {
896+
best = &sh.symbols[i]
897+
}
898+
}
899+
}
900+
if best == nil {
901+
return "", 0
902+
}
903+
return strIndexNull(int(best.name), ec.strTabMap[STRTAB_STRTAB]), best.value
904+
}
905+
906+
// TODO: name progbits? instructions?
907+
if fn, ok := machineToFormatFn[ec.machine]; execInstr && ok {
908+
d.FieldArray("code", func(d *decode.D) {
909+
d.FramedFn(size, func(d *decode.D) {
910+
fn(d, addr, symLookup)
911+
})
912+
})
913+
} else {
914+
d.FieldRawLen("data", size)
915+
}
916+
872917
case SHT_GNU_HASH:
873918
d.FieldStruct("gnu_hash", func(d *decode.D) {
874919
elfDecodeGNUHash(d, ec, size, ec.strTabMap[STRTAB_DYNSTR])

format/format.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const (
1616
AMF0 = "amf0"
1717
APEV2 = "apev2"
1818
AR = "ar"
19+
ARM64 = "arm64"
1920
ASN1_BER = "asn1_ber"
2021
AV1_CCR = "av1_ccr"
2122
AV1_FRAME = "av1_frame"
@@ -99,6 +100,9 @@ const (
99100
VPX_CCR = "vpx_ccr"
100101
WAV = "wav"
101102
WEBP = "webp"
103+
X86_16 = "x86_16"
104+
X86_32 = "x86_32"
105+
X86_64 = "x86_64"
102106
XING = "xing"
103107
ZIP = "zip"
104108
)

format/isa/arm64.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package isa
2+
3+
import (
4+
"strings"
5+
6+
"github.com/wader/fq/format"
7+
"github.com/wader/fq/format/registry"
8+
"github.com/wader/fq/pkg/decode"
9+
"github.com/wader/fq/pkg/scalar"
10+
"golang.org/x/arch/arm64/arm64asm"
11+
)
12+
13+
func init() {
14+
registry.MustRegister(decode.Format{
15+
Name: format.ARM64,
16+
Description: "ARM64 instructions",
17+
DecodeFn: decodeARM64,
18+
RootArray: true,
19+
RootName: "instructions",
20+
})
21+
}
22+
23+
func decodeARM64(d *decode.D, in interface{}) interface{} {
24+
var symLookup func(uint64) (string, uint64)
25+
var base int64
26+
if xi, ok := in.(format.ARM64In); ok {
27+
symLookup = xi.SymLookup
28+
base = xi.Base
29+
}
30+
31+
bb := d.BytesRange(0, int(d.BitsLeft()/8))
32+
// TODO: uint64?
33+
pc := base
34+
35+
for !d.End() {
36+
d.FieldStruct("instruction", func(d *decode.D) {
37+
i, err := arm64asm.Decode(bb)
38+
if err != nil {
39+
d.Fatalf("failed to decode arm64 instruction: %s", err)
40+
}
41+
42+
// TODO: other syntax
43+
d.FieldRawLen("opcode", int64(4)*8, scalar.Sym(arm64asm.GoSyntax(i, uint64(pc), symLookup, nil)), scalar.Hex)
44+
45+
// TODO: Enc?
46+
d.FieldValueU("op", uint64(i.Enc), scalar.Sym(strings.ToLower(i.Op.String())), scalar.Hex)
47+
48+
bb = bb[4:]
49+
pc += int64(4)
50+
})
51+
52+
}
53+
54+
return nil
55+
}

format/isa/x86_64.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package isa
2+
3+
import (
4+
"strings"
5+
6+
"github.com/wader/fq/format"
7+
"github.com/wader/fq/format/registry"
8+
"github.com/wader/fq/pkg/decode"
9+
"github.com/wader/fq/pkg/scalar"
10+
"golang.org/x/arch/x86/x86asm"
11+
)
12+
13+
func init() {
14+
// amd64?
15+
registry.MustRegister(decode.Format{
16+
Name: format.X86_64,
17+
Description: "x86-64 instructions",
18+
DecodeFn: func(d *decode.D, in interface{}) interface{} { return decodeX86(d, in, 64) },
19+
RootArray: true,
20+
RootName: "instructions",
21+
})
22+
registry.MustRegister(decode.Format{
23+
Name: format.X86_32,
24+
Description: "x86-32 instructions",
25+
DecodeFn: func(d *decode.D, in interface{}) interface{} { return decodeX86(d, in, 32) },
26+
RootArray: true,
27+
RootName: "instructions",
28+
})
29+
registry.MustRegister(decode.Format{
30+
Name: format.X86_16,
31+
Description: "x86-16 instructions",
32+
DecodeFn: func(d *decode.D, in interface{}) interface{} { return decodeX86(d, in, 16) },
33+
RootArray: true,
34+
RootName: "instructions",
35+
})
36+
}
37+
38+
func decodeX86(d *decode.D, in interface{}, mode int) interface{} {
39+
var symLookup func(uint64) (string, uint64)
40+
var base int64
41+
if xi, ok := in.(format.X86_64In); ok {
42+
symLookup = xi.SymLookup
43+
base = xi.Base
44+
}
45+
46+
bb := d.BytesRange(0, int(d.BitsLeft()/8))
47+
// TODO: uint64?
48+
pc := base
49+
50+
for !d.End() {
51+
d.FieldStruct("instruction", func(d *decode.D) {
52+
i, err := x86asm.Decode(bb, mode)
53+
if err != nil {
54+
d.Fatalf("failed to decode x86 instruction: %s", err)
55+
}
56+
57+
d.FieldRawLen("opcode", int64(i.Len)*8, scalar.Sym(x86asm.IntelSyntax(i, uint64(pc), symLookup)), scalar.Hex)
58+
59+
// log.Printf("i.Len: %#+v\n", i.Len)
60+
// log.Printf("i.Opcode: %x\n", i.Opcode)
61+
// log.Printf("i: %#+v\n", i)
62+
63+
// TODO: rebuild op lower?
64+
d.FieldValueU("op", uint64(i.Opcode), scalar.Sym(strings.ToLower(i.Op.String())), scalar.Hex)
65+
66+
bb = bb[i.Len:]
67+
pc += int64(i.Len)
68+
})
69+
70+
}
71+
72+
return nil
73+
}

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ require (
3232
golang.org/x/text v0.3.7
3333
)
3434

35+
require golang.org/x/arch v0.0.0-20220401014709-5424468ecbac
36+
3537
require (
3638
github.com/itchyny/timefmt-go v0.1.3 // indirect
3739
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ github.com/wader/gojq v0.12.1-0.20220328204148-c4e42b829bf0 h1:rj+NshD1TyRazsy+H
1515
github.com/wader/gojq v0.12.1-0.20220328204148-c4e42b829bf0/go.mod h1:Pq2wrnwmiGxsaT62vOTEXkH3J3tI81VHJ2K2ZePP6oI=
1616
github.com/wader/readline v0.0.0-20220117233529-692d84ca36e2 h1:AK4wt6mSypGEVAzUcCfrJqVD5hju+w81b9J/k0swV/8=
1717
github.com/wader/readline v0.0.0-20220117233529-692d84ca36e2/go.mod h1:TJUJCkylZhI0Z07t2Nw6l6Ck7NiZqUpnMlkjEzN7+yM=
18+
golang.org/x/arch v0.0.0-20220401014709-5424468ecbac h1:05z6X/pDgf2qll8x7kbRRVdr33GjdV/GOCGiQfnaJS8=
19+
golang.org/x/arch v0.0.0-20220401014709-5424468ecbac/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
1820
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
1921
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
2022
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
@@ -37,3 +39,4 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
3739
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
3840
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
3941
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
42+
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

0 commit comments

Comments
 (0)