mirror of
https://github.com/wader/fq.git
synced 2024-11-26 21:55:57 +03:00
1119 lines
38 KiB
Go
1119 lines
38 KiB
Go
package elf
|
|
|
|
// https://refspecs.linuxbase.org/elf/gabi4+/contents.html
|
|
// https://man7.org/linux/man-pages/man5/elf.5.html
|
|
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h
|
|
// https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=include/elf/external.h;hb=HEAD
|
|
|
|
// TODO: dwarf
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/wader/fq/format"
|
|
"github.com/wader/fq/pkg/decode"
|
|
"github.com/wader/fq/pkg/interp"
|
|
"github.com/wader/fq/pkg/scalar"
|
|
)
|
|
|
|
func init() {
|
|
interp.RegisterFormat(
|
|
format.ELF,
|
|
&decode.Format{
|
|
Description: "Executable and Linkable Format",
|
|
Groups: []*decode.Group{format.Probe},
|
|
DecodeFn: elfDecode,
|
|
})
|
|
}
|
|
|
|
const (
|
|
LITTLE_ENDIAN = 1
|
|
BIG_ENDIAN = 2
|
|
)
|
|
|
|
var endianNames = scalar.UintMapSymStr{
|
|
LITTLE_ENDIAN: "little_endian",
|
|
BIG_ENDIAN: "big_endian",
|
|
}
|
|
|
|
var classBits = scalar.UintMapSymUint{
|
|
1: 32,
|
|
2: 64,
|
|
}
|
|
|
|
const (
|
|
CLASS_32 = 1
|
|
CLASS_64 = 2
|
|
)
|
|
|
|
var osABINames = scalar.UintMapSymStr{
|
|
0: "sysv",
|
|
1: "hpux",
|
|
2: "netbsd",
|
|
3: "linux",
|
|
4: "hurd",
|
|
5: "86open",
|
|
6: "solaris",
|
|
7: "monterey",
|
|
8: "irix",
|
|
9: "freebsd",
|
|
10: "tru64",
|
|
11: "modesto",
|
|
12: "openbsd",
|
|
97: "arm",
|
|
255: "standalone",
|
|
}
|
|
|
|
const (
|
|
ET_NONE = 0
|
|
ET_REL = 1
|
|
ET_EXEC = 2
|
|
ET_DYN = 3
|
|
ET_CORE = 4
|
|
)
|
|
|
|
var typeNames = scalar.UintRangeToScalar{
|
|
{Range: [2]uint64{ET_NONE, ET_NONE}, S: scalar.Uint{Sym: "none"}},
|
|
{Range: [2]uint64{ET_REL, ET_REL}, S: scalar.Uint{Sym: "rel"}},
|
|
{Range: [2]uint64{ET_EXEC, ET_EXEC}, S: scalar.Uint{Sym: "exec"}},
|
|
{Range: [2]uint64{ET_DYN, ET_DYN}, S: scalar.Uint{Sym: "dyn"}},
|
|
{Range: [2]uint64{ET_CORE, ET_CORE}, S: scalar.Uint{Sym: "core"}},
|
|
{Range: [2]uint64{0xfe00, 0xfeff}, S: scalar.Uint{Sym: "os"}},
|
|
{Range: [2]uint64{0xff00, 0xffff}, S: scalar.Uint{Sym: "proc"}},
|
|
}
|
|
|
|
const (
|
|
EM_X86_64 = 0x3e
|
|
EM_ARM64 = 0xb7
|
|
)
|
|
|
|
var machineNames = scalar.UintMap{
|
|
0x00: {Description: "No specific instruction set"},
|
|
0x01: {Sym: "we_32100", Description: "AT&T WE 32100"},
|
|
0x02: {Sym: "sparc", Description: "SPARC"},
|
|
0x03: {Sym: "x86", Description: "x86"},
|
|
0x04: {Sym: "m68k", Description: "Motorola 68000 (M68k)"},
|
|
0x05: {Sym: "m88k", Description: "Motorola 88000 (M88k)"},
|
|
0x06: {Sym: "intel_mcu", Description: "Intel MCU"},
|
|
0x07: {Sym: "intel_80860", Description: "Intel 80860"},
|
|
0x08: {Sym: "mips", Description: "MIPS"},
|
|
0x09: {Sym: "s370", Description: "IBM_System/370"},
|
|
0x0a: {Sym: "mips_rs3000le", Description: "MIPS RS3000 Little-endian"},
|
|
0x0e: {Sym: "pa_risc", Description: "Hewlett-Packard PA-RISC"},
|
|
0x0f: {Description: "Reserved for future use"},
|
|
0x13: {Sym: "80960", Description: "Intel 80960"},
|
|
0x14: {Sym: "powerpc", Description: "PowerPC"},
|
|
0x15: {Sym: "powerpc64", Description: "PowerPC (64-bit)"},
|
|
0x16: {Sym: "s390", Description: "S390, including S390x"},
|
|
0x17: {Sym: "ibm_spu_spc", Description: "IBM SPU/SPC"},
|
|
0x24: {Sym: "nec_v800", Description: "NEC V800"},
|
|
0x25: {Sym: "fr20", Description: "Fujitsu FR20"},
|
|
0x26: {Sym: "trw_rh_32", Description: "TRW RH-32"},
|
|
0x27: {Sym: "motorola_rce", Description: "Motorola RCE"},
|
|
0x28: {Sym: "arm", Description: "ARM (up to ARMv7/Aarch32)"},
|
|
0x29: {Sym: "alpha", Description: "Digital Alpha"},
|
|
0x2a: {Sym: "superh", Description: "SuperH"},
|
|
0x2b: {Sym: "sparc_v9", Description: "SPARC Version 9"},
|
|
0x2c: {Sym: "siemens_tricore", Description: "Siemens TriCore embedded processor"},
|
|
0x2d: {Sym: "argonaut_risc", Description: "Argonaut RISC Core"},
|
|
0x2e: {Sym: "h8_300", Description: "Hitachi H8/300"},
|
|
0x2f: {Sym: "h8_300h", Description: "Hitachi H8/300H"},
|
|
0x30: {Sym: "h8s", Description: "Hitachi H8S"},
|
|
0x31: {Sym: "h8/500", Description: "Hitachi H8/500"},
|
|
0x32: {Sym: "ia_64", Description: "IA-64"},
|
|
0x33: {Sym: "mips_x", Description: "Stanford MIPS-X"},
|
|
0x34: {Sym: "coldfire", Description: "Motorola ColdFire"},
|
|
0x35: {Sym: "m68hc12", Description: "Motorola M68HC12"},
|
|
0x36: {Sym: "fujitsu_mma", Description: "Fujitsu MMA Multimedia Accelerator"},
|
|
0x37: {Sym: "siemens_pcp", Description: "Siemens PCP"},
|
|
0x38: {Sym: "sony_ncpu_risc", Description: "Sony nCPU embedded RISC processor"},
|
|
0x39: {Sym: "denso_ndr1", Description: "Denso NDR1 microprocessor"},
|
|
0x3a: {Sym: "motorola_star", Description: "Motorola Star*Core processor"},
|
|
0x3b: {Sym: "toyota_me16", Description: "Toyota ME16 processor"},
|
|
0x3c: {Sym: "st100", Description: "STMicroelectronics ST100 processor"},
|
|
0x3d: {Sym: "tinyj", Description: "Advanced Logic Corp. TinyJ embedded processor family"},
|
|
EM_X86_64: {Sym: "x86_64", Description: "AMD x86-64"},
|
|
0x8c: {Sym: "tms320C6000", Description: "TMS320C6000 Family"},
|
|
EM_ARM64: {Sym: "arm64", Description: "ARM 64-bits (ARMv8/Aarch64)"},
|
|
0xf3: {Sym: "risc_v", Description: "RISC-V"},
|
|
0xf7: {Sym: "bpf", Description: "Berkeley Packet Filter"},
|
|
0x101: {Sym: "wdc_65C816", Description: "WDC 65C816"},
|
|
}
|
|
|
|
const (
|
|
PT_NULL = 0
|
|
PT_LOAD = 1
|
|
PT_DYNAMIC = 2
|
|
PT_INTERP = 3
|
|
PT_NOTE = 4
|
|
PT_SHLIB = 5
|
|
PT_PHDR = 6
|
|
PT_TLS = 7
|
|
)
|
|
|
|
var phTypeNames = scalar.UintRangeToScalar{
|
|
{Range: [2]uint64{PT_NULL, PT_NULL}, S: scalar.Uint{Sym: "null", Description: "Unused element"}},
|
|
{Range: [2]uint64{PT_LOAD, PT_LOAD}, S: scalar.Uint{Sym: "load", Description: "Loadable segment"}},
|
|
{Range: [2]uint64{PT_DYNAMIC, PT_DYNAMIC}, S: scalar.Uint{Sym: "dynamic", Description: "Dynamic linking information"}},
|
|
{Range: [2]uint64{PT_INTERP, PT_INTERP}, S: scalar.Uint{Sym: "interp", Description: "Interpreter to invoke"}},
|
|
{Range: [2]uint64{PT_NOTE, PT_NOTE}, S: scalar.Uint{Sym: "note", Description: "Auxiliary information"}},
|
|
{Range: [2]uint64{PT_SHLIB, PT_SHLIB}, S: scalar.Uint{Sym: "shlib", Description: "Reserved but has unspecified"}},
|
|
{Range: [2]uint64{PT_PHDR, PT_PHDR}, S: scalar.Uint{Sym: "phdr", Description: "Program header location and size"}},
|
|
{Range: [2]uint64{PT_TLS, PT_TLS}, S: scalar.Uint{Sym: "tls", Description: "Thread-Local Storage template"}},
|
|
{Range: [2]uint64{0x6474e550, 0x6474e550}, S: scalar.Uint{Sym: "gnu_eh_frame", Description: "GNU frame unwind information"}},
|
|
{Range: [2]uint64{0x6474e551, 0x6474e551}, S: scalar.Uint{Sym: "gnu_stack", Description: "GNU stack permission"}},
|
|
{Range: [2]uint64{0x6474e552, 0x6474e552}, S: scalar.Uint{Sym: "gnu_relro", Description: "GNU read-only after relocation"}},
|
|
{Range: [2]uint64{0x60000000, 0x6fffffff}, S: scalar.Uint{Sym: "os", Description: "Operating system-specific"}},
|
|
{Range: [2]uint64{0x70000000, 0x7fffffff}, S: scalar.Uint{Sym: "proc", Description: "Processor-specific"}},
|
|
}
|
|
|
|
const (
|
|
NT_PRSTATUS = 1
|
|
NT_PRFPREG = 2
|
|
NT_PRPSINFO = 3
|
|
NT_TASKSTRUCT = 4
|
|
NT_AUXV = 6
|
|
NT_SIGINFO = 0x53494749 // "SIGI"
|
|
NT_FILE = 0x46494c45 // "FILE"
|
|
NT_PRXFPREG = 0x46e62b7f
|
|
NT_PPC_VMX = 0x100
|
|
NT_PPC_SPE = 0x101
|
|
NT_PPC_VSX = 0x102
|
|
NT_PPC_TAR = 0x103
|
|
NT_PPC_PPR = 0x104
|
|
NT_PPC_DSCR = 0x105
|
|
NT_PPC_EBB = 0x106
|
|
NT_PPC_PMU = 0x107
|
|
NT_PPC_TM_CGPR = 0x108
|
|
NT_PPC_TM_CFPR = 0x109
|
|
NT_PPC_TM_CVMX = 0x10a
|
|
NT_PPC_TM_CVSX = 0x10b
|
|
NT_PPC_TM_SPR = 0x10c
|
|
NT_PPC_TM_CTAR = 0x10d
|
|
NT_PPC_TM_CPPR = 0x10e
|
|
NT_PPC_TM_CDSCR = 0x10f
|
|
NT_PPC_PKEY = 0x110
|
|
NT_386_TLS = 0x200
|
|
NT_386_IOPERM = 0x201
|
|
NT_X86_XSTATE = 0x202
|
|
NT_S390_HIGH_GPRS = 0x300
|
|
NT_S390_TIMER = 0x301
|
|
NT_S390_TODCMP = 0x302
|
|
NT_S390_TODPREG = 0x303
|
|
NT_S390_CTRS = 0x304
|
|
NT_S390_PREFIX = 0x305
|
|
NT_S390_LAST_BREAK = 0x306
|
|
NT_S390_SYSTEM_CALL = 0x307
|
|
NT_S390_TDB = 0x308
|
|
NT_S390_VXRS_LOW = 0x309
|
|
NT_S390_VXRS_HIGH = 0x30a
|
|
NT_S390_GS_CB = 0x30b
|
|
NT_S390_GS_BC = 0x30c
|
|
NT_S390_RI_CB = 0x30d
|
|
NT_S390_PV_CPU_DATA = 0x30e
|
|
NT_ARM_VFP = 0x400
|
|
NT_ARM_TLS = 0x401
|
|
NT_ARM_HW_BREAK = 0x402
|
|
NT_ARM_HW_WATCH = 0x403
|
|
NT_ARM_SYSTEM_CALL = 0x404
|
|
NT_ARM_SVE = 0x405
|
|
NT_ARM_PAC_MASK = 0x406
|
|
NT_ARM_PACA_KEYS = 0x407
|
|
NT_ARM_PACG_KEYS = 0x408
|
|
NT_ARM_TAGGED_ADDR_CTRL = 0x409
|
|
NT_ARM_PAC_ENABLED_KEYS = 0x40a
|
|
NT_ARM_SSVE = 0x40b
|
|
NT_ARM_ZA = 0x40c
|
|
NT_ARC_V2 = 0x600
|
|
NT_VMCOREDD = 0x700
|
|
NT_MIPS_DSP = 0x800
|
|
NT_MIPS_FP_MODE = 0x801
|
|
NT_MIPS_MSA = 0x802
|
|
NT_LOONGARCH_CPUCFG = 0xa00
|
|
NT_LOONGARCH_CSR = 0xa01
|
|
NT_LOONGARCH_LSX = 0xa02
|
|
NT_LOONGARCH_LASX = 0xa03
|
|
NT_LOONGARCH_LBT = 0xa04
|
|
)
|
|
|
|
var coreNoteNames = scalar.UintMap{
|
|
NT_PRSTATUS: {Sym: "prstatus"},
|
|
NT_PRFPREG: {Sym: "prfpreg"},
|
|
NT_PRPSINFO: {Sym: "prpsinfo"},
|
|
NT_TASKSTRUCT: {Sym: "taskstruct"},
|
|
NT_AUXV: {Sym: "auxv"},
|
|
NT_SIGINFO: {Sym: "siginfo", Description: "Signal info"},
|
|
NT_FILE: {Sym: "file", Description: "File info"},
|
|
NT_PRXFPREG: {Sym: "prxfpreg"},
|
|
NT_PPC_SPE: {Sym: "ppc_spe", Description: "PowerPC SPE/EVR registers"},
|
|
NT_PPC_VSX: {Sym: "ppc_vsx", Description: "PowerPC VSX registers"},
|
|
NT_PPC_TAR: {Sym: "ppc_tar", Description: "Target Address Register"},
|
|
NT_PPC_PPR: {Sym: "ppc_ppr", Description: "Program Priority Register"},
|
|
NT_PPC_DSCR: {Sym: "ppc_dscr", Description: "Data Stream Control Register"},
|
|
NT_PPC_EBB: {Sym: "ppc_ebb", Description: "Event Based Branch Registers"},
|
|
NT_PPC_PMU: {Sym: "ppc_pmu", Description: "Performance Monitor Registers"},
|
|
NT_PPC_TM_CGPR: {Sym: "ppc_tm_cgpr", Description: "TM checkpointed GPR Registers"},
|
|
NT_PPC_TM_CFPR: {Sym: "ppc_tm_cfpr", Description: "TM checkpointed FPR Registers"},
|
|
NT_PPC_TM_CVMX: {Sym: "ppc_tm_cvmx", Description: "TM checkpointed VMX Registers"},
|
|
NT_PPC_TM_CVSX: {Sym: "ppc_tm_cvsx", Description: "TM checkpointed VSX Registers"},
|
|
NT_PPC_TM_SPR: {Sym: "ppc_tm_spr", Description: "TM Special Purpose Registers"},
|
|
NT_PPC_TM_CTAR: {Sym: "ppc_tm_ctar", Description: "TM checkpointed Target Address Register"},
|
|
NT_PPC_TM_CPPR: {Sym: "ppc_tm_cppr", Description: "TM checkpointed Program Priority Register"},
|
|
NT_PPC_TM_CDSCR: {Sym: "ppc_tm_cdscr", Description: "TM checkpointed Data Stream Control Register"},
|
|
NT_PPC_PKEY: {Sym: "ppc_pkey", Description: "Memory Protection Keys registers"},
|
|
NT_386_TLS: {Sym: "386_tls", Description: "i386 TLS slots (struct user_desc)"},
|
|
NT_386_IOPERM: {Sym: "386_ioperm", Description: "x86 io permission bitmap (1=deny)"},
|
|
NT_X86_XSTATE: {Sym: "x86_xstate", Description: "x86 extended state using xsave"},
|
|
NT_S390_HIGH_GPRS: {Sym: "s390_high_gprs", Description: "s390 upper register halves"},
|
|
NT_S390_TIMER: {Sym: "s390_timer", Description: "s390 timer register"},
|
|
NT_S390_TODCMP: {Sym: "s390_todcmp", Description: "s390 TOD clock comparator register"},
|
|
NT_S390_TODPREG: {Sym: "s390_todpreg", Description: "s390 TOD programmable register"},
|
|
NT_S390_CTRS: {Sym: "s390_ctrs", Description: "s390 control registers"},
|
|
NT_S390_PREFIX: {Sym: "s390_prefix", Description: "s390 prefix register"},
|
|
NT_S390_LAST_BREAK: {Sym: "s390_last_break", Description: "s390 breaking event address"},
|
|
NT_S390_SYSTEM_CALL: {Sym: "s390_system_call", Description: "s390 system call restart data"},
|
|
NT_S390_TDB: {Sym: "s390_tdb", Description: "s390 transaction diagnostic block"},
|
|
NT_S390_VXRS_LOW: {Sym: "s390_vxrs_low", Description: "s390 vector registers 0-15 upper half"},
|
|
NT_S390_VXRS_HIGH: {Sym: "s390_vxrs_high", Description: "s390 vector registers 16-31"},
|
|
NT_S390_GS_CB: {Sym: "s390_gs_cb", Description: "s390 guarded storage registers"},
|
|
NT_S390_GS_BC: {Sym: "s390_gs_bc", Description: "s390 guarded storage broadcast control block"},
|
|
NT_S390_RI_CB: {Sym: "s390_ri_cb", Description: "s390 runtime instrumentation"},
|
|
NT_S390_PV_CPU_DATA: {Sym: "s390_pv_cpu_data", Description: "s390 protvirt cpu dump data"},
|
|
NT_ARM_VFP: {Sym: "arm_vfp", Description: "ARM VFP/NEON registers"},
|
|
NT_ARM_TLS: {Sym: "arm_tls", Description: "ARM TLS register"},
|
|
NT_ARM_HW_BREAK: {Sym: "arm_hw_break", Description: "ARM hardware breakpoint registers"},
|
|
NT_ARM_HW_WATCH: {Sym: "arm_hw_watch", Description: "ARM hardware watchpoint registers"},
|
|
NT_ARM_SYSTEM_CALL: {Sym: "arm_system_call", Description: "ARM system call number"},
|
|
NT_ARM_SVE: {Sym: "arm_sve", Description: "ARM Scalable Vector Extension registers"},
|
|
NT_ARM_PAC_MASK: {Sym: "arm_pac_mask", Description: "ARM pointer authentication code masks"},
|
|
NT_ARM_PACA_KEYS: {Sym: "arm_paca_keys", Description: "ARM pointer authentication address keys"},
|
|
NT_ARM_PACG_KEYS: {Sym: "arm_pacg_keys", Description: "ARM pointer authentication generic key"},
|
|
NT_ARM_TAGGED_ADDR_CTRL: {Sym: "arm_tagged_addr_ctrl", Description: "arm64 tagged address control (prctl())"},
|
|
NT_ARM_PAC_ENABLED_KEYS: {Sym: "arm_pac_enabled_keys", Description: "arm64 ptr auth enabled keys (prctl())"},
|
|
NT_ARM_SSVE: {Sym: "arm_ssve", Description: "ARM Streaming SVE registers"},
|
|
NT_ARM_ZA: {Sym: "arm_za", Description: "ARM SME ZA registers"},
|
|
NT_ARC_V2: {Sym: "arc_v2", Description: "ARCv2 accumulator/extra registers"},
|
|
NT_VMCOREDD: {Sym: "vmcoredd", Description: "Vmcore Device Dump Note"},
|
|
NT_MIPS_DSP: {Sym: "mips_dsp", Description: "MIPS DSP ASE registers"},
|
|
NT_MIPS_FP_MODE: {Sym: "mips_fp_mode", Description: "MIPS floating-point mode"},
|
|
NT_MIPS_MSA: {Sym: "mips_msa", Description: "MIPS SIMD registers"},
|
|
NT_LOONGARCH_CPUCFG: {Sym: "loongarch_cpucfg", Description: "LoongArch CPU config registers"},
|
|
NT_LOONGARCH_CSR: {Sym: "loongarch_csr", Description: "LoongArch control and status registers"},
|
|
NT_LOONGARCH_LSX: {Sym: "loongarch_lsx", Description: "LoongArch Loongson SIMD Extension registers"},
|
|
NT_LOONGARCH_LASX: {Sym: "loongarch_lasx", Description: "LoongArch Loongson Advanced SIMD Extension registers"},
|
|
NT_LOONGARCH_LBT: {Sym: "loongarch_lbt", Description: "LoongArch Loongson Binary Translation registers"},
|
|
}
|
|
|
|
const (
|
|
SHT_NULL = 0x0
|
|
SHT_PROGBITS = 0x1
|
|
SHT_SYMTAB = 0x2
|
|
SHT_STRTAB = 0x3
|
|
SHT_RELA = 0x4
|
|
SHT_HASH = 0x5
|
|
SHT_DYNAMIC = 0x6
|
|
SHT_NOTE = 0x7
|
|
SHT_NOBITS = 0x8
|
|
SHT_REL = 0x9
|
|
SHT_SHLIB = 0x0a
|
|
SHT_DYNSYM = 0x0b
|
|
SHT_INIT_ARRAY = 0x0e
|
|
SHT_FINI_ARRAY = 0x0f
|
|
SHT_PREINIT_ARRAY = 0x10
|
|
SHT_GROUP = 0x11
|
|
SHT_SYMTAB_SHNDX = 0x12
|
|
SHT_GNU_HASH = 0x6ffffff6
|
|
)
|
|
|
|
var sectionHeaderTypeMap = scalar.UintMap{
|
|
SHT_NULL: {Sym: "null", Description: "Header inactive"},
|
|
SHT_PROGBITS: {Sym: "progbits", Description: "Information defined by the program"},
|
|
SHT_SYMTAB: {Sym: "symtab", Description: "Symbol table"},
|
|
SHT_STRTAB: {Sym: "strtab", Description: "String table"},
|
|
SHT_RELA: {Sym: "rela", Description: "Relocation entries with explicit addends"},
|
|
SHT_HASH: {Sym: "hash", Description: "Symbol hash table"},
|
|
SHT_DYNAMIC: {Sym: "dynamic", Description: "Information for dynamic linking"},
|
|
SHT_NOTE: {Sym: "note", Description: "Information that marks the file in some way"},
|
|
SHT_NOBITS: {Sym: "nobits", Description: "No space in the file"},
|
|
SHT_REL: {Sym: "rel", Description: "Relocation entries without explicit addends"},
|
|
SHT_SHLIB: {Sym: "shlib", Description: "Reserved but has unspecified semantics"},
|
|
SHT_DYNSYM: {Sym: "dynsym", Description: "Dynamic linking symbol table"},
|
|
SHT_INIT_ARRAY: {Sym: "init_array", Description: "Initialization functions"},
|
|
SHT_FINI_ARRAY: {Sym: "fini_array", Description: "Termination functions"},
|
|
SHT_PREINIT_ARRAY: {Sym: "preinit_array", Description: "Pre initialization functions"},
|
|
SHT_GROUP: {Sym: "group", Description: "Section group"},
|
|
SHT_SYMTAB_SHNDX: {Sym: "symtab_shndx", Description: ""},
|
|
SHT_GNU_HASH: {Sym: "gnu_hash", Description: "GNU symbol hash table"},
|
|
}
|
|
|
|
const (
|
|
STRTAB_DYNSTR = ".dynstr"
|
|
STRTAB_SHSTRTAB = ".shstrtab"
|
|
STRTAB_STRTAB = ".strtab"
|
|
)
|
|
|
|
const (
|
|
DT_NULL = 0
|
|
DT_NEEDED = 1
|
|
DT_PLTRELSZ = 2
|
|
DT_PLTGOT = 3
|
|
DT_HASH = 4
|
|
DT_STRTAB = 5
|
|
DT_SYMTAB = 6
|
|
DT_RELA = 7
|
|
DT_RELASZ = 8
|
|
DT_RELAENT = 9
|
|
DT_STRSZ = 10
|
|
DT_SYMENT = 11
|
|
DT_INIT = 12
|
|
DT_FINI = 13
|
|
DT_SONAME = 14
|
|
DT_RPATH = 15
|
|
DT_SYMBOLIC = 16
|
|
DT_REL = 17
|
|
DT_RELSZ = 18
|
|
DT_RELENT = 19
|
|
DT_PLTREL = 20
|
|
DT_DEBUG = 21
|
|
DT_TEXTREL = 22
|
|
DT_JMPREL = 23
|
|
DT_BIND_NOW = 24
|
|
DT_INIT_ARRAY = 25
|
|
DT_FINI_ARRAY = 26
|
|
DT_INIT_ARRAYSZ = 27
|
|
DT_FINI_ARRAYSZ = 28
|
|
DT_RUNPATH = 29
|
|
DT_FLAGS = 30 // TODO: flag map
|
|
DT_ENCODING = 32 // or DT_PREINIT_ARRAY ?
|
|
DT_PREINIT_ARRAYSZ = 33
|
|
DT_LOOS = 0x6000000D
|
|
DT_HIOS = 0x6ffff000
|
|
DT_LOPROC = 0x70000000
|
|
DT_HIPROC = 0x7fffffff
|
|
)
|
|
|
|
const (
|
|
dUnIgnored = iota
|
|
dUnVal
|
|
dUnPtr
|
|
dUnUnspecified
|
|
)
|
|
|
|
type dtEntry struct {
|
|
r [2]uint64
|
|
dUn int
|
|
s scalar.Uint
|
|
}
|
|
|
|
type dynamicTableEntries []dtEntry
|
|
|
|
func (d dynamicTableEntries) lookup(u uint64) (dtEntry, bool) {
|
|
for _, de := range d {
|
|
if de.r[0] >= u && de.r[1] <= u {
|
|
return de, true
|
|
}
|
|
}
|
|
return dtEntry{}, false
|
|
}
|
|
|
|
func (d dynamicTableEntries) MapUint(s scalar.Uint) (scalar.Uint, error) {
|
|
u := s.Actual
|
|
if de, ok := d.lookup(u); ok {
|
|
s = de.s
|
|
s.Actual = u
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
var dynamicTableMap = dynamicTableEntries{
|
|
{r: [2]uint64{DT_NULL, DT_NULL}, dUn: dUnIgnored, s: scalar.Uint{Sym: "null", Description: "Marks end of dynamic section"}},
|
|
{r: [2]uint64{DT_NEEDED, DT_NEEDED}, dUn: dUnVal, s: scalar.Uint{Sym: "needed", Description: "String table offset to name of a needed library"}},
|
|
{r: [2]uint64{DT_PLTRELSZ, DT_PLTRELSZ}, dUn: dUnVal, s: scalar.Uint{Sym: "pltrelsz", Description: "Size in bytes of PLT relocation entries"}},
|
|
{r: [2]uint64{DT_PLTGOT, DT_PLTGOT}, dUn: dUnPtr, s: scalar.Uint{Sym: "pltgot", Description: "Address of PLT and/or GOT"}},
|
|
{r: [2]uint64{DT_HASH, DT_HASH}, dUn: dUnPtr, s: scalar.Uint{Sym: "hash", Description: "Address of symbol hash table"}},
|
|
{r: [2]uint64{DT_STRTAB, DT_STRTAB}, dUn: dUnPtr, s: scalar.Uint{Sym: "strtab", Description: "Address of string table"}},
|
|
{r: [2]uint64{DT_SYMTAB, DT_SYMTAB}, dUn: dUnPtr, s: scalar.Uint{Sym: "symtab", Description: "Address of symbol table"}},
|
|
{r: [2]uint64{DT_RELA, DT_RELA}, dUn: dUnPtr, s: scalar.Uint{Sym: "rela", Description: "Address of Rela relocation table"}},
|
|
{r: [2]uint64{DT_RELASZ, DT_RELASZ}, dUn: dUnVal, s: scalar.Uint{Sym: "relasz", Description: "Size in bytes of the Rela relocation table"}},
|
|
{r: [2]uint64{DT_RELAENT, DT_RELAENT}, dUn: dUnVal, s: scalar.Uint{Sym: "relaent", Description: "Size in bytes of a Rela relocation table entry"}},
|
|
{r: [2]uint64{DT_STRSZ, DT_STRSZ}, dUn: dUnVal, s: scalar.Uint{Sym: "strsz", Description: "Size in bytes of string table"}},
|
|
{r: [2]uint64{DT_SYMENT, DT_SYMENT}, dUn: dUnVal, s: scalar.Uint{Sym: "syment", Description: "Size in bytes of a symbol table entry"}},
|
|
{r: [2]uint64{DT_INIT, DT_INIT}, dUn: dUnPtr, s: scalar.Uint{Sym: "init", Description: "Address of the initialization function"}},
|
|
{r: [2]uint64{DT_FINI, DT_FINI}, dUn: dUnPtr, s: scalar.Uint{Sym: "fini", Description: "Address of the termination function"}},
|
|
{r: [2]uint64{DT_SONAME, DT_SONAME}, dUn: dUnVal, s: scalar.Uint{Sym: "soname", Description: "String table offset to name of shared object"}},
|
|
{r: [2]uint64{DT_RPATH, DT_RPATH}, dUn: dUnVal, s: scalar.Uint{Sym: "rpath", Description: "String table offset to library search path (deprecated)"}},
|
|
{r: [2]uint64{DT_SYMBOLIC, DT_SYMBOLIC}, dUn: dUnIgnored, s: scalar.Uint{Sym: "symbolic", Description: "Alert linker to search this shared object before the executable for symbols DT_REL Address of Rel relocation table"}},
|
|
{r: [2]uint64{DT_REL, DT_REL}, dUn: dUnPtr, s: scalar.Uint{Sym: "rel", Description: ""}},
|
|
{r: [2]uint64{DT_RELSZ, DT_RELSZ}, dUn: dUnVal, s: scalar.Uint{Sym: "relsz", Description: "Size in bytes of Rel relocation table"}},
|
|
{r: [2]uint64{DT_RELENT, DT_RELENT}, dUn: dUnVal, s: scalar.Uint{Sym: "relent", Description: "Size in bytes of a Rel table entry"}},
|
|
{r: [2]uint64{DT_PLTREL, DT_PLTREL}, dUn: dUnVal, s: scalar.Uint{Sym: "pltrel", Description: "Type of relocation entry to which the PLT refers (Rela or Rel)"}},
|
|
{r: [2]uint64{DT_DEBUG, DT_DEBUG}, dUn: dUnPtr, s: scalar.Uint{Sym: "debug", Description: "Undefined use for debugging"}},
|
|
{r: [2]uint64{DT_TEXTREL, DT_TEXTREL}, dUn: dUnIgnored, s: scalar.Uint{Sym: "textrel", Description: "Absence of this entry indicates that no relocation entries should apply to a nonwritable segment"}},
|
|
{r: [2]uint64{DT_JMPREL, DT_JMPREL}, dUn: dUnPtr, s: scalar.Uint{Sym: "jmprel", Description: "Address of relocation entries associated solely with the PLT"}},
|
|
{r: [2]uint64{DT_BIND_NOW, DT_BIND_NOW}, dUn: dUnIgnored, s: scalar.Uint{Sym: "bind_now", Description: "Instruct dynamic linker to process all relocations before transferring control to the executable"}},
|
|
{r: [2]uint64{DT_INIT_ARRAY, DT_INIT_ARRAY}, dUn: dUnPtr, s: scalar.Uint{Sym: "init_array", Description: "Address of the array of pointers to initialization functions"}},
|
|
{r: [2]uint64{DT_FINI_ARRAY, DT_FINI_ARRAY}, dUn: dUnPtr, s: scalar.Uint{Sym: "fini_array", Description: "Address of the array of pointers to termination functions"}},
|
|
{r: [2]uint64{DT_INIT_ARRAYSZ, DT_INIT_ARRAYSZ}, dUn: dUnVal, s: scalar.Uint{Sym: "init_arraysz", Description: "Size in bytes of the array of initialization functions"}},
|
|
{r: [2]uint64{DT_FINI_ARRAYSZ, DT_FINI_ARRAYSZ}, dUn: dUnVal, s: scalar.Uint{Sym: "fini_arraysz", Description: "Size in bytes of the array of termination functions "}},
|
|
{r: [2]uint64{DT_RUNPATH, DT_RUNPATH}, dUn: dUnVal, s: scalar.Uint{Sym: "runpath", Description: "String table offset to library search path"}},
|
|
{r: [2]uint64{DT_FLAGS, DT_FLAGS}, dUn: dUnVal, s: scalar.Uint{Sym: "flags", Description: "Flag values specific to the object being loaded"}}, // TODO: flag ma}},
|
|
{r: [2]uint64{DT_ENCODING, DT_ENCODING}, dUn: dUnUnspecified, s: scalar.Uint{Sym: "encoding", Description: ""}}, // or DT_PREINIT_ARRAY }},
|
|
{r: [2]uint64{DT_PREINIT_ARRAYSZ, DT_PREINIT_ARRAYSZ}, dUn: dUnVal, s: scalar.Uint{Sym: "preinit_arraysz", Description: "Address of the array of pointers to pre-initialization functions"}},
|
|
{r: [2]uint64{DT_LOOS, DT_HIOS}, dUn: dUnUnspecified, s: scalar.Uint{Sym: "lo", Description: "Operating system-specific semantics"}},
|
|
{r: [2]uint64{DT_LOPROC, DT_HIPROC}, dUn: dUnUnspecified, s: scalar.Uint{Sym: "proc", Description: "Processor-specific semantics"}},
|
|
}
|
|
|
|
var symbolTableBindingMap = scalar.UintMapSymStr{
|
|
0: "local",
|
|
1: "global",
|
|
2: "weak",
|
|
10: "loos",
|
|
12: "hios",
|
|
13: "proc",
|
|
14: "proc",
|
|
15: "proc",
|
|
}
|
|
|
|
var symbolTableTypeMap = scalar.UintMapSymStr{
|
|
0: "notype",
|
|
1: "object",
|
|
2: "func",
|
|
3: "section",
|
|
4: "file",
|
|
5: "common",
|
|
6: "tls",
|
|
10: "loos",
|
|
12: "hios",
|
|
13: "proc",
|
|
14: "proc",
|
|
15: "proc",
|
|
}
|
|
|
|
var symbolTableVisibilityMap = scalar.UintMapSymStr{
|
|
0: "default",
|
|
1: "internal",
|
|
2: "hidden",
|
|
3: "protected",
|
|
}
|
|
|
|
func strIndexNull(idx int, s string) string {
|
|
if idx > len(s) {
|
|
return ""
|
|
}
|
|
i := strings.IndexByte(s[idx:], 0)
|
|
if i == -1 {
|
|
return s
|
|
}
|
|
return s[idx : idx+i]
|
|
}
|
|
|
|
type strTable string
|
|
|
|
func (m strTable) MapUint(s scalar.Uint) (scalar.Uint, error) {
|
|
s.Sym = strIndexNull(int(s.Actual), string(m))
|
|
return s, nil
|
|
}
|
|
|
|
func elfDecodeSymbolHashTable(d *decode.D) {
|
|
nBucket := d.FieldU32("nbucket")
|
|
nChain := d.FieldU32("nchain")
|
|
|
|
repeatFn := func(r int, fn func(d *decode.D)) func(d *decode.D) {
|
|
return func(d *decode.D) {
|
|
for i := 0; i < r; i++ {
|
|
fn(d)
|
|
}
|
|
}
|
|
}
|
|
|
|
d.FieldArray("buckets", repeatFn(int(nBucket), func(d *decode.D) { d.FieldU32("bucket") }))
|
|
d.FieldArray("chains", repeatFn(int(nChain), func(d *decode.D) { d.FieldU32("chain") }))
|
|
}
|
|
|
|
func elfDecodeSymbolTable(d *decode.D, ec elfContext, nEntries int, strTab string) {
|
|
for i := 0; i < nEntries; i++ {
|
|
d.FieldStruct("symbol", func(d *decode.D) {
|
|
switch ec.archBits {
|
|
case 32:
|
|
d.FieldU32("name", strTable(strTab))
|
|
d.FieldU32("value")
|
|
d.FieldU32("size")
|
|
d.FieldU4("bind", symbolTableBindingMap)
|
|
d.FieldU4("type", symbolTableTypeMap)
|
|
d.FieldU6("other_unused")
|
|
d.FieldU2("visibility", symbolTableVisibilityMap)
|
|
d.FieldU16("shndx")
|
|
case 64:
|
|
d.FieldU32("name", strTable(strTab))
|
|
d.FieldU4("bind", symbolTableBindingMap)
|
|
d.FieldU4("type", symbolTableTypeMap)
|
|
d.FieldU6("other_unused")
|
|
d.FieldU2("visibility", symbolTableVisibilityMap)
|
|
d.FieldU16("shndx")
|
|
d.FieldU64("value")
|
|
d.FieldU64("size")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func elfDecodeGNUHash(d *decode.D, ec elfContext, size int64, strTab string) {
|
|
d.FramedFn(size, func(d *decode.D) {
|
|
nBuckets := d.FieldU32("nbuckets")
|
|
d.FieldU32("symndx")
|
|
maskwords := d.FieldU32("maskwords")
|
|
d.FieldU32("shift2")
|
|
|
|
repeatFn := func(r int, fn func(d *decode.D)) func(d *decode.D) {
|
|
return func(d *decode.D) {
|
|
for i := 0; i < r; i++ {
|
|
fn(d)
|
|
}
|
|
}
|
|
}
|
|
// TODO: possible to map to symbols?
|
|
_ = strTab
|
|
d.FieldArray("bloom_filter", repeatFn(int(maskwords), func(d *decode.D) { d.FieldU("maskword", ec.archBits) }))
|
|
d.FieldArray("buckets", repeatFn(int(nBuckets), func(d *decode.D) { d.FieldU32("bucket") }))
|
|
d.FieldArray("values", func(d *decode.D) {
|
|
for !d.End() {
|
|
d.FieldU32("value")
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
type dynamicContext struct {
|
|
entries int
|
|
strTabPtr int64
|
|
strSzVal int64
|
|
strTab string
|
|
symEnt int64
|
|
}
|
|
|
|
func elfReadDynamicTags(d *decode.D, ec *elfContext) dynamicContext {
|
|
var strTabPtr int64
|
|
var strSzVal int64
|
|
var symEnt int64
|
|
var entries int
|
|
|
|
seenNull := false
|
|
for !seenNull {
|
|
entries++
|
|
tag := d.U(ec.archBits)
|
|
valPtr := d.U(ec.archBits)
|
|
|
|
switch tag {
|
|
case DT_STRTAB:
|
|
strTabPtr = int64(valPtr) * 8
|
|
case DT_STRSZ:
|
|
strSzVal = int64(valPtr) * 8
|
|
case DT_SYMENT:
|
|
symEnt = int64(valPtr) * 8
|
|
case DT_NULL:
|
|
seenNull = true
|
|
}
|
|
}
|
|
|
|
return dynamicContext{
|
|
entries: entries,
|
|
strTabPtr: strTabPtr,
|
|
strSzVal: strSzVal,
|
|
symEnt: symEnt,
|
|
}
|
|
}
|
|
|
|
type symbol struct {
|
|
name uint64
|
|
value uint64
|
|
}
|
|
|
|
func elfReadSymbolTable(d *decode.D, ec *elfContext, sh sectionHeader) []symbol {
|
|
var ss []symbol
|
|
|
|
for i := 0; i < int(sh.size/sh.entSize); i++ {
|
|
var name uint64
|
|
var value uint64
|
|
switch ec.archBits {
|
|
case 32:
|
|
name = d.U32() // name
|
|
value = d.U32() // value
|
|
d.U32() // size
|
|
d.U4() // bind
|
|
d.U4() // type
|
|
d.U6() // other_unused
|
|
d.U2() // visibility
|
|
d.U16() // shndx
|
|
case 64:
|
|
name = d.U32() // name
|
|
d.U4() // bind
|
|
d.U4() // type
|
|
d.U6() // other_unused
|
|
d.U2() // visibility
|
|
d.U16() // shndx
|
|
value = d.U64() // value
|
|
d.U64() // size
|
|
}
|
|
ss = append(ss, symbol{name: name, value: value})
|
|
}
|
|
|
|
return ss
|
|
}
|
|
|
|
type sectionHeader struct {
|
|
addr int64
|
|
offset int64
|
|
size int64
|
|
entSize int64
|
|
name int
|
|
typ int
|
|
dc dynamicContext // if SHT_DYNAMIC
|
|
symbols []symbol
|
|
}
|
|
|
|
const maxStrTabSize = 100_000_000
|
|
|
|
func readStrTab(d *decode.D, firstBit int64, nBytes int64) string {
|
|
if nBytes > maxStrTabSize {
|
|
d.Errorf("string table too large %d > %d", nBytes, maxStrTabSize)
|
|
}
|
|
return string(d.BytesRange(firstBit, int(nBytes)))
|
|
}
|
|
|
|
func elfReadSectionHeaders(d *decode.D, ec *elfContext) {
|
|
for i := 0; i < ec.shNum; i++ {
|
|
d.SeekAbs(ec.shOff + int64(i)*ec.shEntSize)
|
|
var sh sectionHeader
|
|
|
|
switch ec.archBits {
|
|
case 32:
|
|
sh.name = int(d.U32())
|
|
sh.typ = int(d.U32())
|
|
d.U32() // flags
|
|
sh.addr = int64(d.U32() * 8) // addr
|
|
sh.offset = int64(d.U32()) * 8
|
|
sh.size = int64(d.U32()) * 8
|
|
d.U32() // link
|
|
d.U32() // info
|
|
d.U32() // addralign
|
|
sh.entSize = int64(d.U32()) * 8
|
|
case 64:
|
|
sh.name = int(d.U32())
|
|
sh.typ = int(d.U32())
|
|
d.U64() // addr
|
|
sh.addr = int64(d.U64() * 8) // flags
|
|
sh.offset = int64(d.U64()) * 8
|
|
sh.size = int64(d.U64()) * 8
|
|
d.U32() // link
|
|
d.U32() // info
|
|
d.U64() // addralign
|
|
sh.entSize = int64(d.U64()) * 8
|
|
default:
|
|
panic("unreachable")
|
|
}
|
|
|
|
switch sh.typ {
|
|
case SHT_DYNAMIC:
|
|
d.SeekAbs(sh.offset)
|
|
sh.dc = elfReadDynamicTags(d, ec)
|
|
case SHT_SYMTAB:
|
|
d.SeekAbs(sh.offset)
|
|
sh.symbols = elfReadSymbolTable(d, ec, sh)
|
|
}
|
|
|
|
ec.sections = append(ec.sections, sh)
|
|
}
|
|
|
|
// for dynamic linking sections find offset to string table by looking up
|
|
// section by address using string stable address
|
|
for i := range ec.sections {
|
|
sh := &ec.sections[i]
|
|
if sh.typ != SHT_DYNAMIC {
|
|
continue
|
|
}
|
|
if i, ok := ec.sectionIndexByAddr(sh.dc.strTabPtr); ok {
|
|
strTabSh := ec.sections[i]
|
|
sh.dc.strTab = readStrTab(d, strTabSh.offset, sh.dc.strSzVal/8)
|
|
}
|
|
}
|
|
|
|
// provide default empty string tables to be more robust
|
|
ec.strTabMap = map[string]string{
|
|
STRTAB_DYNSTR: "",
|
|
STRTAB_SHSTRTAB: "",
|
|
STRTAB_STRTAB: "",
|
|
}
|
|
var shStrTab string
|
|
if ec.shStrNdx < len(ec.sections) {
|
|
shStr := ec.sections[ec.shStrNdx]
|
|
shStrTab = readStrTab(d, shStr.offset, shStr.size/8)
|
|
|
|
for _, sh := range ec.sections {
|
|
if sh.typ != SHT_STRTAB {
|
|
continue
|
|
}
|
|
ec.strTabMap[strIndexNull(sh.name, shStrTab)] = readStrTab(d, sh.offset, sh.size/8)
|
|
}
|
|
}
|
|
}
|
|
|
|
type elfContext struct {
|
|
archBits int
|
|
typ int
|
|
machine int
|
|
endian decode.Endian
|
|
|
|
phOff int64
|
|
phNum int
|
|
phSize int64
|
|
|
|
shOff int64
|
|
shNum int
|
|
shEntSize int64
|
|
|
|
shStrNdx int
|
|
|
|
sections []sectionHeader
|
|
strTabMap map[string]string
|
|
}
|
|
|
|
func (ec *elfContext) sectionIndexByAddr(addr int64) (int, bool) {
|
|
for i, s := range ec.sections {
|
|
if s.addr == addr {
|
|
return i, true
|
|
}
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
func elfDecodeHeader(d *decode.D, ec *elfContext) {
|
|
var class uint64
|
|
var archBits int
|
|
var endian uint64
|
|
|
|
d.FieldStruct("ident", func(d *decode.D) {
|
|
d.FieldRawLen("magic", 4*8, d.AssertBitBuf([]byte("\x7fELF")))
|
|
class = d.FieldU8("class", classBits)
|
|
endian = d.FieldU8("data", endianNames)
|
|
d.FieldU8("version")
|
|
d.FieldU8("os_abi", osABINames)
|
|
d.FieldU8("abi_version")
|
|
d.FieldRawLen("pad", 7*8, d.BitBufIsZero())
|
|
})
|
|
|
|
switch class {
|
|
case CLASS_32:
|
|
archBits = 32
|
|
case CLASS_64:
|
|
archBits = 64
|
|
default:
|
|
d.Fatalf("unknown class %d", class)
|
|
}
|
|
|
|
switch endian {
|
|
case LITTLE_ENDIAN:
|
|
d.Endian = decode.LittleEndian
|
|
case BIG_ENDIAN:
|
|
d.Endian = decode.BigEndian
|
|
default:
|
|
d.Fatalf("unknown endian %d", endian)
|
|
}
|
|
|
|
typ := d.FieldU16("type", typeNames, scalar.UintHex)
|
|
machine := d.FieldU16("machine", machineNames, scalar.UintHex)
|
|
d.FieldU32("version")
|
|
d.FieldU("entry", archBits)
|
|
phOff := d.FieldU("phoff", archBits)
|
|
shOff := d.FieldU("shoff", archBits)
|
|
d.FieldU32("flags")
|
|
d.FieldU16("ehsize")
|
|
phSize := d.FieldU16("phentsize")
|
|
phNum := d.FieldU16("phnum")
|
|
shEntSize := d.FieldU16("shentsize")
|
|
shNum := d.FieldU16("shnum")
|
|
shStrNdx := d.FieldU16("shstrndx")
|
|
|
|
ec.archBits = archBits
|
|
ec.endian = d.Endian
|
|
ec.typ = int(typ)
|
|
ec.machine = int(machine)
|
|
ec.phOff = int64(phOff) * 8
|
|
ec.phNum = int(phNum)
|
|
ec.phSize = int64(phSize) * 8
|
|
ec.shOff = int64(shOff) * 8
|
|
ec.shNum = int(shNum)
|
|
ec.shEntSize = int64(shEntSize) * 8
|
|
ec.shStrNdx = int(shStrNdx)
|
|
}
|
|
|
|
func elfDecodeProgramHeader(d *decode.D, ec elfContext) {
|
|
pFlags := func(d *decode.D) {
|
|
d.FieldStruct("flags", func(d *decode.D) {
|
|
if d.Endian == decode.LittleEndian {
|
|
d.FieldU5("unused0")
|
|
d.FieldBool("r")
|
|
d.FieldBool("w")
|
|
d.FieldBool("x")
|
|
d.FieldU24("unused1")
|
|
} else {
|
|
d.FieldU29("unused0")
|
|
d.FieldBool("r")
|
|
d.FieldBool("w")
|
|
d.FieldBool("x")
|
|
}
|
|
})
|
|
}
|
|
|
|
var typ uint64
|
|
var offset uint64
|
|
var size uint64
|
|
|
|
switch ec.archBits {
|
|
case 32:
|
|
typ = d.FieldU32("type", phTypeNames)
|
|
offset = d.FieldU("offset", ec.archBits, scalar.UintHex)
|
|
d.FieldU("vaddr", ec.archBits, scalar.UintHex)
|
|
d.FieldU("paddr", ec.archBits, scalar.UintHex)
|
|
size = d.FieldU32("filesz")
|
|
d.FieldU32("memsz")
|
|
pFlags(d)
|
|
d.FieldU32("align")
|
|
case 64:
|
|
typ = d.FieldU32("type", phTypeNames)
|
|
pFlags(d)
|
|
offset = d.FieldU("offset", ec.archBits, scalar.UintHex)
|
|
d.FieldU("vaddr", ec.archBits, scalar.UintHex)
|
|
d.FieldU("paddr", ec.archBits, scalar.UintHex)
|
|
size = d.FieldU64("filesz")
|
|
d.FieldU64("memsz")
|
|
d.FieldU64("align")
|
|
}
|
|
|
|
d.RangeFn(int64(offset*8), int64(size*8), func(d *decode.D) {
|
|
switch {
|
|
case typ == PT_NOTE:
|
|
d.FieldArray("notes", func(d *decode.D) {
|
|
for !d.End() {
|
|
d.FieldStruct("note", func(d *decode.D) {
|
|
// elf manpage says this is 32 or 64 bit but it seems it is always 32
|
|
// and that is also what readelf external.h says
|
|
nameSz := d.FieldU32("n_namesz")
|
|
descSz := d.FieldU32("n_descsz")
|
|
if ec.typ == ET_CORE {
|
|
d.FieldU32("n_type", coreNoteNames, scalar.UintHex)
|
|
} else {
|
|
d.FieldU32("n_type", scalar.UintHex)
|
|
}
|
|
d.FieldUTF8NullFixedLen("name", int(nameSz))
|
|
nameAlign := d.AlignBits(4 * 8)
|
|
if nameAlign != 0 {
|
|
d.FieldRawLen("name_align", int64(nameAlign))
|
|
}
|
|
d.FieldRawLen("desc", int64(descSz)*8)
|
|
descAlign := d.AlignBits(4 * 8)
|
|
if descAlign != 0 {
|
|
d.FieldRawLen("decs_align", int64(descAlign))
|
|
}
|
|
})
|
|
}
|
|
})
|
|
default:
|
|
d.FieldRawLen("data", d.BitsLeft())
|
|
}
|
|
})
|
|
}
|
|
|
|
func elfDecodeProgramHeaders(d *decode.D, ec elfContext) {
|
|
for i := 0; i < ec.phNum; i++ {
|
|
d.FieldStruct("program_header", func(d *decode.D) {
|
|
d.SeekAbs(ec.phOff + int64(i)*ec.phSize)
|
|
elfDecodeProgramHeader(d, ec)
|
|
})
|
|
}
|
|
}
|
|
|
|
func elfDecodeDynamicTag(d *decode.D, ec elfContext, dc dynamicContext) {
|
|
dtTag := d.FieldU("tag", ec.archBits, dynamicTableMap)
|
|
name := "unspecified"
|
|
dfMapper := scalar.UintHex
|
|
if de, ok := dynamicTableMap.lookup(dtTag); ok {
|
|
switch de.dUn {
|
|
case dUnIgnored:
|
|
name = "ignored"
|
|
case dUnVal:
|
|
name = "val"
|
|
dfMapper = scalar.UintDec
|
|
case dUnPtr:
|
|
name = "ptr"
|
|
}
|
|
}
|
|
|
|
switch dtTag {
|
|
case DT_NEEDED:
|
|
d.FieldU(name, ec.archBits, dfMapper, strTable(dc.strTab))
|
|
case DT_HASH:
|
|
v := d.FieldU(name, ec.archBits, dfMapper)
|
|
if i, ok := ec.sectionIndexByAddr(int64(v) * 8); ok {
|
|
d.FieldValueUint("section_index", uint64(i))
|
|
}
|
|
case DT_SYMTAB,
|
|
DT_STRTAB,
|
|
DT_PLTGOT,
|
|
DT_JMPREL,
|
|
DT_INIT,
|
|
DT_FINI:
|
|
v := d.FieldU(name, ec.archBits, dfMapper)
|
|
if i, ok := ec.sectionIndexByAddr(int64(v) * 8); ok {
|
|
d.FieldValueUint("section_index", uint64(i))
|
|
}
|
|
default:
|
|
d.FieldU(name, ec.archBits, dfMapper)
|
|
}
|
|
}
|
|
|
|
func elfDecodeDynamicTags(d *decode.D, ec elfContext, dc dynamicContext) {
|
|
for i := 0; i < dc.entries; i++ {
|
|
d.FieldStruct("dynamic_tags", func(d *decode.D) {
|
|
elfDecodeDynamicTag(d, ec, dc)
|
|
})
|
|
}
|
|
}
|
|
|
|
func elfDecodeSectionHeader(d *decode.D, ec elfContext, sh sectionHeader) {
|
|
shFlags := func(d *decode.D, archBits int) {
|
|
d.FieldStruct("flags", func(d *decode.D) {
|
|
if d.Endian == decode.LittleEndian {
|
|
d.FieldBool("link_order")
|
|
d.FieldBool("info_link")
|
|
d.FieldBool("strings")
|
|
d.FieldBool("merge")
|
|
d.FieldU1("unused0")
|
|
d.FieldBool("execinstr")
|
|
d.FieldBool("alloc")
|
|
d.FieldBool("write")
|
|
d.FieldBool("tls")
|
|
d.FieldBool("group")
|
|
d.FieldBool("os_nonconforming")
|
|
|
|
d.FieldU9("unused1")
|
|
|
|
d.FieldU8("os_specific")
|
|
d.FieldU4("processor_specific")
|
|
if archBits == 64 {
|
|
d.FieldU32("unused2")
|
|
}
|
|
} else {
|
|
// TODO: add.FieldUnused that is per decoder?
|
|
if archBits == 64 {
|
|
d.FieldU32("unused0")
|
|
}
|
|
d.FieldU4("processor_specific")
|
|
d.FieldU8("os_specific")
|
|
d.FieldU9("unused1")
|
|
d.FieldBool("tls")
|
|
d.FieldBool("group")
|
|
d.FieldBool("os_nonconforming")
|
|
d.FieldBool("link_order")
|
|
d.FieldBool("info_link")
|
|
d.FieldBool("strings")
|
|
d.FieldBool("merge")
|
|
d.FieldU1("unused2")
|
|
d.FieldBool("execinstr")
|
|
d.FieldBool("alloc")
|
|
d.FieldBool("write")
|
|
}
|
|
})
|
|
}
|
|
|
|
var offset int64
|
|
var size int64
|
|
var entSize int64
|
|
var typ uint64
|
|
|
|
switch ec.archBits {
|
|
case 32:
|
|
d.FieldU32("name", strTable(ec.strTabMap[STRTAB_SHSTRTAB]))
|
|
typ = d.FieldU32("type", sectionHeaderTypeMap, scalar.UintHex)
|
|
shFlags(d, ec.archBits)
|
|
d.FieldU("addr", ec.archBits, scalar.UintHex)
|
|
offset = int64(d.FieldU("offset", ec.archBits)) * 8
|
|
size = int64(d.FieldU32("size", scalar.UintHex) * 8)
|
|
d.FieldU32("link")
|
|
d.FieldU32("info")
|
|
d.FieldU32("addralign")
|
|
entSize = int64(d.FieldU32("entsize") * 8)
|
|
case 64:
|
|
d.FieldU32("name", strTable(ec.strTabMap[STRTAB_SHSTRTAB]))
|
|
typ = d.FieldU32("type", sectionHeaderTypeMap, scalar.UintHex)
|
|
shFlags(d, ec.archBits)
|
|
d.FieldU("addr", ec.archBits, scalar.UintHex)
|
|
offset = int64(d.FieldU("offset", ec.archBits, scalar.UintHex) * 8)
|
|
size = int64(d.FieldU64("size") * 8)
|
|
d.FieldU32("link")
|
|
d.FieldU32("info")
|
|
d.FieldU64("addralign")
|
|
entSize = int64(d.FieldU64("entsize") * 8)
|
|
}
|
|
|
|
if typ == SHT_NOBITS {
|
|
// section occupies no space in file
|
|
return
|
|
}
|
|
|
|
d.SeekAbs(offset)
|
|
switch typ {
|
|
case SHT_STRTAB:
|
|
d.FieldUTF8("string", int(size/8))
|
|
case SHT_DYNAMIC:
|
|
d.FieldArray("dynamic_tags", func(d *decode.D) {
|
|
elfDecodeDynamicTags(d, ec, sh.dc)
|
|
})
|
|
case SHT_HASH:
|
|
d.FieldStruct("symbol_hash_table", elfDecodeSymbolHashTable)
|
|
case SHT_SYMTAB:
|
|
d.FieldArray("symbol_table", func(d *decode.D) {
|
|
elfDecodeSymbolTable(d, ec, int(size/entSize), ec.strTabMap[STRTAB_STRTAB])
|
|
})
|
|
case SHT_DYNSYM:
|
|
d.FieldArray("symbol_table", func(d *decode.D) {
|
|
elfDecodeSymbolTable(d, ec, int(size/entSize), ec.strTabMap[STRTAB_DYNSTR])
|
|
})
|
|
case SHT_PROGBITS:
|
|
// TODO: name progbits?
|
|
// TODO: decode opcodes
|
|
d.FieldRawLen("data", size)
|
|
case SHT_GNU_HASH:
|
|
d.FieldStruct("gnu_hash", func(d *decode.D) {
|
|
elfDecodeGNUHash(d, ec, size, ec.strTabMap[STRTAB_DYNSTR])
|
|
})
|
|
default:
|
|
d.FieldRawLen("data", size)
|
|
}
|
|
}
|
|
|
|
func elfDecodeSectionHeaders(d *decode.D, ec elfContext) {
|
|
for i := 0; i < ec.shNum; i++ {
|
|
d.SeekAbs(ec.shOff + int64(i)*ec.shEntSize)
|
|
d.FieldStruct("section_header", func(d *decode.D) {
|
|
elfDecodeSectionHeader(d, ec, ec.sections[i])
|
|
})
|
|
}
|
|
}
|
|
|
|
func elfDecode(d *decode.D) any {
|
|
var ec elfContext
|
|
|
|
d.FieldStruct("header", func(d *decode.D) { elfDecodeHeader(d, &ec) })
|
|
d.Endian = ec.endian
|
|
// a first pass to find all sections and string table information etc
|
|
elfReadSectionHeaders(d, &ec)
|
|
d.FieldArray("program_headers", func(d *decode.D) {
|
|
elfDecodeProgramHeaders(d, ec)
|
|
})
|
|
d.FieldArray("section_headers", func(d *decode.D) {
|
|
elfDecodeSectionHeaders(d, ec)
|
|
})
|
|
|
|
return nil
|
|
}
|