1e6ddac0dSAlexei Starovoitov //===- BPFDisassembler.cpp - Disassembler for BPF ---------------*- C++ -*-===//
2e6ddac0dSAlexei Starovoitov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e6ddac0dSAlexei Starovoitov //
7e6ddac0dSAlexei Starovoitov //===----------------------------------------------------------------------===//
8e6ddac0dSAlexei Starovoitov //
9e6ddac0dSAlexei Starovoitov // This file is part of the BPF Disassembler.
10e6ddac0dSAlexei Starovoitov //
11e6ddac0dSAlexei Starovoitov //===----------------------------------------------------------------------===//
12e6ddac0dSAlexei Starovoitov
13e6ddac0dSAlexei Starovoitov #include "MCTargetDesc/BPFMCTargetDesc.h"
14a68ee931SRichard Trieu #include "TargetInfo/BPFTargetInfo.h"
154282c404SEugene Zelenko #include "llvm/ADT/ArrayRef.h"
166bda14b3SChandler Carruth #include "llvm/MC/MCAsmInfo.h"
176bda14b3SChandler Carruth #include "llvm/MC/MCContext.h"
18*c644488aSSheng #include "llvm/MC/MCDecoderOps.h"
19e6ddac0dSAlexei Starovoitov #include "llvm/MC/MCDisassembler/MCDisassembler.h"
20e6ddac0dSAlexei Starovoitov #include "llvm/MC/MCInst.h"
21ef736a1cSserge-sans-paille #include "llvm/MC/SubtargetFeature.h"
2289b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h"
234282c404SEugene Zelenko #include "llvm/Support/MathExtras.h"
244282c404SEugene Zelenko #include <cstdint>
25e6ddac0dSAlexei Starovoitov
26e6ddac0dSAlexei Starovoitov using namespace llvm;
27e6ddac0dSAlexei Starovoitov
28e6ddac0dSAlexei Starovoitov #define DEBUG_TYPE "bpf-disassembler"
29e6ddac0dSAlexei Starovoitov
30e6ddac0dSAlexei Starovoitov typedef MCDisassembler::DecodeStatus DecodeStatus;
31e6ddac0dSAlexei Starovoitov
32e6ddac0dSAlexei Starovoitov namespace {
33e6ddac0dSAlexei Starovoitov
34e6ddac0dSAlexei Starovoitov /// A disassembler class for BPF.
35e6ddac0dSAlexei Starovoitov class BPFDisassembler : public MCDisassembler {
36e6ddac0dSAlexei Starovoitov public:
37ae961bb0SYonghong Song enum BPF_CLASS {
38ae961bb0SYonghong Song BPF_LD = 0x0,
39ae961bb0SYonghong Song BPF_LDX = 0x1,
40ae961bb0SYonghong Song BPF_ST = 0x2,
41ae961bb0SYonghong Song BPF_STX = 0x3,
42ae961bb0SYonghong Song BPF_ALU = 0x4,
43ae961bb0SYonghong Song BPF_JMP = 0x5,
4466b18e57SJiong Wang BPF_JMP32 = 0x6,
45ae961bb0SYonghong Song BPF_ALU64 = 0x7
46ae961bb0SYonghong Song };
47ae961bb0SYonghong Song
48ae961bb0SYonghong Song enum BPF_SIZE {
49ae961bb0SYonghong Song BPF_W = 0x0,
50ae961bb0SYonghong Song BPF_H = 0x1,
51ae961bb0SYonghong Song BPF_B = 0x2,
52ae961bb0SYonghong Song BPF_DW = 0x3
53ae961bb0SYonghong Song };
54ae961bb0SYonghong Song
55ae961bb0SYonghong Song enum BPF_MODE {
56ae961bb0SYonghong Song BPF_IMM = 0x0,
57ae961bb0SYonghong Song BPF_ABS = 0x1,
58ae961bb0SYonghong Song BPF_IND = 0x2,
59ae961bb0SYonghong Song BPF_MEM = 0x3,
60ae961bb0SYonghong Song BPF_LEN = 0x4,
61ae961bb0SYonghong Song BPF_MSH = 0x5,
62286daafdSYonghong Song BPF_ATOMIC = 0x6
63ae961bb0SYonghong Song };
64ae961bb0SYonghong Song
BPFDisassembler(const MCSubtargetInfo & STI,MCContext & Ctx)65e6ddac0dSAlexei Starovoitov BPFDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
66e6ddac0dSAlexei Starovoitov : MCDisassembler(STI, Ctx) {}
674282c404SEugene Zelenko ~BPFDisassembler() override = default;
68e6ddac0dSAlexei Starovoitov
69e6ddac0dSAlexei Starovoitov DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
70e6ddac0dSAlexei Starovoitov ArrayRef<uint8_t> Bytes, uint64_t Address,
71e6ddac0dSAlexei Starovoitov raw_ostream &CStream) const override;
72ae961bb0SYonghong Song
getInstClass(uint64_t Inst) const73ae961bb0SYonghong Song uint8_t getInstClass(uint64_t Inst) const { return (Inst >> 56) & 0x7; };
getInstSize(uint64_t Inst) const74ae961bb0SYonghong Song uint8_t getInstSize(uint64_t Inst) const { return (Inst >> 59) & 0x3; };
getInstMode(uint64_t Inst) const75ae961bb0SYonghong Song uint8_t getInstMode(uint64_t Inst) const { return (Inst >> 61) & 0x7; };
76e6ddac0dSAlexei Starovoitov };
774282c404SEugene Zelenko
784282c404SEugene Zelenko } // end anonymous namespace
79e6ddac0dSAlexei Starovoitov
createBPFDisassembler(const Target & T,const MCSubtargetInfo & STI,MCContext & Ctx)80e6ddac0dSAlexei Starovoitov static MCDisassembler *createBPFDisassembler(const Target &T,
81e6ddac0dSAlexei Starovoitov const MCSubtargetInfo &STI,
82e6ddac0dSAlexei Starovoitov MCContext &Ctx) {
83e6ddac0dSAlexei Starovoitov return new BPFDisassembler(STI, Ctx);
84e6ddac0dSAlexei Starovoitov }
85e6ddac0dSAlexei Starovoitov
86e6ddac0dSAlexei Starovoitov
LLVMInitializeBPFDisassembler()870dbcb363STom Stellard extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFDisassembler() {
88e6ddac0dSAlexei Starovoitov // Register the disassembler.
89e6ddac0dSAlexei Starovoitov TargetRegistry::RegisterMCDisassembler(getTheBPFTarget(),
90e6ddac0dSAlexei Starovoitov createBPFDisassembler);
91e6ddac0dSAlexei Starovoitov TargetRegistry::RegisterMCDisassembler(getTheBPFleTarget(),
92e6ddac0dSAlexei Starovoitov createBPFDisassembler);
93e6ddac0dSAlexei Starovoitov TargetRegistry::RegisterMCDisassembler(getTheBPFbeTarget(),
94e6ddac0dSAlexei Starovoitov createBPFDisassembler);
95e6ddac0dSAlexei Starovoitov }
96e6ddac0dSAlexei Starovoitov
97e6ddac0dSAlexei Starovoitov static const unsigned GPRDecoderTable[] = {
98e6ddac0dSAlexei Starovoitov BPF::R0, BPF::R1, BPF::R2, BPF::R3, BPF::R4, BPF::R5,
99e6ddac0dSAlexei Starovoitov BPF::R6, BPF::R7, BPF::R8, BPF::R9, BPF::R10, BPF::R11};
100e6ddac0dSAlexei Starovoitov
DecodeGPRRegisterClass(MCInst & Inst,unsigned RegNo,uint64_t,const MCDisassembler *)101e6ddac0dSAlexei Starovoitov static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo,
102e6ddac0dSAlexei Starovoitov uint64_t /*Address*/,
1034ae9745aSMaksim Panchenko const MCDisassembler * /*Decoder*/) {
104e6ddac0dSAlexei Starovoitov if (RegNo > 11)
105e6ddac0dSAlexei Starovoitov return MCDisassembler::Fail;
106e6ddac0dSAlexei Starovoitov
107e6ddac0dSAlexei Starovoitov unsigned Reg = GPRDecoderTable[RegNo];
108e6ddac0dSAlexei Starovoitov Inst.addOperand(MCOperand::createReg(Reg));
109e6ddac0dSAlexei Starovoitov return MCDisassembler::Success;
110e6ddac0dSAlexei Starovoitov }
111e6ddac0dSAlexei Starovoitov
112d2e0d1faSYonghong Song static const unsigned GPR32DecoderTable[] = {
113d2e0d1faSYonghong Song BPF::W0, BPF::W1, BPF::W2, BPF::W3, BPF::W4, BPF::W5,
114d2e0d1faSYonghong Song BPF::W6, BPF::W7, BPF::W8, BPF::W9, BPF::W10, BPF::W11};
115d2e0d1faSYonghong Song
1164ae9745aSMaksim Panchenko static DecodeStatus
DecodeGPR32RegisterClass(MCInst & Inst,unsigned RegNo,uint64_t,const MCDisassembler *)1174ae9745aSMaksim Panchenko DecodeGPR32RegisterClass(MCInst &Inst, unsigned RegNo, uint64_t /*Address*/,
1184ae9745aSMaksim Panchenko const MCDisassembler * /*Decoder*/) {
119d2e0d1faSYonghong Song if (RegNo > 11)
120d2e0d1faSYonghong Song return MCDisassembler::Fail;
121d2e0d1faSYonghong Song
122d2e0d1faSYonghong Song unsigned Reg = GPR32DecoderTable[RegNo];
123d2e0d1faSYonghong Song Inst.addOperand(MCOperand::createReg(Reg));
124d2e0d1faSYonghong Song return MCDisassembler::Success;
125d2e0d1faSYonghong Song }
126d2e0d1faSYonghong Song
decodeMemoryOpValue(MCInst & Inst,unsigned Insn,uint64_t Address,const MCDisassembler * Decoder)127e6ddac0dSAlexei Starovoitov static DecodeStatus decodeMemoryOpValue(MCInst &Inst, unsigned Insn,
1284ae9745aSMaksim Panchenko uint64_t Address,
1294ae9745aSMaksim Panchenko const MCDisassembler *Decoder) {
130e6ddac0dSAlexei Starovoitov unsigned Register = (Insn >> 16) & 0xf;
131eec75882SYonghong Song if (Register > 11)
132eec75882SYonghong Song return MCDisassembler::Fail;
133eec75882SYonghong Song
134e6ddac0dSAlexei Starovoitov Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register]));
135e6ddac0dSAlexei Starovoitov unsigned Offset = (Insn & 0xffff);
136e6ddac0dSAlexei Starovoitov Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Offset)));
137e6ddac0dSAlexei Starovoitov
138e6ddac0dSAlexei Starovoitov return MCDisassembler::Success;
139e6ddac0dSAlexei Starovoitov }
140e6ddac0dSAlexei Starovoitov
141e6ddac0dSAlexei Starovoitov #include "BPFGenDisassemblerTables.inc"
readInstruction64(ArrayRef<uint8_t> Bytes,uint64_t Address,uint64_t & Size,uint64_t & Insn,bool IsLittleEndian)142e6ddac0dSAlexei Starovoitov static DecodeStatus readInstruction64(ArrayRef<uint8_t> Bytes, uint64_t Address,
143f7bd5ebdSAlexei Starovoitov uint64_t &Size, uint64_t &Insn,
144f7bd5ebdSAlexei Starovoitov bool IsLittleEndian) {
145e6ddac0dSAlexei Starovoitov uint64_t Lo, Hi;
146e6ddac0dSAlexei Starovoitov
147e6ddac0dSAlexei Starovoitov if (Bytes.size() < 8) {
148e6ddac0dSAlexei Starovoitov Size = 0;
149e6ddac0dSAlexei Starovoitov return MCDisassembler::Fail;
150e6ddac0dSAlexei Starovoitov }
151e6ddac0dSAlexei Starovoitov
152e6ddac0dSAlexei Starovoitov Size = 8;
153f7bd5ebdSAlexei Starovoitov if (IsLittleEndian) {
154e6ddac0dSAlexei Starovoitov Hi = (Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 0) | (Bytes[3] << 8);
155e6ddac0dSAlexei Starovoitov Lo = (Bytes[4] << 0) | (Bytes[5] << 8) | (Bytes[6] << 16) | (Bytes[7] << 24);
156f7bd5ebdSAlexei Starovoitov } else {
157f7bd5ebdSAlexei Starovoitov Hi = (Bytes[0] << 24) | ((Bytes[1] & 0x0F) << 20) | ((Bytes[1] & 0xF0) << 12) |
158f7bd5ebdSAlexei Starovoitov (Bytes[2] << 8) | (Bytes[3] << 0);
159f7bd5ebdSAlexei Starovoitov Lo = (Bytes[4] << 24) | (Bytes[5] << 16) | (Bytes[6] << 8) | (Bytes[7] << 0);
160f7bd5ebdSAlexei Starovoitov }
161e6ddac0dSAlexei Starovoitov Insn = Make_64(Hi, Lo);
162e6ddac0dSAlexei Starovoitov
163e6ddac0dSAlexei Starovoitov return MCDisassembler::Success;
164e6ddac0dSAlexei Starovoitov }
165e6ddac0dSAlexei Starovoitov
getInstruction(MCInst & Instr,uint64_t & Size,ArrayRef<uint8_t> Bytes,uint64_t Address,raw_ostream & CStream) const166e6ddac0dSAlexei Starovoitov DecodeStatus BPFDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
167e6ddac0dSAlexei Starovoitov ArrayRef<uint8_t> Bytes,
168e6ddac0dSAlexei Starovoitov uint64_t Address,
169e6ddac0dSAlexei Starovoitov raw_ostream &CStream) const {
170f7bd5ebdSAlexei Starovoitov bool IsLittleEndian = getContext().getAsmInfo()->isLittleEndian();
171f7bd5ebdSAlexei Starovoitov uint64_t Insn, Hi;
172e6ddac0dSAlexei Starovoitov DecodeStatus Result;
173e6ddac0dSAlexei Starovoitov
174f7bd5ebdSAlexei Starovoitov Result = readInstruction64(Bytes, Address, Size, Insn, IsLittleEndian);
175e6ddac0dSAlexei Starovoitov if (Result == MCDisassembler::Fail) return MCDisassembler::Fail;
176e6ddac0dSAlexei Starovoitov
177ae961bb0SYonghong Song uint8_t InstClass = getInstClass(Insn);
1780a039660SJiong Wang uint8_t InstMode = getInstMode(Insn);
179ae961bb0SYonghong Song if ((InstClass == BPF_LDX || InstClass == BPF_STX) &&
180ae961bb0SYonghong Song getInstSize(Insn) != BPF_DW &&
181286daafdSYonghong Song (InstMode == BPF_MEM || InstMode == BPF_ATOMIC) &&
182ae961bb0SYonghong Song STI.getFeatureBits()[BPF::ALU32])
183ae961bb0SYonghong Song Result = decodeInstruction(DecoderTableBPFALU3264, Instr, Insn, Address,
184ae961bb0SYonghong Song this, STI);
185ae961bb0SYonghong Song else
186ae961bb0SYonghong Song Result = decodeInstruction(DecoderTableBPF64, Instr, Insn, Address, this,
187ae961bb0SYonghong Song STI);
188ae961bb0SYonghong Song
189e6ddac0dSAlexei Starovoitov if (Result == MCDisassembler::Fail) return MCDisassembler::Fail;
190e6ddac0dSAlexei Starovoitov
191e6ddac0dSAlexei Starovoitov switch (Instr.getOpcode()) {
192ef29a84dSYonghong Song case BPF::LD_imm64:
193ef29a84dSYonghong Song case BPF::LD_pseudo: {
194e6ddac0dSAlexei Starovoitov if (Bytes.size() < 16) {
195e6ddac0dSAlexei Starovoitov Size = 0;
196e6ddac0dSAlexei Starovoitov return MCDisassembler::Fail;
197e6ddac0dSAlexei Starovoitov }
198e6ddac0dSAlexei Starovoitov Size = 16;
199f7bd5ebdSAlexei Starovoitov if (IsLittleEndian)
200f7bd5ebdSAlexei Starovoitov Hi = (Bytes[12] << 0) | (Bytes[13] << 8) | (Bytes[14] << 16) | (Bytes[15] << 24);
201f7bd5ebdSAlexei Starovoitov else
202f7bd5ebdSAlexei Starovoitov Hi = (Bytes[12] << 24) | (Bytes[13] << 16) | (Bytes[14] << 8) | (Bytes[15] << 0);
203e6ddac0dSAlexei Starovoitov auto& Op = Instr.getOperand(1);
204e6ddac0dSAlexei Starovoitov Op.setImm(Make_64(Hi, Op.getImm()));
205e6ddac0dSAlexei Starovoitov break;
206e6ddac0dSAlexei Starovoitov }
207e6ddac0dSAlexei Starovoitov case BPF::LD_ABS_B:
208e6ddac0dSAlexei Starovoitov case BPF::LD_ABS_H:
209e6ddac0dSAlexei Starovoitov case BPF::LD_ABS_W:
210e6ddac0dSAlexei Starovoitov case BPF::LD_IND_B:
211e6ddac0dSAlexei Starovoitov case BPF::LD_IND_H:
212e6ddac0dSAlexei Starovoitov case BPF::LD_IND_W: {
213e6ddac0dSAlexei Starovoitov auto Op = Instr.getOperand(0);
214e6ddac0dSAlexei Starovoitov Instr.clear();
215e6ddac0dSAlexei Starovoitov Instr.addOperand(MCOperand::createReg(BPF::R6));
216e6ddac0dSAlexei Starovoitov Instr.addOperand(Op);
217e6ddac0dSAlexei Starovoitov break;
218e6ddac0dSAlexei Starovoitov }
219e6ddac0dSAlexei Starovoitov }
220e6ddac0dSAlexei Starovoitov
221e6ddac0dSAlexei Starovoitov return Result;
222e6ddac0dSAlexei Starovoitov }
223e6ddac0dSAlexei Starovoitov
224e6ddac0dSAlexei Starovoitov typedef DecodeStatus (*DecodeFunc)(MCInst &MI, unsigned insn, uint64_t Address,
2254ae9745aSMaksim Panchenko const MCDisassembler *Decoder);
226