2021-12-06 21:33:17 +03:00
//nolint:revive
2020-06-08 03:29:51 +03:00
package elf
2021-12-06 21:33:17 +03:00
// https://refspecs.linuxbase.org/elf/gabi4+/contents.html
2020-06-08 03:29:51 +03:00
// https://man7.org/linux/man-pages/man5/elf.5.html
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h
2022-09-09 13:42:00 +03:00
// https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=include/elf/external.h;hb=HEAD
2020-06-08 03:29:51 +03:00
2021-12-06 21:33:17 +03:00
// TODO: dwarf
2020-06-08 03:29:51 +03:00
import (
"strings"
2021-08-17 13:06:32 +03:00
"github.com/wader/fq/format"
"github.com/wader/fq/pkg/decode"
2022-07-16 19:39:57 +03:00
"github.com/wader/fq/pkg/interp"
2021-12-02 00:48:25 +03:00
"github.com/wader/fq/pkg/scalar"
2020-06-08 03:29:51 +03:00
)
func init ( ) {
2022-07-16 19:39:57 +03:00
interp . RegisterFormat ( decode . Format {
2020-06-08 03:29:51 +03:00
Name : format . ELF ,
Description : "Executable and Linkable Format" ,
Groups : [ ] string { format . PROBE } ,
DecodeFn : elfDecode ,
} )
}
2021-11-05 17:04:26 +03:00
const (
LITTLE_ENDIAN = 1
BIG_ENDIAN = 2
)
2022-09-30 14:58:23 +03:00
var endianNames = scalar . UintMapSymStr {
2021-12-06 21:33:17 +03:00
LITTLE_ENDIAN : "little_endian" ,
BIG_ENDIAN : "big_endian" ,
2021-11-05 17:04:26 +03:00
}
2022-09-30 14:58:23 +03:00
var classBits = scalar . UintMapSymUint {
2021-11-05 17:04:26 +03:00
1 : 32 ,
2 : 64 ,
}
2021-11-21 15:08:18 +03:00
const (
CLASS_32 = 1
CLASS_64 = 2
)
2022-09-30 14:58:23 +03:00
var osABINames = scalar . UintMapSymStr {
2021-12-06 21:33:17 +03:00
0 : "sysv" ,
1 : "hpux" ,
2 : "netbsd" ,
3 : "linux" ,
4 : "hurd" ,
2021-11-05 17:04:26 +03:00
5 : "86open" ,
2021-12-06 21:33:17 +03:00
6 : "solaris" ,
7 : "monterey" ,
8 : "irix" ,
9 : "freebsd" ,
10 : "tru64" ,
11 : "modesto" ,
12 : "openbsd" ,
97 : "arm" ,
255 : "standalone" ,
}
2022-09-09 13:42:00 +03:00
const (
ET_NONE = 0
ET_REL = 1
ET_EXEC = 2
ET_DYN = 3
ET_CORE = 4
)
2022-09-30 14:58:23 +03:00
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" } } ,
2021-12-06 21:33:17 +03:00
}
const (
EM_X86_64 = 0x3e
EM_ARM64 = 0xb7
)
2022-09-30 14:58:23 +03:00
var machineNames = scalar . UintMap {
2021-12-06 21:33:17 +03:00
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" } ,
}
2022-09-09 13:42:00 +03:00
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
)
2022-09-30 14:58:23 +03:00
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" } } ,
2021-11-05 17:04:26 +03:00
}
2022-09-09 13:42:00 +03:00
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
)
2022-09-30 14:58:23 +03:00
var coreNoteNames = scalar . UintMap {
2022-09-09 13:42:00 +03:00
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" } ,
}
2020-06-08 03:29:51 +03:00
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
2021-12-06 21:33:17 +03:00
SHT_GNU_HASH = 0x6ffffff6
)
2022-09-30 14:58:23 +03:00
var sectionHeaderTypeMap = scalar . UintMap {
2021-12-06 21:33:17 +03:00
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"
2020-06-08 03:29:51 +03:00
)
2021-12-06 21:33:17 +03:00
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
2022-09-30 14:58:23 +03:00
s scalar . Uint
2021-12-06 21:33:17 +03:00
}
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
}
2022-09-30 14:58:23 +03:00
func ( d dynamicTableEntries ) MapUint ( s scalar . Uint ) ( scalar . Uint , error ) {
u := s . Actual
2021-12-06 21:33:17 +03:00
if de , ok := d . lookup ( u ) ; ok {
s = de . s
s . Actual = u
}
return s , nil
}
var dynamicTableMap = dynamicTableEntries {
2022-09-30 14:58:23 +03:00
{ 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" } } ,
2021-12-06 21:33:17 +03:00
}
2022-09-30 14:58:23 +03:00
var symbolTableBindingMap = scalar . UintMapSymStr {
2021-12-06 21:33:17 +03:00
0 : "local" ,
1 : "global" ,
2 : "weak" ,
10 : "loos" ,
12 : "hios" ,
13 : "proc" ,
14 : "proc" ,
15 : "proc" ,
}
2022-09-30 14:58:23 +03:00
var symbolTableTypeMap = scalar . UintMapSymStr {
2021-12-06 21:33:17 +03:00
0 : "notype" ,
1 : "object" ,
2 : "func" ,
3 : "section" ,
4 : "file" ,
5 : "common" ,
6 : "tls" ,
10 : "loos" ,
12 : "hios" ,
13 : "proc" ,
14 : "proc" ,
15 : "proc" ,
}
2022-09-30 14:58:23 +03:00
var symbolTableVisibilityMap = scalar . UintMapSymStr {
2021-12-06 21:33:17 +03:00
0 : "default" ,
1 : "internal" ,
2 : "hidden" ,
3 : "protected" ,
2020-06-08 03:29:51 +03:00
}
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 ]
}
2021-12-02 00:48:25 +03:00
type strTable string
2022-09-30 14:58:23 +03:00
func ( m strTable ) MapUint ( s scalar . Uint ) ( scalar . Uint , error ) {
s . Sym = strIndexNull ( int ( s . Actual ) , string ( m ) )
2021-12-02 00:48:25 +03:00
return s , nil
2020-06-08 03:29:51 +03:00
}
2021-12-06 21:33:17 +03:00
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 ) {
2022-01-13 20:34:59 +03:00
d . FramedFn ( size , func ( d * decode . D ) {
2021-12-06 21:33:17 +03:00
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 {
2022-07-01 00:30:56 +03:00
entries int
strTabPtr int64
strSzVal int64
strTab string
symEnt int64
2021-12-06 21:33:17 +03:00
}
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
}
}
2020-06-08 03:29:51 +03:00
2021-12-06 21:33:17 +03:00
return dynamicContext {
2022-07-01 00:30:56 +03:00
entries : entries ,
strTabPtr : strTabPtr ,
strSzVal : strSzVal ,
symEnt : symEnt ,
2021-12-06 21:33:17 +03:00
}
}
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
}
2022-07-22 23:22:33 +03:00
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 ) ) )
}
2021-12-06 21:33:17 +03:00
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 )
}
2022-07-01 00:30:56 +03:00
// 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 ]
2022-07-22 23:22:33 +03:00
sh . dc . strTab = readStrTab ( d , strTabSh . offset , sh . dc . strSzVal / 8 )
2022-07-01 00:30:56 +03:00
}
}
2022-09-06 12:27:08 +03:00
// provide default empty string tables to be more robust
ec . strTabMap = map [ string ] string {
STRTAB_DYNSTR : "" ,
STRTAB_SHSTRTAB : "" ,
STRTAB_STRTAB : "" ,
2021-12-06 21:33:17 +03:00
}
2022-09-06 12:27:08 +03:00
var shStrTab string
if ec . shStrNdx < len ( ec . sections ) {
shStr := ec . sections [ ec . shStrNdx ]
shStrTab = readStrTab ( d , shStr . offset , shStr . size / 8 )
2022-07-22 23:22:33 +03:00
2022-09-06 12:27:08 +03:00
for _ , sh := range ec . sections {
if sh . typ != SHT_STRTAB {
continue
}
ec . strTabMap [ strIndexNull ( sh . name , shStrTab ) ] = readStrTab ( d , sh . offset , sh . size / 8 )
2021-12-06 21:33:17 +03:00
}
}
}
type elfContext struct {
archBits int
2022-09-09 13:42:00 +03:00
typ int
2021-12-06 21:33:17 +03:00
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 ) {
2021-11-21 15:08:18 +03:00
var class uint64
2020-06-08 03:29:51 +03:00
var archBits int
2021-11-05 17:04:26 +03:00
var endian uint64
2020-06-08 03:29:51 +03:00
2021-11-05 17:04:26 +03:00
d . FieldStruct ( "ident" , func ( d * decode . D ) {
2021-11-16 15:03:45 +03:00
d . FieldRawLen ( "magic" , 4 * 8 , d . AssertBitBuf ( [ ] byte ( "\x7fELF" ) ) )
2021-12-02 00:48:25 +03:00
class = d . FieldU8 ( "class" , classBits )
endian = d . FieldU8 ( "data" , endianNames )
2020-06-08 03:29:51 +03:00
d . FieldU8 ( "version" )
2021-12-02 00:48:25 +03:00
d . FieldU8 ( "os_abi" , osABINames )
2020-06-08 03:29:51 +03:00
d . FieldU8 ( "abi_version" )
2021-12-02 00:48:25 +03:00
d . FieldRawLen ( "pad" , 7 * 8 , d . BitBufIsZero ( ) )
2020-06-08 03:29:51 +03:00
} )
2021-11-21 15:08:18 +03:00
switch class {
case CLASS_32 :
archBits = 32
case CLASS_64 :
archBits = 64
default :
d . Fatalf ( "unknown class %d" , class )
}
2021-11-05 17:04:26 +03:00
switch endian {
case LITTLE_ENDIAN :
d . Endian = decode . LittleEndian
case BIG_ENDIAN :
d . Endian = decode . BigEndian
default :
2021-11-21 15:08:18 +03:00
d . Fatalf ( "unknown endian %d" , endian )
2021-11-05 17:04:26 +03:00
}
2022-09-30 14:58:23 +03:00
typ := d . FieldU16 ( "type" , typeNames , scalar . UintHex )
machine := d . FieldU16 ( "machine" , machineNames , scalar . UintHex )
2020-06-08 03:29:51 +03:00
d . FieldU32 ( "version" )
d . FieldU ( "entry" , archBits )
2021-12-06 21:33:17 +03:00
phOff := d . FieldU ( "phoff" , archBits )
shOff := d . FieldU ( "shoff" , archBits )
2020-06-08 03:29:51 +03:00
d . FieldU32 ( "flags" )
d . FieldU16 ( "ehsize" )
2021-12-06 21:33:17 +03:00
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
2022-09-09 13:42:00 +03:00
ec . typ = int ( typ )
2021-12-06 21:33:17 +03:00
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 )
}
2020-06-08 03:29:51 +03:00
2021-12-06 21:33:17 +03:00
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" )
}
} )
2020-06-08 03:29:51 +03:00
}
2022-09-09 13:42:00 +03:00
var typ uint64
2022-07-29 14:41:21 +03:00
var offset uint64
var size uint64
switch ec . archBits {
case 32 :
2022-09-09 13:42:00 +03:00
typ = d . FieldU32 ( "type" , phTypeNames )
2022-09-30 14:58:23 +03:00
offset = d . FieldU ( "offset" , ec . archBits , scalar . UintHex )
d . FieldU ( "vaddr" , ec . archBits , scalar . UintHex )
d . FieldU ( "paddr" , ec . archBits , scalar . UintHex )
2022-07-29 14:41:21 +03:00
size = d . FieldU32 ( "filesz" )
d . FieldU32 ( "memsz" )
pFlags ( d )
d . FieldU32 ( "align" )
case 64 :
2022-09-09 13:42:00 +03:00
typ = d . FieldU32 ( "type" , phTypeNames )
2022-07-29 14:41:21 +03:00
pFlags ( d )
2022-09-30 14:58:23 +03:00
offset = d . FieldU ( "offset" , ec . archBits , scalar . UintHex )
d . FieldU ( "vaddr" , ec . archBits , scalar . UintHex )
d . FieldU ( "paddr" , ec . archBits , scalar . UintHex )
2022-07-29 14:41:21 +03:00
size = d . FieldU64 ( "filesz" )
d . FieldU64 ( "memsz" )
d . FieldU64 ( "align" )
}
2020-06-08 03:29:51 +03:00
2022-07-29 14:41:21 +03:00
d . RangeFn ( int64 ( offset * 8 ) , int64 ( size * 8 ) , func ( d * decode . D ) {
2022-09-09 13:42:00 +03:00
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 {
2022-09-30 14:58:23 +03:00
d . FieldU32 ( "n_type" , coreNoteNames , scalar . UintHex )
2022-09-09 13:42:00 +03:00
} else {
2022-09-30 14:58:23 +03:00
d . FieldU32 ( "n_type" , scalar . UintHex )
2022-09-09 13:42:00 +03:00
}
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 ( ) )
}
2021-12-06 21:33:17 +03:00
} )
}
2020-06-08 03:29:51 +03:00
2021-12-06 21:33:17 +03:00
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 )
} )
}
}
2020-06-08 03:29:51 +03:00
2021-12-06 21:33:17 +03:00
func elfDecodeDynamicTag ( d * decode . D , ec elfContext , dc dynamicContext ) {
dtTag := d . FieldU ( "tag" , ec . archBits , dynamicTableMap )
name := "unspecified"
2022-09-30 14:58:23 +03:00
dfMapper := scalar . UintHex
2021-12-06 21:33:17 +03:00
if de , ok := dynamicTableMap . lookup ( dtTag ) ; ok {
switch de . dUn {
case dUnIgnored :
name = "ignored"
case dUnVal :
name = "val"
2022-09-30 14:58:23 +03:00
dfMapper = scalar . UintDec
2021-12-06 21:33:17 +03:00
case dUnPtr :
name = "ptr"
2020-06-08 03:29:51 +03:00
}
2021-12-06 21:33:17 +03:00
}
2020-06-08 03:29:51 +03:00
2021-12-06 21:33:17 +03:00
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 {
2022-09-30 14:58:23 +03:00
d . FieldValueUint ( "section_index" , uint64 ( i ) )
2021-12-06 21:33:17 +03:00
}
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 {
2022-09-30 14:58:23 +03:00
d . FieldValueUint ( "section_index" , uint64 ( i ) )
2021-12-06 21:33:17 +03:00
}
default :
d . FieldU ( name , ec . archBits , dfMapper )
}
}
2020-06-08 03:29:51 +03:00
2021-12-06 21:33:17 +03:00
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 )
} )
}
}
2020-06-08 03:29:51 +03:00
2021-12-06 21:33:17 +03:00
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" )
2020-06-08 03:29:51 +03:00
}
2021-12-06 21:33:17 +03:00
} 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 ] ) )
2022-09-30 14:58:23 +03:00
typ = d . FieldU32 ( "type" , sectionHeaderTypeMap , scalar . UintHex )
2021-12-06 21:33:17 +03:00
shFlags ( d , ec . archBits )
2022-09-30 14:58:23 +03:00
d . FieldU ( "addr" , ec . archBits , scalar . UintHex )
2021-12-06 21:33:17 +03:00
offset = int64 ( d . FieldU ( "offset" , ec . archBits ) ) * 8
2022-09-30 14:58:23 +03:00
size = int64 ( d . FieldU32 ( "size" , scalar . UintHex ) * 8 )
2021-12-06 21:33:17 +03:00
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 ] ) )
2022-09-30 14:58:23 +03:00
typ = d . FieldU32 ( "type" , sectionHeaderTypeMap , scalar . UintHex )
2021-12-06 21:33:17 +03:00
shFlags ( d , ec . archBits )
2022-09-30 14:58:23 +03:00
d . FieldU ( "addr" , ec . archBits , scalar . UintHex )
offset = int64 ( d . FieldU ( "offset" , ec . archBits , scalar . UintHex ) * 8 )
2021-12-06 21:33:17 +03:00
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 ] )
} )
}
}
2022-07-19 19:33:50 +03:00
func elfDecode ( d * decode . D , _ any ) any {
2021-12-06 21:33:17 +03:00
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 )
2022-05-03 16:42:40 +03:00
d . FieldArray ( "program_headers" , func ( d * decode . D ) {
elfDecodeProgramHeaders ( d , ec )
} )
d . FieldArray ( "section_headers" , func ( d * decode . D ) {
elfDecodeSectionHeaders ( d , ec )
} )
2020-06-08 03:29:51 +03:00
return nil
}