1
1
mirror of https://github.com/wader/fq.git synced 2024-11-26 10:33:53 +03:00
fq/format/macho/macho.go
Mattias Wadman 87b2c6c10c help,doc: Use markdown for format documentation again
Markdown is used as is in online documentation and in cli the markdown decoder
is used to decode and the some jq code massages it into something cli friendly.

Was just too much of a mess to have doc in jq.
2022-09-11 00:53:29 +02:00

942 lines
26 KiB
Go

package macho
// https://github.com/aidansteele/osx-abi-macho-file-format-reference
import (
"embed"
"strings"
"time"
"github.com/wader/fq/format"
"github.com/wader/fq/pkg/bitio"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/interp"
"github.com/wader/fq/pkg/scalar"
)
//go:embed macho.md
var machoFS embed.FS
func init() {
interp.RegisterFormat(decode.Format{
Name: format.MACHO,
Description: "Mach-O macOS executable",
Groups: []string{format.PROBE},
DecodeFn: machoDecode,
})
interp.RegisterFS(machoFS)
}
func strIndexNull(idx int, s string) string {
if idx > len(s) {
return ""
}
i := strings.IndexByte(s[idx:], 0)
if i == -1 {
return ""
}
return s[idx : idx+i]
}
type strTable string
func (m strTable) MapScalar(s scalar.S) (scalar.S, error) {
s.Sym = strIndexNull(int(s.ActualU()), string(m))
return s, nil
}
//nolint:revive
const (
MH_MAGIC = 0xfeed_face
MH_CIGAM = 0xcefa_edfe
MH_MAGIC_64 = 0xfeed_facf
MH_CIGAM_64 = 0xcffa_edfe
)
var magicSymMapper = scalar.UToScalar{
MH_MAGIC: scalar.S{Sym: "32le", Description: "32-bit little endian"},
MH_CIGAM: scalar.S{Sym: "32be", Description: "32-bit big endian"},
MH_MAGIC_64: scalar.S{Sym: "64le", Description: "64-bit little endian"},
MH_CIGAM_64: scalar.S{Sym: "64be", Description: "64-bit big endian"},
}
var cpuTypes = scalar.UToSymStr{
0xff_ff_ff_ff: "any",
1: "vax",
2: "romp",
4: "ns32032",
5: "ns32332",
6: "mc680x0",
7: "x86",
8: "mips",
9: "ns32532",
10: "mc98000",
11: "hppa",
12: "arm",
13: "mc88000",
14: "sparc",
15: "i860",
16: "i860_little",
17: "rs6000",
18: "powerpc",
0x1000007: "x86_64",
0x100000c: "arm64",
0x1000013: "powerpc64",
255: "veo",
}
func intelSubTypeHelper(f, m uint64) uint64 {
return f + (m << 4)
}
var cpuSubTypes = map[uint64]scalar.UToSymStr{
0xff_ff_ff_ff: {
0xff_ff_ff_ff: "multiple",
},
1: {
0xff_ff_ff_ff: "multiple",
0: "vax_all",
1: "vax780",
2: "vax785",
3: "vax750",
4: "vax730",
5: "uvaxi",
6: "uvaxii",
7: "vax8200",
8: "vax8500",
9: "vax8600",
10: "vax8650",
11: "vax8800",
12: "uvaxiii",
},
6: {
0xff_ff_ff_ff: "multiple",
1: "mc680x0_all", // 1: mc68030
2: "mc68040",
3: "mc68030_only",
},
7: {
0xff_ff_ff_ff: "multiple",
intelSubTypeHelper(3, 0): "i386_all", // i386
intelSubTypeHelper(4, 0): "i486",
intelSubTypeHelper(4, 8): "486sx",
intelSubTypeHelper(5, 0): "pent",
intelSubTypeHelper(6, 1): "pentpro",
intelSubTypeHelper(6, 3): "pentii_m3",
intelSubTypeHelper(6, 5): "pentii_m5",
intelSubTypeHelper(7, 6): "celeron",
intelSubTypeHelper(7, 7): "celeron_mobile",
intelSubTypeHelper(8, 0): "pentium_3",
intelSubTypeHelper(8, 1): "pentium_3_m",
intelSubTypeHelper(8, 2): "pentium_3_xeon",
intelSubTypeHelper(9, 0): "pentium_m",
intelSubTypeHelper(10, 0): "pentium_4",
intelSubTypeHelper(10, 1): "pentium_4_m",
intelSubTypeHelper(11, 0): "itanium",
intelSubTypeHelper(11, 1): "itanium_2",
intelSubTypeHelper(12, 0): "xeon",
intelSubTypeHelper(12, 1): "xeon_2",
},
8: {
0xff_ff_ff_ff: "multiple",
0: "mips_all",
1: "mips_r2300",
2: "mips_r2600",
3: "mips_r2800",
4: "mips_r2000a",
5: "mips_r2000",
6: "mips_r3000a",
7: "mips_r3000",
},
10: {
0xff_ff_ff_ff: "multiple",
0: "mc98000_all",
1: "mc98001",
},
11: {
0xff_ff_ff_ff: "multiple",
0: "hppa_all",
1: "hppa_7100",
2: "hppa_7100_lc",
},
12: {
0xff_ff_ff_ff: "multiple",
0: "arm_all",
5: "arm_v4t",
6: "arm_v6",
7: "arm_v5tej",
8: "arm_xscale",
9: "arm_v7",
10: "arm_v7f",
11: "arm_v7s",
12: "arm_v7k",
13: "arm_v8",
14: "arm_v6m",
15: "arm_v7m",
16: "arm_v7em",
},
13: {
0xff_ff_ff_ff: "multiple",
0: "mc88000_all",
1: "mc88100",
2: "mc88110",
},
14: {
0xff_ff_ff_ff: "multiple",
0: "sparc_all",
},
15: {
0xff_ff_ff_ff: "multiple",
0: "i860_all",
1: "i860_a860",
},
18: {
0xff_ff_ff_ff: "multiple",
0: "powerpc_all",
1: "powerpc_601",
2: "powerpc_602",
3: "powerpc_603",
4: "powerpc_603e",
5: "powerpc_603ev",
6: "powerpc_604",
7: "powerpc_604e",
8: "powerpc_620",
9: "powerpc_750",
10: "powerpc_7400",
11: "powerpc_7450",
100: "powerpc_970",
},
0x1000012: {
0xff_ff_ff_ff: "multiple",
0: "arm64_all",
1: "arm64_v8",
2: "arm64_e",
},
}
var fileTypes = scalar.UToSymStr{
0x1: "object",
0x2: "execute",
0x3: "fvmlib",
0x4: "core",
0x5: "preload",
0x6: "dylib",
0x7: "dylinker",
0x8: "bundle",
0x9: "dylib_stub",
0xa: "dsym",
0xb: "kext_bundle",
}
//nolint:revive
const (
LC_REQ_DYLD = 0x80000000
LC_SEGMENT = 0x1
LC_SYMTAB = 0x2
LC_SYMSEG = 0x3
LC_THREAD = 0x4
LC_UNIXTHREAD = 0x5
LC_LOADFVMLIB = 0x6
LC_IDFVMLIB = 0x7
LC_IDENT = 0x8 // not implemented
LC_FVMFILE = 0x9 // not implemented
LC_PREPAGE = 0xa // not implemented
LC_DYSYMTAB = 0xb
LC_LOAD_DYLIB = 0xc
LC_ID_DYLIB = 0xd
LC_LOAD_DYLINKER = 0xe
LC_ID_DYLINKER = 0xf
LC_PREBOUND_DYLIB = 0x10
LC_ROUTINES = 0x11
LC_SUB_FRAMEWORK = 0x12
LC_SUB_UMBRELLA = 0x13
LC_SUB_CLIENT = 0x14
LC_SUB_LIBRARY = 0x15
LC_TWOLEVEL_HINTS = 0x16
LC_PREBIND_CKSUM = 0x17 // not implemented
LC_LOAD_WEAK_DYLIB = 0x80000018
LC_SEGMENT_64 = 0x19
LC_ROUTINES_64 = 0x1a
LC_UUID = 0x1b
LC_RPATH = 0x8000001c
LC_CODE_SIGNATURE = 0x1d
LC_SEGMENT_SPLIT_INFO = 0x1e
LC_REEXPORT_DYLIB = 0x8000001f
LC_LAZY_LOAD_DYLIB = 0x20
LC_ENCRYPTION_INFO = 0x21
LC_DYLD_INFO = 0x22
LC_DYLD_INFO_ONLY = 0x80000022
LC_LOAD_UPWARD_DYLIB = 0x80000023
LC_VERSION_MIN_MACOSX = 0x24
LC_VERSION_MIN_IPHONEOS = 0x25
LC_FUNCTION_STARTS = 0x26
LC_DYLD_ENVIRONMENT = 0x27
LC_MAIN = 0x80000028
LC_DATA_IN_CODE = 0x29
LC_SOURCE_VERSION = 0x2a
LC_DYLIB_CODE_SIGN_DRS = 0x2b
LC_ENCRYPTION_INFO_64 = 0x2c
LC_LINKER_OPTION = 0x2d
LC_LINKER_OPTIMIZATION_HINT = 0x2e
LC_VERSION_MIN_TVOS = 0x2f
LC_VERSION_MIN_WATCHOS = 0x30
LC_NOTE = 0x31 // not implemented
LC_BUILD_VERSION = 0x32
)
var loadCommands = scalar.UToSymStr{
LC_REQ_DYLD: "req_dyld",
LC_SEGMENT: "segment",
LC_SYMTAB: "symtab",
LC_SYMSEG: "symseg",
LC_THREAD: "thread",
LC_UNIXTHREAD: "unixthread",
LC_LOADFVMLIB: "loadfvmlib",
LC_IDFVMLIB: "idfvmlib",
LC_IDENT: "ident",
LC_FVMFILE: "fvmfile",
LC_PREPAGE: "prepage",
LC_DYSYMTAB: "dysymtab",
LC_LOAD_DYLIB: "load_dylib",
LC_ID_DYLIB: "id_dylib",
LC_LOAD_DYLINKER: "load_dylinker",
LC_ID_DYLINKER: "id_dylinker",
LC_PREBOUND_DYLIB: "prebound_dylib",
LC_ROUTINES: "routines",
LC_SUB_FRAMEWORK: "sub_framework",
LC_SUB_UMBRELLA: "sub_umbrella",
LC_SUB_CLIENT: "sub_client",
LC_SUB_LIBRARY: "sub_library",
LC_TWOLEVEL_HINTS: "twolevel_hints",
LC_PREBIND_CKSUM: "prebind_cksum",
LC_LOAD_WEAK_DYLIB: "load_weak_dylib",
LC_SEGMENT_64: "segment_64",
LC_ROUTINES_64: "routines_64",
LC_UUID: "uuid",
LC_RPATH: "rpath",
LC_CODE_SIGNATURE: "code_signature",
LC_SEGMENT_SPLIT_INFO: "segment_split_info",
LC_REEXPORT_DYLIB: "reexport_dylib",
LC_LAZY_LOAD_DYLIB: "lazy_load_dylib",
LC_ENCRYPTION_INFO: "encryption_info",
LC_DYLD_INFO: "dyld_info",
LC_DYLD_INFO_ONLY: "dyld_info_only",
LC_LOAD_UPWARD_DYLIB: "load_upward_dylib",
LC_VERSION_MIN_MACOSX: "version_min_macosx",
LC_VERSION_MIN_IPHONEOS: "version_min_iphoneos",
LC_FUNCTION_STARTS: "function_starts",
LC_DYLD_ENVIRONMENT: "dyld_environment",
LC_MAIN: "main",
LC_DATA_IN_CODE: "data_in_code",
LC_SOURCE_VERSION: "source_version",
LC_DYLIB_CODE_SIGN_DRS: "dylib_code_sign_drs",
LC_ENCRYPTION_INFO_64: "encryption_info_64",
LC_LINKER_OPTION: "linker_option",
LC_LINKER_OPTIMIZATION_HINT: "linker_optimization_hint",
LC_VERSION_MIN_TVOS: "version_min_tvos",
LC_VERSION_MIN_WATCHOS: "version_min_watchos",
LC_NOTE: "note",
LC_BUILD_VERSION: "build_version",
}
var sectionTypes = scalar.UToSymStr{
0x0: "regular",
0x1: "zerofill",
0x2: "cstring_literals",
0x3: "4byte_literals",
0x4: "8byte_literals",
0x5: "literal_pointers",
0x6: "non_lazy_symbol_pointers",
0x7: "lazy_symbol_pointers",
0x8: "symbol_stubs",
0x9: "mod_init_func_pointers",
0xa: "mod_term_func_pointers",
0xb: "coalesced",
0xc: "gb_zerofill",
0xd: "interposing",
0xe: "16byte_literals",
0xf: "dtrace_dof",
0x10: "lazy_dylib_symbol_pointers",
0x11: "thread_local_regular",
0x12: "thread_local_zerofill",
0x13: "thread_local_variables",
0x14: "thread_local_variable_pointers",
0x15: "thread_local_init_function_pointers",
}
func machoDecode(d *decode.D, _ any) any {
var archBits int
var cpuType uint64
var ncmds uint64
magicBuffer := d.U32LE()
if magicBuffer == MH_MAGIC || magicBuffer == MH_MAGIC_64 {
d.Endian = decode.LittleEndian
if magicBuffer == MH_MAGIC {
archBits = 32
} else {
archBits = 64
}
} else if magicBuffer == MH_CIGAM || magicBuffer == MH_CIGAM_64 {
d.Endian = decode.BigEndian
if magicBuffer == MH_CIGAM {
archBits = 32
} else {
archBits = 64
}
} else {
d.Fatalf("invalid magic")
}
d.SeekRel(-4 * 8)
d.FieldStruct("header", func(d *decode.D) {
d.FieldValueS("arch_bits", int64(archBits))
d.FieldU32("magic", magicSymMapper, scalar.ActualHex)
d.FieldValueU("bits", uint64(archBits))
cpuType = d.FieldU32("cputype", cpuTypes, scalar.ActualHex)
d.FieldU32("cpusubtype", cpuSubTypes[cpuType], scalar.ActualHex)
d.FieldU32("filetype", fileTypes)
ncmds = d.FieldU32("ncdms")
d.FieldU32("sizeofncdms")
d.FieldStruct("flags", parseMachHeaderFlags)
if archBits == 64 {
d.FieldRawLen("reserved", 4*8, d.BitBufIsZero())
}
})
loadCommandsNext := d.Pos()
d.FieldArray("load_commands", func(d *decode.D) {
for i := uint64(0); i < ncmds; i++ {
d.FieldStruct("load_command", func(d *decode.D) {
d.SeekAbs(loadCommandsNext)
cmd := d.FieldU32("cmd", loadCommands, scalar.ActualHex)
cmdSize := d.FieldU32("cmdsize")
if cmdSize == 0 {
d.Fatalf("cmdSize is zero")
}
loadCommandsNext += int64(cmdSize) * 8
switch cmd {
case LC_UUID:
d.FieldStruct("uuid_command", func(d *decode.D) {
d.FieldRawLen("uuid", 16*8)
})
case LC_SEGMENT,
LC_SEGMENT_64:
// nsect := (cmdsize - uint64(archBits)) / uint64(archBits)
var vmaddr int64
var fileoff int64
var nsects uint64
d.FieldStruct("segment_command", func(d *decode.D) {
d.FieldValueS("arch_bits", int64(archBits))
d.FieldUTF8NullFixedLen("segname", 16) // OPCODE_DECODER segname==__TEXT
if archBits == 32 {
vmaddr = int64(d.FieldU32("vmaddr", scalar.ActualHex))
d.FieldU32("vmsize")
fileoff = int64(d.FieldU32("fileoff", scalar.ActualHex))
d.FieldU32("tfilesize")
} else {
vmaddr = int64(d.FieldU64("vmaddr", scalar.ActualHex))
d.FieldU64("vmsize")
fileoff = int64(d.FieldU64("fileoff", scalar.ActualHex))
d.FieldU64("tfilesize")
}
d.FieldS32("initprot")
d.FieldS32("maxprot")
nsects = d.FieldU32("nsects")
d.FieldStruct("flags", parseSegmentFlags)
})
d.FieldArray("sections", func(d *decode.D) {
for i := uint64(0); i < nsects; i++ {
d.FieldStruct("section", func(d *decode.D) {
// OPCODE_DECODER sectname==__text
sectName := d.FieldUTF8NullFixedLen("sectname", 16)
d.FieldUTF8NullFixedLen("segname", 16)
var size uint64
if archBits == 32 {
d.FieldU32("address", scalar.ActualHex)
size = d.FieldU32("size")
} else {
d.FieldU64("address", scalar.ActualHex)
size = d.FieldU64("size")
}
offset := d.FieldU32("offset", scalar.ActualHex)
d.FieldU32("align")
d.FieldU32("reloff")
d.FieldU32("nreloc")
// get section type
d.FieldStruct("flags", parseSectionFlags)
d.FieldU8("type", sectionTypes)
d.FieldU32("reserved1")
d.FieldU32("reserved2")
if archBits == 64 {
d.FieldU32("reserved3")
}
switch sectName {
case "__bss", // uninitialized data
"__common": // allocated by linker
// skip, no data from file
// TODO: more?
default:
d.RangeFn(int64(offset)*8, int64(size)*8, func(d *decode.D) {
switch sectName {
case "__cstring":
d.FieldArray("cstrings", func(d *decode.D) {
for !d.End() {
d.FieldUTF8Null("cstring")
}
})
case "__ustring":
d.FieldArray("ustrings", func(d *decode.D) {
for !d.End() {
// TODO: always LE?
d.FieldUTF16LENull("ustring")
}
})
case "__cfstring":
d.FieldArray("cfstrings", func(d *decode.D) {
for !d.End() {
d.FieldStruct("cfstring", func(d *decode.D) {
// https://github.com/llvm-mirror/clang/blob/aa231e4be75ac4759c236b755c57876f76e3cf05/lib/CodeGen/CodeGenModule.cpp#L4708
const flagUTF8 = 0x07c8
const flagUTF16 = 0x07d0
d.FieldU("isa_vmaddr", archBits)
flag := d.FieldU("flags", archBits, scalar.ActualHex, scalar.UToSymStr{
flagUTF8: "utf8",
flagUTF16: "utf16",
})
dataPtr := int64(d.FieldU("data_ptr", archBits, scalar.ActualHex))
length := int64(d.FieldU("length", archBits))
offset := ((dataPtr - vmaddr) + fileoff) * 8
switch flag {
case flagUTF8:
d.RangeFn(offset, length*8, func(d *decode.D) { d.FieldUTF8("string", int(length)) })
case flagUTF16:
// TODO: endian?
d.RangeFn(offset, length*8*2, func(d *decode.D) { d.FieldUTF16("string", int(length*2)) })
}
})
}
})
default:
d.FieldRawLen("data", d.BitsLeft())
}
})
}
})
}
})
case LC_TWOLEVEL_HINTS:
d.FieldU32("offset", scalar.ActualHex)
d.FieldU32("nhints")
case LC_LOAD_DYLIB,
LC_ID_DYLIB,
LC_LOAD_UPWARD_DYLIB,
LC_LOAD_WEAK_DYLIB,
LC_LAZY_LOAD_DYLIB,
LC_REEXPORT_DYLIB:
d.FieldStruct("dylib_command", func(d *decode.D) {
offset := d.FieldU32("offset", scalar.ActualHex)
d.FieldU32("timestamp", timestampMapper)
d.FieldU32("current_version")
d.FieldU32("compatibility_version")
d.FieldUTF8NullFixedLen("name", int(cmdSize)-int(offset))
})
case LC_LOAD_DYLINKER,
LC_ID_DYLINKER,
LC_DYLD_ENVIRONMENT:
offset := d.FieldU32("offset", scalar.ActualHex)
d.FieldUTF8NullFixedLen("name", int(cmdSize)-int(offset))
case LC_RPATH:
offset := d.FieldU32("offset", scalar.ActualHex)
d.FieldUTF8NullFixedLen("name", int(cmdSize)-int(offset))
case LC_PREBOUND_DYLIB:
// https://github.com/aidansteele/osx-abi-macho-file-format-reference#prebound_dylib_command
d.U32() // name_offset
nmodules := d.FieldU32("nmodules")
d.U32() // linked_modules_offset
d.FieldUTF8Null("name")
d.FieldBitBufFn("linked_modules", func(d *decode.D) bitio.ReaderAtSeeker {
return d.RawLen(int64((nmodules / 8) + (nmodules % 8)))
})
case LC_THREAD,
LC_UNIXTHREAD:
d.FieldU32("flavor")
count := d.FieldU32("count")
switch cpuType {
case 0x7:
d.FieldStruct("state", threadStateI386Decode)
case 0xC:
d.FieldStruct("state", threadStateARM32Decode)
case 0x13:
d.FieldStruct("state", threadStatePPC32Decode)
case 0x1000007:
d.FieldStruct("state", threadStateX8664Decode)
case 0x100000C:
d.FieldStruct("state", threadStateARM64Decode)
case 0x1000013:
d.FieldStruct("state", threadStatePPC64Decode)
default:
d.FieldRawLen("state", int64(count*32))
}
case LC_ROUTINES,
LC_ROUTINES_64:
if archBits == 32 {
d.FieldU32("init_address", scalar.ActualHex)
d.FieldU32("init_module")
d.FieldU32("reserved1")
d.FieldU32("reserved2")
d.FieldU32("reserved3")
d.FieldU32("reserved4")
d.FieldU32("reserved5")
d.FieldU32("reserved6")
} else {
d.FieldU64("init_address", scalar.ActualHex)
d.FieldU64("init_module")
d.FieldU64("reserved1")
d.FieldU64("reserved2")
d.FieldU64("reserved3")
d.FieldU64("reserved4")
d.FieldU64("reserved5")
d.FieldU64("reserved6")
}
case LC_SUB_UMBRELLA,
LC_SUB_LIBRARY,
LC_SUB_CLIENT,
LC_SUB_FRAMEWORK:
offset := d.FieldU32("offset", scalar.ActualHex)
d.FieldUTF8NullFixedLen("name", int(cmdSize)-int(offset))
case LC_SYMTAB:
symOff := d.FieldU32("symoff")
nSyms := d.FieldU32("nsyms")
strOff := d.FieldU32("stroff")
strSize := d.FieldU32("strsize")
d.RangeFn(int64(strOff)*8, int64(strSize)*8, func(d *decode.D) {
d.FieldRawLen("str_table", d.BitsLeft())
})
symTabTable := strTable(string(d.BytesRange(int64(strOff)*8, int(strSize))))
d.SeekAbs(int64(symOff) * 8)
d.FieldArray("symbols", func(d *decode.D) {
for i := 0; i < int(nSyms); i++ {
symbolTypeMap := scalar.UToSymStr{
0x0: "undef",
0x1: "abs",
0x5: "indr",
0x6: "pbud",
0x7: "sect",
}
d.FieldStruct("symbol", func(d *decode.D) {
d.FieldU32("strx", symTabTable)
d.FieldStruct("type", func(d *decode.D) {
d.FieldU3("stab")
d.FieldU1("pext")
d.FieldU3("type", symbolTypeMap)
d.FieldU1("ext")
})
d.FieldU8("sect")
d.FieldU16("desc")
d.FieldU("value", archBits, scalar.ActualHex)
})
}
})
case LC_DYSYMTAB:
d.FieldU32("ilocalsym")
d.FieldU32("nlocalsym")
d.FieldU32("iextdefsym")
d.FieldU32("nextdefsym")
d.FieldU32("iundefsym")
d.FieldU32("nundefsym")
d.FieldU32("tocoff")
d.FieldU32("ntoc")
d.FieldU32("modtaboff")
d.FieldU32("nmodtab")
d.FieldU32("extrefsymoff")
d.FieldU32("nextrefsyms")
d.FieldU32("indirectsymoff")
d.FieldU32("nindirectsyms")
d.FieldU32("extreloff")
d.FieldU32("nextrel")
d.FieldU32("locreloff")
d.FieldU32("nlocrel")
case LC_BUILD_VERSION:
d.FieldU32("platform")
d.FieldU32("minos")
d.FieldU32("sdk")
ntools := d.FieldU32("ntools")
var ntoolsIdx uint64
d.FieldStructArrayLoop("tools", "tool", func() bool {
return ntoolsIdx < ntools
}, func(d *decode.D) {
d.FieldU32("tool")
d.FieldU32("version")
ntoolsIdx++
})
case LC_CODE_SIGNATURE,
LC_SEGMENT_SPLIT_INFO,
LC_FUNCTION_STARTS,
LC_DATA_IN_CODE,
LC_DYLIB_CODE_SIGN_DRS,
LC_LINKER_OPTIMIZATION_HINT:
d.FieldStruct("linkedit_data", func(d *decode.D) {
d.FieldU32("off")
d.FieldU32("size")
})
case LC_VERSION_MIN_IPHONEOS,
LC_VERSION_MIN_MACOSX,
LC_VERSION_MIN_TVOS,
LC_VERSION_MIN_WATCHOS:
d.FieldU32("version")
d.FieldU32("sdk")
case LC_DYLD_INFO,
LC_DYLD_INFO_ONLY:
d.FieldStruct("dyld_info", func(d *decode.D) {
d.FieldU32("rebase_off", scalar.ActualHex)
d.FieldU32("rebase_size")
d.FieldU32("bind_off", scalar.ActualHex)
d.FieldU32("bind_size")
d.FieldU32("weak_bind_off", scalar.ActualHex)
d.FieldU32("weak_bind_size")
d.FieldU32("lazy_bind_off", scalar.ActualHex)
d.FieldU32("lazy_bind_size")
d.FieldU32("export_off", scalar.ActualHex)
d.FieldU32("export_size")
})
case LC_MAIN:
d.FieldStruct("entrypoint", func(d *decode.D) {
d.FieldU64("entryoff", scalar.ActualHex)
d.FieldU64("stacksize")
})
case LC_SOURCE_VERSION:
d.FieldStruct("source_version_tag", func(d *decode.D) {
d.FieldU64("tag")
})
case LC_LINKER_OPTION:
d.FieldStruct("linker_option", func(d *decode.D) {
count := d.FieldU32("count")
d.FieldUTF8NullFixedLen("option", int(count))
})
case LC_ENCRYPTION_INFO,
LC_ENCRYPTION_INFO_64:
d.FieldStruct("encryption_info", func(d *decode.D) {
offset := d.FieldU32("offset", scalar.ActualHex)
size := d.FieldU32("size")
d.FieldU32("id")
d.RangeFn(int64(offset)*8, int64(size)*8, func(d *decode.D) {
d.FieldRawLen("data", d.BitsLeft())
})
})
if cmd == LC_ENCRYPTION_INFO_64 {
// 64 bit align
d.FieldU32("pad")
}
case LC_IDFVMLIB,
LC_LOADFVMLIB:
d.FieldStruct("fvmlib", func(d *decode.D) {
offset := d.FieldU32("offset", scalar.ActualHex)
d.FieldU32("minor_version")
d.FieldU32("header_addr", scalar.ActualHex)
d.FieldUTF8NullFixedLen("name", int(cmdSize)-int(offset))
})
default:
// ignore
}
})
}
})
return nil
}
func parseMachHeaderFlags(d *decode.D) {
d.FieldRawLen("reserved", 6)
d.FieldBool("app_extension_safe")
d.FieldBool("no_heap_execution")
d.FieldBool("has_tlv_descriptors")
d.FieldBool("dead_strippable_dylib")
d.FieldBool("pie")
d.FieldBool("no_reexported_dylibs")
d.FieldBool("setuid_safe")
d.FieldBool("root_safe")
d.FieldBool("allow_stack_execution")
d.FieldBool("binds_to_weak")
d.FieldBool("weak_defines")
d.FieldBool("canonical")
d.FieldBool("subsections_via_symbols")
d.FieldBool("allmodsbound")
d.FieldBool("prebindable")
d.FieldBool("nofixprebinding")
d.FieldBool("nomultidefs")
d.FieldBool("force_flat")
d.FieldBool("twolevel")
d.FieldBool("lazy_init")
d.FieldBool("split_segs")
d.FieldBool("prebound")
d.FieldBool("bindatload")
d.FieldBool("dyldlink")
d.FieldBool("incrlink")
d.FieldBool("noundefs")
}
func parseSegmentFlags(d *decode.D) {
d.FieldRawLen("reserved", 28)
d.FieldBool("protected_version_1")
d.FieldBool("noreloc")
d.FieldBool("fvmlib")
d.FieldBool("highvm")
}
func parseSectionFlags(d *decode.D) {
d.FieldBool("attr_pure_instructions")
d.FieldBool("attr_no_toc")
d.FieldBool("attr_strip_static_syms")
d.FieldBool("attr_no_dead_strip")
d.FieldBool("attr_live_support")
d.FieldBool("attr_self_modifying_code")
d.FieldBool("attr_debug")
d.FieldRawLen("reserved", 14)
d.FieldBool("attr_some_instructions")
d.FieldBool("attr_ext_reloc")
d.FieldBool("attr_loc_reloc")
}
var timestampMapper = scalar.Fn(func(s scalar.S) (scalar.S, error) {
s.Sym = time.UnixMilli(int64(s.ActualU())).UTC().String()
return s, nil
})
func threadStateI386Decode(d *decode.D) {
d.FieldU32("eax")
d.FieldU32("ebx")
d.FieldU32("ecx")
d.FieldU32("edx")
d.FieldU32("edi")
d.FieldU32("esi")
d.FieldU32("ebp")
d.FieldU32("esp")
d.FieldU32("ss")
d.FieldU32("eflags")
d.FieldU32("eip")
d.FieldU32("cs")
d.FieldU32("ds")
d.FieldU32("es")
d.FieldU32("fs")
d.FieldU32("gs")
}
func threadStateX8664Decode(d *decode.D) {
d.FieldU64("rax")
d.FieldU64("rbx")
d.FieldU64("rcx")
d.FieldU64("rdx")
d.FieldU64("rdi")
d.FieldU64("rsi")
d.FieldU64("rbp")
d.FieldU64("rsp")
d.FieldU64("r8")
d.FieldU64("r9")
d.FieldU64("r10")
d.FieldU64("r11")
d.FieldU64("r12")
d.FieldU64("r13")
d.FieldU64("r14")
d.FieldU64("r15")
d.FieldU64("rip")
d.FieldU64("rflags")
d.FieldU64("cs")
d.FieldU64("fs")
d.FieldU64("gs")
}
func threadStateARM32Decode(d *decode.D) {
rIdx := 0
d.FieldStructArrayLoop("r", "r", func() bool {
return rIdx < 13
}, func(d *decode.D) {
d.FieldU32("value")
rIdx++
})
d.FieldU32("sp")
d.FieldU32("lr")
d.FieldU32("pc")
d.FieldU32("cpsr")
}
func threadStateARM64Decode(d *decode.D) {
rIdx := 0
d.FieldStructArrayLoop("r", "r", func() bool {
return rIdx < 29
}, func(d *decode.D) {
d.FieldU64("value")
rIdx++
})
d.FieldU64("fp")
d.FieldU64("lr")
d.FieldU64("sp")
d.FieldU64("pc")
d.FieldU32("cpsr")
d.FieldU32("pad")
}
func threadStatePPC32Decode(d *decode.D) {
srrIdx := 0
d.FieldStructArrayLoop("srr", "srr", func() bool {
return srrIdx < 2
}, func(d *decode.D) {
d.FieldU32("value")
srrIdx++
})
rIdx := 0
d.FieldStructArrayLoop("r", "r", func() bool {
return rIdx < 32
}, func(d *decode.D) {
d.FieldU32("value")
rIdx++
})
d.FieldU32("ct")
d.FieldU32("xer")
d.FieldU32("lr")
d.FieldU32("ctr")
d.FieldU32("mq")
d.FieldU32("vrsave")
}
func threadStatePPC64Decode(d *decode.D) {
srrIdx := 0
d.FieldStructArrayLoop("srr", "srr", func() bool {
return srrIdx < 2
}, func(d *decode.D) {
d.FieldU64("value")
srrIdx++
})
rIdx := 0
d.FieldStructArrayLoop("r", "r", func() bool {
return rIdx < 32
}, func(d *decode.D) {
d.FieldU64("value")
rIdx++
})
d.FieldU32("ct")
d.FieldU64("xer")
d.FieldU64("lr")
d.FieldU64("ctr")
d.FieldU32("vrsave")
}