1d88c1a5aSDimitry Andric //===- BPFDisassembler.cpp - Disassembler for BPF ---------------*- C++ -*-===//
2d88c1a5aSDimitry Andric //
3d88c1a5aSDimitry Andric // The LLVM Compiler Infrastructure
4d88c1a5aSDimitry Andric //
5d88c1a5aSDimitry Andric // This file is distributed under the University of Illinois Open Source
6d88c1a5aSDimitry Andric // License. See LICENSE.TXT for details.
7d88c1a5aSDimitry Andric //
8d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
9d88c1a5aSDimitry Andric //
10d88c1a5aSDimitry Andric // This file is part of the BPF Disassembler.
11d88c1a5aSDimitry Andric //
12d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
13d88c1a5aSDimitry Andric
14d88c1a5aSDimitry Andric #include "MCTargetDesc/BPFMCTargetDesc.h"
1524e2fe98SDimitry Andric #include "llvm/ADT/ArrayRef.h"
16db17bf38SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
17db17bf38SDimitry Andric #include "llvm/MC/MCContext.h"
18d88c1a5aSDimitry Andric #include "llvm/MC/MCDisassembler/MCDisassembler.h"
19d88c1a5aSDimitry Andric #include "llvm/MC/MCFixedLenDisassembler.h"
20d88c1a5aSDimitry Andric #include "llvm/MC/MCInst.h"
2124e2fe98SDimitry Andric #include "llvm/Support/MathExtras.h"
22d88c1a5aSDimitry Andric #include "llvm/Support/TargetRegistry.h"
2324e2fe98SDimitry Andric #include <cstdint>
24d88c1a5aSDimitry Andric
25d88c1a5aSDimitry Andric using namespace llvm;
26d88c1a5aSDimitry Andric
27d88c1a5aSDimitry Andric #define DEBUG_TYPE "bpf-disassembler"
28d88c1a5aSDimitry Andric
29d88c1a5aSDimitry Andric typedef MCDisassembler::DecodeStatus DecodeStatus;
30d88c1a5aSDimitry Andric
31d88c1a5aSDimitry Andric namespace {
32d88c1a5aSDimitry Andric
33d88c1a5aSDimitry Andric /// A disassembler class for BPF.
34d88c1a5aSDimitry Andric class BPFDisassembler : public MCDisassembler {
35d88c1a5aSDimitry Andric public:
36*4ba319b5SDimitry Andric enum BPF_CLASS {
37*4ba319b5SDimitry Andric BPF_LD = 0x0,
38*4ba319b5SDimitry Andric BPF_LDX = 0x1,
39*4ba319b5SDimitry Andric BPF_ST = 0x2,
40*4ba319b5SDimitry Andric BPF_STX = 0x3,
41*4ba319b5SDimitry Andric BPF_ALU = 0x4,
42*4ba319b5SDimitry Andric BPF_JMP = 0x5,
43*4ba319b5SDimitry Andric BPF_RES = 0x6,
44*4ba319b5SDimitry Andric BPF_ALU64 = 0x7
45*4ba319b5SDimitry Andric };
46*4ba319b5SDimitry Andric
47*4ba319b5SDimitry Andric enum BPF_SIZE {
48*4ba319b5SDimitry Andric BPF_W = 0x0,
49*4ba319b5SDimitry Andric BPF_H = 0x1,
50*4ba319b5SDimitry Andric BPF_B = 0x2,
51*4ba319b5SDimitry Andric BPF_DW = 0x3
52*4ba319b5SDimitry Andric };
53*4ba319b5SDimitry Andric
54*4ba319b5SDimitry Andric enum BPF_MODE {
55*4ba319b5SDimitry Andric BPF_IMM = 0x0,
56*4ba319b5SDimitry Andric BPF_ABS = 0x1,
57*4ba319b5SDimitry Andric BPF_IND = 0x2,
58*4ba319b5SDimitry Andric BPF_MEM = 0x3,
59*4ba319b5SDimitry Andric BPF_LEN = 0x4,
60*4ba319b5SDimitry Andric BPF_MSH = 0x5,
61*4ba319b5SDimitry Andric BPF_XADD = 0x6
62*4ba319b5SDimitry Andric };
63*4ba319b5SDimitry Andric
BPFDisassembler(const MCSubtargetInfo & STI,MCContext & Ctx)64d88c1a5aSDimitry Andric BPFDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
65d88c1a5aSDimitry Andric : MCDisassembler(STI, Ctx) {}
6624e2fe98SDimitry Andric ~BPFDisassembler() override = default;
67d88c1a5aSDimitry Andric
68d88c1a5aSDimitry Andric DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
69d88c1a5aSDimitry Andric ArrayRef<uint8_t> Bytes, uint64_t Address,
70d88c1a5aSDimitry Andric raw_ostream &VStream,
71d88c1a5aSDimitry Andric raw_ostream &CStream) const override;
72*4ba319b5SDimitry Andric
getInstClass(uint64_t Inst) const73*4ba319b5SDimitry Andric uint8_t getInstClass(uint64_t Inst) const { return (Inst >> 56) & 0x7; };
getInstSize(uint64_t Inst) const74*4ba319b5SDimitry Andric uint8_t getInstSize(uint64_t Inst) const { return (Inst >> 59) & 0x3; };
getInstMode(uint64_t Inst) const75*4ba319b5SDimitry Andric uint8_t getInstMode(uint64_t Inst) const { return (Inst >> 61) & 0x7; };
76d88c1a5aSDimitry Andric };
7724e2fe98SDimitry Andric
7824e2fe98SDimitry Andric } // end anonymous namespace
79d88c1a5aSDimitry Andric
createBPFDisassembler(const Target & T,const MCSubtargetInfo & STI,MCContext & Ctx)80d88c1a5aSDimitry Andric static MCDisassembler *createBPFDisassembler(const Target &T,
81d88c1a5aSDimitry Andric const MCSubtargetInfo &STI,
82d88c1a5aSDimitry Andric MCContext &Ctx) {
83d88c1a5aSDimitry Andric return new BPFDisassembler(STI, Ctx);
84d88c1a5aSDimitry Andric }
85d88c1a5aSDimitry Andric
86d88c1a5aSDimitry Andric
LLVMInitializeBPFDisassembler()87d88c1a5aSDimitry Andric extern "C" void LLVMInitializeBPFDisassembler() {
88d88c1a5aSDimitry Andric // Register the disassembler.
89d88c1a5aSDimitry Andric TargetRegistry::RegisterMCDisassembler(getTheBPFTarget(),
90d88c1a5aSDimitry Andric createBPFDisassembler);
91d88c1a5aSDimitry Andric TargetRegistry::RegisterMCDisassembler(getTheBPFleTarget(),
92d88c1a5aSDimitry Andric createBPFDisassembler);
93d88c1a5aSDimitry Andric TargetRegistry::RegisterMCDisassembler(getTheBPFbeTarget(),
94d88c1a5aSDimitry Andric createBPFDisassembler);
95d88c1a5aSDimitry Andric }
96d88c1a5aSDimitry Andric
97d88c1a5aSDimitry Andric static const unsigned GPRDecoderTable[] = {
98d88c1a5aSDimitry Andric BPF::R0, BPF::R1, BPF::R2, BPF::R3, BPF::R4, BPF::R5,
99d88c1a5aSDimitry Andric BPF::R6, BPF::R7, BPF::R8, BPF::R9, BPF::R10, BPF::R11};
100d88c1a5aSDimitry Andric
DecodeGPRRegisterClass(MCInst & Inst,unsigned RegNo,uint64_t,const void *)101d88c1a5aSDimitry Andric static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo,
102d88c1a5aSDimitry Andric uint64_t /*Address*/,
103d88c1a5aSDimitry Andric const void * /*Decoder*/) {
104d88c1a5aSDimitry Andric if (RegNo > 11)
105d88c1a5aSDimitry Andric return MCDisassembler::Fail;
106d88c1a5aSDimitry Andric
107d88c1a5aSDimitry Andric unsigned Reg = GPRDecoderTable[RegNo];
108d88c1a5aSDimitry Andric Inst.addOperand(MCOperand::createReg(Reg));
109d88c1a5aSDimitry Andric return MCDisassembler::Success;
110d88c1a5aSDimitry Andric }
111d88c1a5aSDimitry Andric
1122cab237bSDimitry Andric static const unsigned GPR32DecoderTable[] = {
1132cab237bSDimitry Andric BPF::W0, BPF::W1, BPF::W2, BPF::W3, BPF::W4, BPF::W5,
1142cab237bSDimitry Andric BPF::W6, BPF::W7, BPF::W8, BPF::W9, BPF::W10, BPF::W11};
1152cab237bSDimitry Andric
DecodeGPR32RegisterClass(MCInst & Inst,unsigned RegNo,uint64_t,const void *)1162cab237bSDimitry Andric static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, unsigned RegNo,
1172cab237bSDimitry Andric uint64_t /*Address*/,
1182cab237bSDimitry Andric const void * /*Decoder*/) {
1192cab237bSDimitry Andric if (RegNo > 11)
1202cab237bSDimitry Andric return MCDisassembler::Fail;
1212cab237bSDimitry Andric
1222cab237bSDimitry Andric unsigned Reg = GPR32DecoderTable[RegNo];
1232cab237bSDimitry Andric Inst.addOperand(MCOperand::createReg(Reg));
1242cab237bSDimitry Andric return MCDisassembler::Success;
1252cab237bSDimitry Andric }
1262cab237bSDimitry Andric
decodeMemoryOpValue(MCInst & Inst,unsigned Insn,uint64_t Address,const void * Decoder)127d88c1a5aSDimitry Andric static DecodeStatus decodeMemoryOpValue(MCInst &Inst, unsigned Insn,
128d88c1a5aSDimitry Andric uint64_t Address, const void *Decoder) {
129d88c1a5aSDimitry Andric unsigned Register = (Insn >> 16) & 0xf;
130d88c1a5aSDimitry Andric Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register]));
131d88c1a5aSDimitry Andric unsigned Offset = (Insn & 0xffff);
132d88c1a5aSDimitry Andric Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Offset)));
133d88c1a5aSDimitry Andric
134d88c1a5aSDimitry Andric return MCDisassembler::Success;
135d88c1a5aSDimitry Andric }
136d88c1a5aSDimitry Andric
137d88c1a5aSDimitry Andric #include "BPFGenDisassemblerTables.inc"
readInstruction64(ArrayRef<uint8_t> Bytes,uint64_t Address,uint64_t & Size,uint64_t & Insn,bool IsLittleEndian)138d88c1a5aSDimitry Andric static DecodeStatus readInstruction64(ArrayRef<uint8_t> Bytes, uint64_t Address,
139f37b6182SDimitry Andric uint64_t &Size, uint64_t &Insn,
140f37b6182SDimitry Andric bool IsLittleEndian) {
141d88c1a5aSDimitry Andric uint64_t Lo, Hi;
142d88c1a5aSDimitry Andric
143d88c1a5aSDimitry Andric if (Bytes.size() < 8) {
144d88c1a5aSDimitry Andric Size = 0;
145d88c1a5aSDimitry Andric return MCDisassembler::Fail;
146d88c1a5aSDimitry Andric }
147d88c1a5aSDimitry Andric
148d88c1a5aSDimitry Andric Size = 8;
149f37b6182SDimitry Andric if (IsLittleEndian) {
150d88c1a5aSDimitry Andric Hi = (Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 0) | (Bytes[3] << 8);
151d88c1a5aSDimitry Andric Lo = (Bytes[4] << 0) | (Bytes[5] << 8) | (Bytes[6] << 16) | (Bytes[7] << 24);
152f37b6182SDimitry Andric } else {
153f37b6182SDimitry Andric Hi = (Bytes[0] << 24) | ((Bytes[1] & 0x0F) << 20) | ((Bytes[1] & 0xF0) << 12) |
154f37b6182SDimitry Andric (Bytes[2] << 8) | (Bytes[3] << 0);
155f37b6182SDimitry Andric Lo = (Bytes[4] << 24) | (Bytes[5] << 16) | (Bytes[6] << 8) | (Bytes[7] << 0);
156f37b6182SDimitry Andric }
157d88c1a5aSDimitry Andric Insn = Make_64(Hi, Lo);
158d88c1a5aSDimitry Andric
159d88c1a5aSDimitry Andric return MCDisassembler::Success;
160d88c1a5aSDimitry Andric }
161d88c1a5aSDimitry Andric
getInstruction(MCInst & Instr,uint64_t & Size,ArrayRef<uint8_t> Bytes,uint64_t Address,raw_ostream & VStream,raw_ostream & CStream) const162d88c1a5aSDimitry Andric DecodeStatus BPFDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
163d88c1a5aSDimitry Andric ArrayRef<uint8_t> Bytes,
164d88c1a5aSDimitry Andric uint64_t Address,
165d88c1a5aSDimitry Andric raw_ostream &VStream,
166d88c1a5aSDimitry Andric raw_ostream &CStream) const {
167f37b6182SDimitry Andric bool IsLittleEndian = getContext().getAsmInfo()->isLittleEndian();
168f37b6182SDimitry Andric uint64_t Insn, Hi;
169d88c1a5aSDimitry Andric DecodeStatus Result;
170d88c1a5aSDimitry Andric
171f37b6182SDimitry Andric Result = readInstruction64(Bytes, Address, Size, Insn, IsLittleEndian);
172d88c1a5aSDimitry Andric if (Result == MCDisassembler::Fail) return MCDisassembler::Fail;
173d88c1a5aSDimitry Andric
174*4ba319b5SDimitry Andric uint8_t InstClass = getInstClass(Insn);
175*4ba319b5SDimitry Andric if ((InstClass == BPF_LDX || InstClass == BPF_STX) &&
176*4ba319b5SDimitry Andric getInstSize(Insn) != BPF_DW &&
177*4ba319b5SDimitry Andric getInstMode(Insn) == BPF_MEM &&
178*4ba319b5SDimitry Andric STI.getFeatureBits()[BPF::ALU32])
179*4ba319b5SDimitry Andric Result = decodeInstruction(DecoderTableBPFALU3264, Instr, Insn, Address,
180*4ba319b5SDimitry Andric this, STI);
181*4ba319b5SDimitry Andric else
182*4ba319b5SDimitry Andric Result = decodeInstruction(DecoderTableBPF64, Instr, Insn, Address, this,
183*4ba319b5SDimitry Andric STI);
184*4ba319b5SDimitry Andric
185d88c1a5aSDimitry Andric if (Result == MCDisassembler::Fail) return MCDisassembler::Fail;
186d88c1a5aSDimitry Andric
187d88c1a5aSDimitry Andric switch (Instr.getOpcode()) {
1882cab237bSDimitry Andric case BPF::LD_imm64:
1892cab237bSDimitry Andric case BPF::LD_pseudo: {
190d88c1a5aSDimitry Andric if (Bytes.size() < 16) {
191d88c1a5aSDimitry Andric Size = 0;
192d88c1a5aSDimitry Andric return MCDisassembler::Fail;
193d88c1a5aSDimitry Andric }
194d88c1a5aSDimitry Andric Size = 16;
195f37b6182SDimitry Andric if (IsLittleEndian)
196f37b6182SDimitry Andric Hi = (Bytes[12] << 0) | (Bytes[13] << 8) | (Bytes[14] << 16) | (Bytes[15] << 24);
197f37b6182SDimitry Andric else
198f37b6182SDimitry Andric Hi = (Bytes[12] << 24) | (Bytes[13] << 16) | (Bytes[14] << 8) | (Bytes[15] << 0);
199d88c1a5aSDimitry Andric auto& Op = Instr.getOperand(1);
200d88c1a5aSDimitry Andric Op.setImm(Make_64(Hi, Op.getImm()));
201d88c1a5aSDimitry Andric break;
202d88c1a5aSDimitry Andric }
203d88c1a5aSDimitry Andric case BPF::LD_ABS_B:
204d88c1a5aSDimitry Andric case BPF::LD_ABS_H:
205d88c1a5aSDimitry Andric case BPF::LD_ABS_W:
206d88c1a5aSDimitry Andric case BPF::LD_IND_B:
207d88c1a5aSDimitry Andric case BPF::LD_IND_H:
208d88c1a5aSDimitry Andric case BPF::LD_IND_W: {
209d88c1a5aSDimitry Andric auto Op = Instr.getOperand(0);
210d88c1a5aSDimitry Andric Instr.clear();
211d88c1a5aSDimitry Andric Instr.addOperand(MCOperand::createReg(BPF::R6));
212d88c1a5aSDimitry Andric Instr.addOperand(Op);
213d88c1a5aSDimitry Andric break;
214d88c1a5aSDimitry Andric }
215d88c1a5aSDimitry Andric }
216d88c1a5aSDimitry Andric
217d88c1a5aSDimitry Andric return Result;
218d88c1a5aSDimitry Andric }
219d88c1a5aSDimitry Andric
220d88c1a5aSDimitry Andric typedef DecodeStatus (*DecodeFunc)(MCInst &MI, unsigned insn, uint64_t Address,
221d88c1a5aSDimitry Andric const void *Decoder);
222