mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-01-10 06:27:59 -05:00
0
Ghidra/Processors/eBPF/Module.manifest
Normal file
0
Ghidra/Processors/eBPF/Module.manifest
Normal file
26
Ghidra/Processors/eBPF/build.gradle
Normal file
26
Ghidra/Processors/eBPF/build.gradle
Normal file
@@ -0,0 +1,26 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
|
||||
apply from: "$rootProject.projectDir/gradle/javaProject.gradle"
|
||||
apply from: "$rootProject.projectDir/gradle/processorProject.gradle"
|
||||
apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
|
||||
apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
|
||||
apply plugin: 'eclipse'
|
||||
eclipse.project.name = 'Processors eBPF'
|
||||
|
||||
dependencies {
|
||||
api project(':Base')
|
||||
}
|
||||
9
Ghidra/Processors/eBPF/certification.manifest
Normal file
9
Ghidra/Processors/eBPF/certification.manifest
Normal file
@@ -0,0 +1,9 @@
|
||||
##VERSION: 2.0
|
||||
Module.manifest||GHIDRA||||END|
|
||||
data/languages/eBPF.cspec||GHIDRA||||END|
|
||||
data/languages/eBPF.dwarf||GHIDRA||||END|
|
||||
data/languages/eBPF.ldefs||GHIDRA||||END|
|
||||
data/languages/eBPF.opinion||GHIDRA||||END|
|
||||
data/languages/eBPF.pspec||GHIDRA||||END|
|
||||
data/languages/eBPF.sinc||GHIDRA||||END|
|
||||
data/languages/eBPF_le.slaspec||GHIDRA||||END|
|
||||
63
Ghidra/Processors/eBPF/data/languages/eBPF.cspec
Normal file
63
Ghidra/Processors/eBPF/data/languages/eBPF.cspec
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<compiler_spec>
|
||||
<data_organization>
|
||||
<absolute_max_alignment value="0" />
|
||||
<machine_alignment value="2" />
|
||||
<default_alignment value="1" />
|
||||
<default_pointer_alignment value="8" />
|
||||
<pointer_size value="8" />
|
||||
<wchar_size value="2" />
|
||||
<short_size value="2" />
|
||||
<integer_size value="4" />
|
||||
<long_size value="4" />
|
||||
<long_long_size value="8" />
|
||||
<float_size value="4" />
|
||||
<double_size value="8" />
|
||||
<long_double_size value="8" />
|
||||
<size_alignment_map>
|
||||
<entry size="1" alignment="1" />
|
||||
<entry size="2" alignment="2" />
|
||||
<entry size="4" alignment="4" />
|
||||
<entry size="8" alignment="8" />
|
||||
</size_alignment_map>
|
||||
</data_organization>
|
||||
<global>
|
||||
<range space="ram"/>
|
||||
<range space="syscall"/>
|
||||
</global>
|
||||
<stackpointer register="R10" space="ram"/>
|
||||
<default_proto>
|
||||
<prototype name="__fastcall" extrapop="0" stackshift="0">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="R1"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="R2"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="R3"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="R4"/>
|
||||
</pentry>
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="R5"/>
|
||||
</pentry>
|
||||
</input>
|
||||
<output killedbycall="true">
|
||||
<pentry minsize="1" maxsize="8">
|
||||
<register name="R0"/>
|
||||
</pentry>
|
||||
</output>
|
||||
<unaffected>
|
||||
<varnode space="ram" offset="8" size="8"/>
|
||||
<register name="R6"/>
|
||||
<register name="R7"/>
|
||||
<register name="R8"/>
|
||||
<register name="R9"/>
|
||||
<register name="R10"/>
|
||||
</unaffected>
|
||||
</prototype>
|
||||
</default_proto>
|
||||
</compiler_spec>
|
||||
16
Ghidra/Processors/eBPF/data/languages/eBPF.dwarf
Normal file
16
Ghidra/Processors/eBPF/data/languages/eBPF.dwarf
Normal file
@@ -0,0 +1,16 @@
|
||||
<dwarf>
|
||||
<register_mappings>
|
||||
<register_mapping dwarf="0" ghidra="R0"/>
|
||||
<register_mapping dwarf="1" ghidra="R1"/>
|
||||
<register_mapping dwarf="2" ghidra="R2"/>
|
||||
<register_mapping dwarf="3" ghidra="R3"/>
|
||||
<register_mapping dwarf="4" ghidra="R4"/>
|
||||
<register_mapping dwarf="5" ghidra="R5"/>
|
||||
<register_mapping dwarf="6" ghidra="R6"/>
|
||||
<register_mapping dwarf="7" ghidra="R7"/>
|
||||
<register_mapping dwarf="8" ghidra="R8"/>
|
||||
<register_mapping dwarf="9" ghidra="R9"/>
|
||||
<register_mapping dwarf="10" ghidra="R10" stackpointer="true"/>
|
||||
</register_mappings>
|
||||
<call_frame_cfa value="8"/>
|
||||
</dwarf>
|
||||
15
Ghidra/Processors/eBPF/data/languages/eBPF.ldefs
Normal file
15
Ghidra/Processors/eBPF/data/languages/eBPF.ldefs
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<language_definitions>
|
||||
<language processor="eBPF"
|
||||
endian="little"
|
||||
size="64"
|
||||
variant="default"
|
||||
version="1.0"
|
||||
slafile="eBPF_le.sla"
|
||||
processorspec="eBPF.pspec"
|
||||
id="eBPF:LE:64:default">
|
||||
<description>eBPF processor 64-bit little-endian</description>
|
||||
<compiler name="default" spec="eBPF.cspec" id="default"/>
|
||||
<external_name tool="DWARF.register.mapping.file" name="eBPF.dwarf"/>
|
||||
</language>
|
||||
</language_definitions>
|
||||
5
Ghidra/Processors/eBPF/data/languages/eBPF.opinion
Normal file
5
Ghidra/Processors/eBPF/data/languages/eBPF.opinion
Normal file
@@ -0,0 +1,5 @@
|
||||
<opinions>
|
||||
<constraint loader="Executable and Linking Format (ELF)" compilerSpecID="default">
|
||||
<constraint primary="247" processor="eBPF" endian="little" size="64" />
|
||||
</constraint>
|
||||
</opinions>
|
||||
73
Ghidra/Processors/eBPF/data/languages/eBPF.pspec
Normal file
73
Ghidra/Processors/eBPF/data/languages/eBPF.pspec
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<processor_spec>
|
||||
<programcounter register="PC"/>
|
||||
<default_symbols>
|
||||
<symbol name="bpf_unspec" address="syscall:0x0"/>
|
||||
<symbol name="bpf_map_lookup_elem" address="syscall:0x1"/>
|
||||
<symbol name="bpf_map_update_elem" address="syscall:0x2"/>
|
||||
<symbol name="bpf_map_delete_elem" address="syscall:0x3"/>
|
||||
<symbol name="bpf_probe_read" address="syscall:0x4"/>
|
||||
<symbol name="bpf_ktime_get_ns" address="syscall:0x5"/>
|
||||
<symbol name="bpf_trace_printk" address="syscall:0x6"/>
|
||||
<symbol name="bpf_get_prandom_u32" address="syscall:0x7"/>
|
||||
<symbol name="bpf_get_smp_processor_id" address="syscall:0x8"/>
|
||||
<symbol name="bpf_skb_store_bytes" address="syscall:0x9"/>
|
||||
<symbol name="bpf_l3_csum_replace" address="syscall:0xa"/>
|
||||
<symbol name="bpf_l4_csum_replace" address="syscall:0xb"/>
|
||||
<symbol name="bpf_tail_call" address="syscall:0xc"/>
|
||||
<symbol name="bpf_clone_redirect" address="syscall:0xd"/>
|
||||
<symbol name="bpf_get_current_pid_tgid" address="syscall:0xe"/>
|
||||
<symbol name="bpf_get_current_uid_gid" address="syscall:0xf"/>
|
||||
<symbol name="bpf_get_current_comm" address="syscall:0x10"/>
|
||||
<symbol name="bpf_get_cgroup_classid" address="syscall:0x11"/>
|
||||
<symbol name="bpf_skb_vlan_push" address="syscall:0x12"/>
|
||||
<symbol name="bpf_skb_vlan_pop" address="syscall:0x13"/>
|
||||
<symbol name="bpf_skb_get_tunnel_key" address="syscall:0x14"/>
|
||||
<symbol name="bpf_skb_set_tunnel_key" address="syscall:0x15"/>
|
||||
<symbol name="bpf_perf_event_read" address="syscall:0x16"/>
|
||||
<symbol name="bpf_redirect" address="syscall:0x17"/>
|
||||
<symbol name="bpf_get_route_realm" address="syscall:0x18"/>
|
||||
<symbol name="bpf_perf_event_output" address="syscall:0x19"/>
|
||||
<symbol name="bpf_skb_load_bytes" address="syscall:0x1a"/>
|
||||
<symbol name="bpf_get_stackid" address="syscall:0x1b"/>
|
||||
<symbol name="bpf_csum_diff" address="syscall:0x1c"/>
|
||||
<symbol name="bpf_skb_get_tunnel_opt" address="syscall:0x1d"/>
|
||||
<symbol name="bpf_skb_set_tunnel_opt" address="syscall:0x1e"/>
|
||||
<symbol name="bpf_skb_change_proto" address="syscall:0x1f"/>
|
||||
<symbol name="bpf_skb_change_type" address="syscall:0x20"/>
|
||||
<symbol name="bpf_skb_under_cgroup" address="syscall:0x21"/>
|
||||
<symbol name="bpf_get_hash_recalc" address="syscall:0x22"/>
|
||||
<symbol name="bpf_get_current_task" address="syscall:0x23"/>
|
||||
<symbol name="bpf_probe_write_user" address="syscall:0x24"/>
|
||||
<symbol name="bpf_current_task_under_cgroup" address="syscall:0x25"/>
|
||||
<symbol name="bpf_skb_change_tail" address="syscall:0x26"/>
|
||||
<symbol name="bpf_skb_pull_data" address="syscall:0x27"/>
|
||||
<symbol name="bpf_csum_update" address="syscall:0x28"/>
|
||||
<symbol name="bpf_set_hash_invalid" address="syscall:0x29"/>
|
||||
<symbol name="bpf_get_numa_node_id" address="syscall:0x2a"/>
|
||||
<symbol name="bpf_skb_change_head" address="syscall:0x2b"/>
|
||||
<symbol name="bpf_xdp_adjust_head" address="syscall:0x2c"/>
|
||||
<symbol name="bpf_probe_read_str" address="syscall:0x2d"/>
|
||||
<symbol name="bpf_get_socket_cookie" address="syscall:0x2e"/>
|
||||
<symbol name="bpf_get_socket_cookie" address="syscall:0x2f"/>
|
||||
<symbol name="bpf_get_socket_cookie" address="syscall:0x30"/>
|
||||
<symbol name="bpf_get_socket_uid" address="syscall:0x31"/>
|
||||
<symbol name="bpf_set_hash" address="syscall:0x32"/>
|
||||
<symbol name="bpf_setsockopt" address="syscall:0x33"/>
|
||||
<symbol name="bpf_skb_adjust_room" address="syscall:0x34"/>
|
||||
<symbol name="bpf_redirect_map" address="syscall:0x35"/>
|
||||
<symbol name="bpf_sk_redirect_map" address="syscall:0x36"/>
|
||||
<symbol name="bpf_sock_map_update" address="syscall:0x37"/>
|
||||
<symbol name="bpf_xdp_adjust_meta" address="syscall:0x38"/>
|
||||
<symbol name="bpf_perf_event_read_value" address="syscall:0x39"/>
|
||||
<symbol name="bpf_perf_prog_read_value" address="syscall:0x3a"/>
|
||||
<symbol name="bpf_getsockopt" address="syscall:0x3b"/>
|
||||
<symbol name="bpf_override_return" address="syscall:0x3c"/>
|
||||
<symbol name="bpf_sock_ops_cb_flags_set" address="syscall:0x3d"/>
|
||||
<symbol name="bpf_msg_redirect_map" address="syscall:0x3e"/>
|
||||
<symbol name="bpf_msg_apply_bytes" address="syscall:0x3f"/>
|
||||
</default_symbols>
|
||||
<default_memory_blocks>
|
||||
<memory_block name="eBPFHelper_functions" start_address="syscall:0" length="0x400" initialized="true"/>
|
||||
</default_memory_blocks>
|
||||
</processor_spec>
|
||||
519
Ghidra/Processors/eBPF/data/languages/eBPF.sinc
Normal file
519
Ghidra/Processors/eBPF/data/languages/eBPF.sinc
Normal file
@@ -0,0 +1,519 @@
|
||||
###############################################################################
|
||||
# eBPF Processor Specification for Ghidra
|
||||
###############################################################################
|
||||
|
||||
#eBPF is a RISC register machine with a total of 11 64-bit registers, a program counter and a 512 byte fixed-size stack.
|
||||
#9 registers are general purpouse read-write, one is a read-only stack pointer and the program counter is implicit,
|
||||
#i.e. we can only jump to a certain offset from it. The eBPF registers are always 64-bit wide.
|
||||
|
||||
define space ram type=ram_space size=8 default;
|
||||
define space register type=register_space size=4;
|
||||
define space syscall type=ram_space size=4;
|
||||
|
||||
define register offset=0 size=8 [ R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 PC ];
|
||||
|
||||
# Instruction encoding: Insop:8, dst_reg:4, src_reg:4, off:16, imm:32 - from lsb to msb
|
||||
define token instr(64)
|
||||
imm=(32, 63) signed
|
||||
off=(16, 31) signed
|
||||
src=(12, 15)
|
||||
dst=(8, 11)
|
||||
op_alu_jmp_opcode=(4, 7)
|
||||
op_alu_jmp_source=(3, 3)
|
||||
op_ld_st_mode=(5, 7)
|
||||
op_ld_st_size=(3, 4)
|
||||
op_insn_class=(0, 2)
|
||||
;
|
||||
|
||||
#We'll need this token to operate with LDDW instruction, which has 64 bit imm value
|
||||
define token immtoken(64)
|
||||
imm2=(32, 63)
|
||||
;
|
||||
|
||||
#To operate with registers
|
||||
attach variables [ src dst ] [ R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 _ _ _ _ _ ];
|
||||
|
||||
#Arithmetic instructions
|
||||
#BPF_ALU64
|
||||
###############################################################################
|
||||
|
||||
:MOV dst, src is src & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = src; }
|
||||
:MOV dst, imm is imm & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = imm; }
|
||||
|
||||
:ADD dst, src is src & dst & op_alu_jmp_opcode=0x0 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst + src; }
|
||||
:ADD dst, imm is imm & dst & op_alu_jmp_opcode=0x0 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst + imm; }
|
||||
|
||||
:SUB dst, src is src & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst - src; }
|
||||
:SUB dst, imm is imm & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst - imm; }
|
||||
|
||||
:MUL dst, src is src & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst * src; }
|
||||
:MUL dst, imm is imm & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst * imm; }
|
||||
|
||||
:DIV dst, src is src & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst / src; }
|
||||
:DIV dst, imm is imm & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst / imm; }
|
||||
|
||||
:OR dst, src is src & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst | src; }
|
||||
:OR dst, imm is imm & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst | imm; }
|
||||
|
||||
:AND dst, src is src & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst & src; }
|
||||
:AND dst, imm is imm & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst & imm; }
|
||||
|
||||
:LSH dst, src is src & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst << src; }
|
||||
:LSH dst, imm is imm & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst << imm; }
|
||||
|
||||
:RSH dst, src is src & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst >> src; }
|
||||
:RSH dst, imm is imm & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst >> imm; }
|
||||
|
||||
:NEG dst is dst & op_alu_jmp_opcode=0x8 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = -dst; }
|
||||
|
||||
:MOD dst, src is src & dst & op_alu_jmp_opcode=0x9 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst % src; }
|
||||
:MOD dst, imm is imm & dst & op_alu_jmp_opcode=0x9 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst % imm; }
|
||||
|
||||
:XOR dst, src is src & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst ^ src; }
|
||||
:XOR dst, imm is imm & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst ^ imm; }
|
||||
|
||||
:ARSH dst, src is src & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst s>> src; }
|
||||
:ARSH dst, imm is imm & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst s>> imm; }
|
||||
|
||||
#BPF_ALU
|
||||
###############################################################################
|
||||
|
||||
:MOV dst, src is src & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(src:4); }
|
||||
:MOV dst, imm is imm & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = imm; }
|
||||
|
||||
:ADD dst, src is src & dst & op_alu_jmp_opcode=0x0 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 + src:4); }
|
||||
:ADD dst, imm is imm & dst & op_alu_jmp_opcode=0x0 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 + imm); }
|
||||
|
||||
:SUB dst, src is src & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 - src:4); }
|
||||
:SUB dst, imm is imm & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 - imm); }
|
||||
|
||||
:MUL dst, src is src & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 * src:4); }
|
||||
:MUL dst, imm is imm & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 * imm); }
|
||||
|
||||
:DIV dst, src is src & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 / src:4); }
|
||||
:DIV dst, imm is imm & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 / imm); }
|
||||
|
||||
:OR dst, src is src & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 | src:4); }
|
||||
:OR dst, imm is imm & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 | imm); }
|
||||
|
||||
:AND dst, src is src & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 & src:4); }
|
||||
:AND dst, imm is imm & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 & imm); }
|
||||
|
||||
:LSH dst, src is src & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 << src:4); }
|
||||
:LSH dst, imm is imm & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 << imm); }
|
||||
|
||||
:RSH dst, src is src & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 >> src:4); }
|
||||
:RSH dst, imm is imm & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 >> imm); }
|
||||
|
||||
:NEG dst is dst & op_alu_jmp_opcode=0x8 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(-dst:4); }
|
||||
|
||||
:MOD dst, src is src & dst & op_alu_jmp_opcode=0x9 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 % src:4); }
|
||||
:MOD dst, imm is imm & dst & op_alu_jmp_opcode=0x9 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 % imm); }
|
||||
|
||||
:XOR dst, src is src & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 ^ src:4); }
|
||||
:XOR dst, imm is imm & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 ^ imm); }
|
||||
|
||||
:ARSH dst, src is src & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 s>> src:4); }
|
||||
:ARSH dst, imm is imm & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 s>> imm); }
|
||||
|
||||
#Bytewasp instructions
|
||||
###############################################################################
|
||||
# BPF_ALU | BPF_K | BPF_END
|
||||
:LE16 dst is imm=0x10 & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=0 & op_insn_class=0x4 { dst=((dst) >> 8) | ((dst) << 8); }
|
||||
:LE32 dst is imm=0x20 & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=0 & op_insn_class=0x4 { dst=((dst) >> 24) | (((dst) & 0x00FF0000) >> 8) | (((dst) & 0x0000FF00) << 8) | ((dst) << 24); }
|
||||
:LE64 dst is imm=0x40 & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=0 & op_insn_class=0x4 {
|
||||
dst=( (dst << 56) & 0xff00000000000000 ) |
|
||||
( (dst << 40) & 0x00ff000000000000 ) |
|
||||
( (dst << 24) & 0x0000ff0000000000 ) |
|
||||
( (dst << 8) & 0x000000ff00000000 ) |
|
||||
( (dst >> 8) & 0x00000000ff000000 ) |
|
||||
( (dst >> 24) & 0x0000000000ff0000 ) |
|
||||
( (dst >> 40) & 0x000000000000ff00 ) |
|
||||
( (dst >> 56) & 0x00000000000000ff );
|
||||
}
|
||||
|
||||
# BPF_ALU | BPF_X | BPF_END
|
||||
:BE16 dst is imm=0x10 & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=1 & op_insn_class=0x4 { dst=((dst) >> 8) | ((dst) << 8); }
|
||||
:BE32 dst is imm=0x20 & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=1 & op_insn_class=0x4 { dst=((dst) >> 24) | (((dst) & 0x00FF0000) >> 8) | (((dst) & 0x0000FF00) << 8) | ((dst) << 24); }
|
||||
:BE64 dst is imm=0x40 & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=1 & op_insn_class=0x4 {
|
||||
dst=( (dst << 56) & 0xff00000000000000 ) |
|
||||
( (dst << 40) & 0x00ff000000000000 ) |
|
||||
( (dst << 24) & 0x0000ff0000000000 ) |
|
||||
( (dst << 8) & 0x000000ff00000000 ) |
|
||||
( (dst >> 8) & 0x00000000ff000000 ) |
|
||||
( (dst >> 24) & 0x0000000000ff0000 ) |
|
||||
( (dst >> 40) & 0x000000000000ff00 ) |
|
||||
( (dst >> 56) & 0x00000000000000ff );
|
||||
}
|
||||
|
||||
#Memory instructions - Load and Store
|
||||
###############################################################################
|
||||
|
||||
#LDDW is the only 16-byte eBPF instruction which consists of two consecutive 8-byte blocks ('struct bpf_insn')
|
||||
#and interpreted as single instruction which loads 64-bit imm value into dst. Encoding of LDDW:
|
||||
#LSR MSR
|
||||
# opcode src dst offset Low 8-byte imm zero-block High 8-byte imm
|
||||
#bits 8 4 4 16 32 32 32
|
||||
# So, imm64 consists of concatination of high 8-byte imm and low 8-byte imm.
|
||||
|
||||
:LDDW dst, concat is imm & dst & op_ld_st_mode=0x0 & op_ld_st_size=0x3 & op_insn_class=0x0; imm2 [ concat= (imm2 << 32) | ((imm) & 0xFFFFFFFF); ] { dst = concat; }
|
||||
|
||||
#BPF_LD_MAP_FD(DST, MAP_FD) -> second LDDW = pseudo LDDW insn used to refer to process-local map_fd
|
||||
#For each instruction which needs relocation, it inject corresponding file descriptor to imm field.
|
||||
#As a part of protocol, src_reg is set to BPF_PSEUDO_MAP_FD (which defined as 1) to notify kernel this is a map loading instruction.
|
||||
|
||||
:LDDW dst, imm is imm & src=1 & dst & op_ld_st_mode=0x0 & op_ld_st_size=0x3 & op_insn_class=0x0; imm2 { dst = *:8 imm:8; }
|
||||
|
||||
:LDABSW dst, imm is imm & dst & op_ld_st_mode=0x1 & op_ld_st_size=0x0 & op_insn_class=0x0 { dst=*:4 imm:8; }
|
||||
|
||||
:LDABSH dst, imm is imm & dst & op_ld_st_mode=0x1 & op_ld_st_size=0x1 & op_insn_class=0x0 { dst=*:2 imm:8; }
|
||||
|
||||
:LDABSB dst, imm is imm & dst & op_ld_st_mode=0x1 & op_ld_st_size=0x2 & op_insn_class=0x0 { dst=*:1 imm:8; }
|
||||
|
||||
:LDABSDW dst, imm is imm & dst & op_ld_st_mode=0x1 & op_ld_st_size=0x3 & op_insn_class=0x0 { dst=*:8 imm:8; }
|
||||
|
||||
:LDINDW src, dst, imm is imm & src & dst & op_ld_st_mode=0x2 & op_ld_st_size=0x0 & op_insn_class=0x0 { dst=*:4 (src + imm); }
|
||||
|
||||
:LDINDH src, dst, imm is imm & src & dst & op_ld_st_mode=0x2 & op_ld_st_size=0x1 & op_insn_class=0x0 { dst=*:2 (src + imm); }
|
||||
|
||||
:LDINDB src, dst, imm is imm & src & dst & op_ld_st_mode=0x2 & op_ld_st_size=0x2 & op_insn_class=0x0 { dst=*:1 (src + imm); }
|
||||
|
||||
:LDINDDW src, dst, imm is imm & src & dst & op_ld_st_mode=0x2 & op_ld_st_size=0x3 & op_insn_class=0x0 { dst=*:8 (src + imm); }
|
||||
|
||||
:LDXW dst, [src + off] is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x0 & op_insn_class=0x1 { dst=*:4 (src + off); }
|
||||
|
||||
:LDXH dst, [src + off] is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x1 & op_insn_class=0x1 { dst=*:2 (src + off); }
|
||||
|
||||
:LDXB dst, [src + off] is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x2 & op_insn_class=0x1 { dst=*:1 (src + off); }
|
||||
|
||||
:LDXDW dst, [src + off] is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x3 & op_insn_class=0x1 { dst=*:8 (src + off); }
|
||||
|
||||
:STW [dst + off], imm is imm & off & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x0 & op_insn_class=0x2 { *:4 (dst + off)=imm:4; }
|
||||
|
||||
:STH [dst + off], imm is imm & off & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x1 & op_insn_class=0x2 { *:2 (dst + off)=imm:2; }
|
||||
|
||||
:STB [dst + off], imm is imm & off & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x2 & op_insn_class=0x2 { *:1 (dst + off)=imm:1; }
|
||||
|
||||
:STDW [dst + off], imm is imm & off & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x3 & op_insn_class=0x2 { *:8 (dst + off)=imm:8; }
|
||||
|
||||
:STXW [dst + off], src is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off)=src:4; }
|
||||
|
||||
:STXH [dst + off], src is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x1 & op_insn_class=0x3 { *:2 (dst + off)=src:2; }
|
||||
|
||||
:STXB [dst + off], src is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x2 & op_insn_class=0x3 { *:1 (dst + off)=src:1; }
|
||||
|
||||
:STXDW [dst + off], src is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off)=src:8; }
|
||||
|
||||
# BPF_ATOMIC
|
||||
# BPF_ADD:
|
||||
|
||||
# BPF_STX | BPF_ATOMIC | BPF_W
|
||||
:STXXADDW [dst + off], src is imm=0x0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) + src:4; }
|
||||
|
||||
# BPF_STX | BPF_ATOMIC | BPF_DW
|
||||
:STXXADDDW [dst + off], src is imm=0x0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) + src; }
|
||||
|
||||
# BPF_OR:
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0x40 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) | src:4; }
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0x40 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) | src; }
|
||||
|
||||
# BPF_AND:
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0x50 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) & src:4; }
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0x50 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) & src; }
|
||||
|
||||
# BPF_XOR:
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0xa0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) ^ src:4; }
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0xa0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) ^ src; }
|
||||
|
||||
# BPF_ADD | BPF_FETCH -> src = atomic_fetch_add(dst + off, src):
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0x1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
local tmp:4 = *:4 (dst + off);
|
||||
*:4 (dst + off) = *:4 (dst + off) + src:4;
|
||||
src = zext(tmp);
|
||||
}
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0x1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
local tmp:8 = *:8 (dst + off);
|
||||
*:8 (dst + off) = *:8 (dst + off) + src;
|
||||
src = tmp;
|
||||
}
|
||||
|
||||
# BPF_OR | BPF_FETCH -> src = atomic_fetch_or(dst + off, src):
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0x41 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
local tmp:4 = *:4 (dst + off);
|
||||
*:4 (dst + off) = *:4 (dst + off) | src:4;
|
||||
src = zext(tmp);
|
||||
}
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0x41 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
local tmp:8 = *:8 (dst + off);
|
||||
*:8 (dst + off) = *:8 (dst + off) | src;
|
||||
src = tmp;
|
||||
}
|
||||
|
||||
# BPF_AND | BPF_FETCH -> src = atomic_fetch_and(dst + off, src):
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0x51 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
local tmp:4 = *:4 (dst + off);
|
||||
*:4 (dst + off) = *:4 (dst + off) & src:4;
|
||||
src = zext(tmp);
|
||||
}
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0x51 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
local tmp:8 = *:8 (dst + off);
|
||||
*:8 (dst + off) = *:8 (dst + off) & src;
|
||||
src = tmp;
|
||||
}
|
||||
|
||||
# BPF_XOR | BPF_FETCH -> src = atomic_fetch_xor(dst + off, src):
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0xa1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
local tmp:4 = *:4 (dst + off);
|
||||
*:4 (dst + off) = *:4 (dst + off) ^ src:4;
|
||||
src = zext(tmp);
|
||||
}
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0xa1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
local tmp:8 = *:8 (dst + off);
|
||||
*:8 (dst + off) = *:8 (dst + off) ^ src;
|
||||
src = tmp;
|
||||
}
|
||||
|
||||
# BPF_XCHG -> src_reg = atomic_xchg(dst + off, src):
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0xe1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
local tmp:4 = *:4 (dst + off);
|
||||
*:4 (dst + off) = src:4;
|
||||
src = zext(tmp);
|
||||
}
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0xe1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
local tmp:8 = *:8 (dst + off);
|
||||
*:8 (dst + off) = src;
|
||||
src = tmp;
|
||||
}
|
||||
|
||||
# BPF_CMPXCHG -> R0 = atomic_cmpxchg(dst + off, R0, src):
|
||||
|
||||
:STXXADDW [dst + off], src is imm=0xf1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
|
||||
local tmp:4 = *:4 (dst + off);
|
||||
if (R0:4 == tmp) goto <equal>;
|
||||
R0 = zext(tmp);
|
||||
<equal>
|
||||
*:4 (dst + off) = src:4;
|
||||
}
|
||||
|
||||
:STXXADDDW [dst + off], src is imm=0xf1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
|
||||
local tmp:8 = *:8 (dst + off);
|
||||
if (R0 == tmp) goto <equal>;
|
||||
R0 = tmp;
|
||||
<equal>
|
||||
*:8 (dst + off) = src;
|
||||
}
|
||||
|
||||
#Jump instructions (BPF_JMP, BPF_JMP32)
|
||||
###############################################################################
|
||||
|
||||
joff: reloc is off [ reloc = inst_next + off * 8; ] { export *:8 reloc; }
|
||||
|
||||
:JA joff is joff & op_alu_jmp_opcode=0x0 & op_alu_jmp_source=0 & op_insn_class=0x5 {
|
||||
goto joff;
|
||||
}
|
||||
|
||||
:JEQ dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=0 & op_insn_class=0x5 {
|
||||
if (dst == imm) goto joff;
|
||||
}
|
||||
|
||||
:JEQ dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=1 & op_insn_class=0x5 {
|
||||
if (dst == src) goto joff;
|
||||
}
|
||||
|
||||
:JEQ dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=0 & op_insn_class=0x6 {
|
||||
if (dst:4 == imm:4) goto joff;
|
||||
}
|
||||
|
||||
:JEQ dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=1 & op_insn_class=0x6 {
|
||||
if (dst:4 == src:4) goto joff;
|
||||
}
|
||||
|
||||
:JGT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=0 & op_insn_class=0x5 {
|
||||
if (dst > imm) goto joff;
|
||||
}
|
||||
|
||||
:JGT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=1 & op_insn_class=0x5 {
|
||||
if (dst > src) goto joff;
|
||||
}
|
||||
|
||||
:JGT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=0 & op_insn_class=0x6 {
|
||||
if (dst:4 > imm:4) goto joff;
|
||||
}
|
||||
|
||||
:JGT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=1 & op_insn_class=0x6 {
|
||||
if (dst:4 > src:4) goto joff;
|
||||
}
|
||||
|
||||
:JGE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=0 & op_insn_class=0x5 {
|
||||
if (dst >= imm) goto joff;
|
||||
}
|
||||
|
||||
:JGE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=1 & op_insn_class=0x5 {
|
||||
if (dst >= src) goto joff;
|
||||
}
|
||||
|
||||
:JGE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=0 & op_insn_class=0x6 {
|
||||
if (dst:4 >= imm:4) goto joff;
|
||||
}
|
||||
|
||||
:JGE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=1 & op_insn_class=0x6 {
|
||||
if (dst:4 >= src:4) goto joff;
|
||||
}
|
||||
|
||||
:JLT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=0 & op_insn_class=0x5 {
|
||||
if (dst < imm) goto joff;
|
||||
}
|
||||
|
||||
:JLT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=1 & op_insn_class=0x5 {
|
||||
if (dst < src) goto joff;
|
||||
}
|
||||
|
||||
:JLT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=0 & op_insn_class=0x6 {
|
||||
if (dst:4 < imm:4) goto joff;
|
||||
}
|
||||
|
||||
:JLT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=1 & op_insn_class=0x6 {
|
||||
if (dst:4 < src:4) goto joff;
|
||||
}
|
||||
|
||||
:JLE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=0 & op_insn_class=0x5 {
|
||||
if (dst <= imm) goto joff;
|
||||
}
|
||||
|
||||
:JLE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=1 & op_insn_class=0x5 {
|
||||
if (dst <= src) goto joff;
|
||||
}
|
||||
|
||||
:JLE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=0 & op_insn_class=0x6 {
|
||||
if (dst:4 <= imm:4) goto joff;
|
||||
}
|
||||
|
||||
:JLE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=1 & op_insn_class=0x6 {
|
||||
if (dst:4 <= src:4) goto joff;
|
||||
}
|
||||
|
||||
:JNE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=0 & op_insn_class=0x5 {
|
||||
if (dst != imm) goto joff;
|
||||
}
|
||||
|
||||
:JNE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=1 & op_insn_class=0x5 {
|
||||
if (dst != src) goto joff;
|
||||
}
|
||||
|
||||
:JNE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=0 & op_insn_class=0x6 {
|
||||
if (dst:4 != imm:4) goto joff;
|
||||
}
|
||||
|
||||
:JNE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=1 & op_insn_class=0x6 {
|
||||
if (dst:4 != src:4) goto joff;
|
||||
}
|
||||
|
||||
:JSET dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=0 & op_insn_class=0x5 {
|
||||
if ((dst & imm) != 0) goto joff;
|
||||
}
|
||||
|
||||
:JSET dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=1 & op_insn_class=0x5 {
|
||||
if ((dst & src) != 0) goto joff;
|
||||
}
|
||||
|
||||
:JSET dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=0 & op_insn_class=0x6 {
|
||||
if ((dst:4 & imm:4) != 0) goto joff;
|
||||
}
|
||||
|
||||
:JSET dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=1 & op_insn_class=0x6 {
|
||||
if ((dst:4 & src:4) != 0) goto joff;
|
||||
}
|
||||
|
||||
:JSGT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=0 & op_insn_class=0x5 {
|
||||
if (dst s> imm) goto joff;
|
||||
}
|
||||
|
||||
:JSGT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=1 & op_insn_class=0x5 {
|
||||
if (dst s> src) goto joff;
|
||||
}
|
||||
|
||||
:JSGT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=0 & op_insn_class=0x6 {
|
||||
if (dst:4 s> imm:4) goto joff;
|
||||
}
|
||||
|
||||
:JSGT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=1 & op_insn_class=0x6 {
|
||||
if (dst:4 s> src:4) goto joff;
|
||||
}
|
||||
|
||||
:JSGE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=0 & op_insn_class=0x5 {
|
||||
if (dst s>= imm) goto joff;
|
||||
}
|
||||
|
||||
:JSGE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=1 & op_insn_class=0x5 {
|
||||
if (dst s>= src) goto joff;
|
||||
}
|
||||
|
||||
:JSGE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=0 & op_insn_class=0x6 {
|
||||
if (dst:4 s>= imm:4) goto joff;
|
||||
}
|
||||
|
||||
:JSGE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=1 & op_insn_class=0x6 {
|
||||
if (dst:4 s>= src:4) goto joff;
|
||||
}
|
||||
|
||||
:JSLT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=0 & op_insn_class=0x5 {
|
||||
if (dst s< imm) goto joff;
|
||||
}
|
||||
|
||||
:JSLT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=1 & op_insn_class=0x5 {
|
||||
if (dst s< src) goto joff;
|
||||
}
|
||||
|
||||
:JSLT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=0 & op_insn_class=0x6 {
|
||||
if (dst:4 s< imm:4) goto joff;
|
||||
}
|
||||
|
||||
:JSLT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=1 & op_insn_class=0x6 {
|
||||
if (dst:4 s< src:4) goto joff;
|
||||
}
|
||||
|
||||
:JSLE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=0 & op_insn_class=0x5 {
|
||||
if (dst s<= imm) goto joff;
|
||||
}
|
||||
|
||||
:JSLE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=1 & op_insn_class=0x5 {
|
||||
if (dst s<= src) goto joff;
|
||||
}
|
||||
|
||||
:JSLE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=0 & op_insn_class=0x6 {
|
||||
if (dst:4 s<= imm:4) goto joff;
|
||||
}
|
||||
|
||||
:JSLE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=1 & op_insn_class=0x6 {
|
||||
if (dst:4 s<= src:4) goto joff;
|
||||
}
|
||||
|
||||
SysCall: imm is imm { export *[syscall]:1 imm; }
|
||||
|
||||
:CALL SysCall is imm & src=0 & op_alu_jmp_opcode=0x8 & op_alu_jmp_source=0 & op_insn_class=0x5 & SysCall {
|
||||
call SysCall;
|
||||
}
|
||||
|
||||
disp32: reloc is imm [ reloc = inst_next + imm; ] { export *:4 reloc; }
|
||||
|
||||
:CALL disp32 is imm & src=1 & op_alu_jmp_opcode=0x8 & op_alu_jmp_source=0 & op_insn_class=0x5 & disp32 {
|
||||
call disp32;
|
||||
}
|
||||
|
||||
:EXIT is op_alu_jmp_opcode=0x9 & op_alu_jmp_source=0 & op_insn_class=0x5 { return [*:8 R10]; }
|
||||
3
Ghidra/Processors/eBPF/data/languages/eBPF_le.slaspec
Normal file
3
Ghidra/Processors/eBPF/data/languages/eBPF_le.slaspec
Normal file
@@ -0,0 +1,3 @@
|
||||
define endian=little;
|
||||
|
||||
@include "eBPF.sinc"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,49 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.elf.extend;
|
||||
|
||||
import ghidra.app.util.bin.format.elf.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class eBPF_ElfExtension extends ElfExtension {
|
||||
@Override
|
||||
public boolean canHandle(ElfHeader elf) {
|
||||
return elf.e_machine() == ElfConstants.EM_BPF && elf.is64Bit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(ElfLoadHelper elfLoadHelper) {
|
||||
Language language = elfLoadHelper.getProgram().getLanguage();
|
||||
return canHandle(elfLoadHelper.getElfHeader()) && "eBPF".equals(language.getProcessor().toString()) &&
|
||||
language.getLanguageDescription().getSize() == 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataTypeSuffix() {
|
||||
return "eBPF";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processGotPlt(ElfLoadHelper elfLoadHelper, TaskMonitor monitor) throws CancelledException {
|
||||
if (!canHandle(elfLoadHelper)) {
|
||||
return;
|
||||
}
|
||||
super.processGotPlt(elfLoadHelper, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.elf.relocation;
|
||||
|
||||
import ghidra.app.plugin.core.reloc.RelocationFixupHandler;
|
||||
import ghidra.app.util.opinion.ElfLoader;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.lang.Processor;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.Relocation;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
|
||||
public class ElfeBPFRelocationFixupHandler extends RelocationFixupHandler {
|
||||
@Override
|
||||
public boolean processRelocation(Program program, Relocation relocation, Address oldImageBase,
|
||||
Address newImageBase) throws MemoryAccessException, CodeUnitInsertionException {
|
||||
return process64BitRelocation(program, relocation, oldImageBase, newImageBase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlesProgram(Program program) {
|
||||
if (!ElfLoader.ELF_NAME.equals(program.getExecutableFormat())) {
|
||||
return false;
|
||||
}
|
||||
Language language = program.getLanguage();
|
||||
if (language.getLanguageDescription().getSize() != 64) {
|
||||
return false;
|
||||
}
|
||||
Processor processor = language.getProcessor();
|
||||
return (processor.equals(Processor.findOrPossiblyCreateProcessor("eBPF")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.elf.relocation;
|
||||
|
||||
public class eBPF_ElfRelocationConstants {
|
||||
|
||||
/** No operation needed */
|
||||
public static final int R_BPF_NONE = 0;
|
||||
/** S + A */
|
||||
public static final int R_BPF_64_64 = 1;
|
||||
/** S + A */
|
||||
public static final int R_BPF_64_ABS64 = 2;
|
||||
/** S + A */
|
||||
public static final int R_BPF_64_ABS32 = 3;
|
||||
/** S + A */
|
||||
public static final int R_BPF_64_NODYLD32 = 4;
|
||||
/** (S + A) / 8 - 1 */
|
||||
public static final int R_BPF_64_32 = 10;
|
||||
|
||||
private eBPF_ElfRelocationConstants() {
|
||||
// no construct
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.bin.format.elf.relocation;
|
||||
|
||||
import ghidra.app.util.bin.format.elf.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.symbol.SymbolTable;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
public class eBPF_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
@Override
|
||||
public boolean canRelocate(ElfHeader elf) {
|
||||
return elf.e_machine() == ElfConstants.EM_BPF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RelocationResult relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
|
||||
Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
||||
|
||||
ElfHeader elf = elfRelocationContext.getElfHeader();
|
||||
if (elf.e_machine() != ElfConstants.EM_BPF) {
|
||||
return RelocationResult.FAILURE;
|
||||
}
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
Memory memory = program.getMemory();
|
||||
|
||||
int type = relocation.getType();
|
||||
if (type == eBPF_ElfRelocationConstants.R_BPF_NONE) {
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
|
||||
String section_name = elfRelocationContext.relocationTable.getSectionToBeRelocated().getNameAsString();
|
||||
if (section_name.toString().contains("debug")) {
|
||||
return RelocationResult.SKIPPED;
|
||||
}
|
||||
|
||||
SymbolTable table = program.getSymbolTable();
|
||||
int symbolIndex = relocation.getSymbolIndex();
|
||||
ElfSymbol symbol = elfRelocationContext.getSymbol(symbolIndex);
|
||||
String symbolName = symbol.getNameAsString();
|
||||
Address symbolAddr = table.getSymbols(symbolName).next().getAddress();
|
||||
|
||||
long new_value = 0;
|
||||
int byteLength = 4; // most relocations affect 4-bytes
|
||||
|
||||
try {
|
||||
switch (type){
|
||||
case eBPF_ElfRelocationConstants.R_BPF_64_64: {
|
||||
new_value = symbolAddr.getAddressableWordOffset();
|
||||
Byte dst = memory.getByte(relocationAddress.add(0x1));
|
||||
memory.setLong(relocationAddress.add(0x4), new_value);
|
||||
memory.setByte(relocationAddress.add(0x1), (byte)(dst + 0x10));
|
||||
break;
|
||||
}
|
||||
case eBPF_ElfRelocationConstants.R_BPF_64_32: {
|
||||
|
||||
// if we have, e.g, non-static function, it will be marked in the relocation table
|
||||
// and indexed in the symbol table and it's easy to calculate the pc-relative offset
|
||||
long instr_next = relocationAddress.add(0x8).getAddressableWordOffset();
|
||||
if (symbol.isFunction()) {
|
||||
new_value = symbolAddr.getAddressableWordOffset();
|
||||
int offset = (int)(new_value - instr_next);
|
||||
memory.setInt(relocationAddress.add(0x4), offset);
|
||||
} else if (symbol.isSection()) {
|
||||
if (memory.getInt(relocationAddress) == 0x1085) {
|
||||
ElfSectionHeader sectionHeader = elfRelocationContext.getElfHeader().getSection(symbolName);
|
||||
long section_start = program.getImageBase().getOffset() + sectionHeader.getAddress();
|
||||
|
||||
// getting call instruction offset (current imm)
|
||||
int current_imm = memory.getInt(relocationAddress.add(0x4));
|
||||
|
||||
// calculate the call target section offset
|
||||
// according to formula in "kernel.org" docs: https://www.kernel.org/doc/html/latest/bpf/llvm_reloc.html
|
||||
int func_sec_offset = (current_imm + 1) * 8;
|
||||
long func_addr = section_start + func_sec_offset;
|
||||
int offset = (int)(func_addr - instr_next);
|
||||
memory.setInt(relocationAddress.add(0x4), offset);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (symbolIndex == 0) {
|
||||
markAsWarning(program, relocationAddress,
|
||||
Long.toString(type), "applied relocation with symbol-index of 0", elfRelocationContext.getLog());
|
||||
}
|
||||
return RelocationResult.UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException e) { }
|
||||
return new RelocationResult(Status.APPLIED, byteLength);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user