1 //===- BPFDisassembler.cpp - Disassembler for BPF ---------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file is part of the BPF Disassembler.
11 //===----------------------------------------------------------------------===//
13 #include "MCTargetDesc/BPFMCTargetDesc.h"
14 #include "TargetInfo/BPFTargetInfo.h"
15 #include "llvm/ADT/ArrayRef.h"
16 #include "llvm/MC/MCAsmInfo.h"
17 #include "llvm/MC/MCContext.h"
18 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
19 #include "llvm/MC/MCFixedLenDisassembler.h"
20 #include "llvm/MC/MCInst.h"
21 #include "llvm/Support/MathExtras.h"
22 #include "llvm/Support/TargetRegistry.h"
27 #define DEBUG_TYPE "bpf-disassembler"
29 typedef MCDisassembler::DecodeStatus DecodeStatus
;
33 /// A disassembler class for BPF.
34 class BPFDisassembler
: public MCDisassembler
{
64 BPFDisassembler(const MCSubtargetInfo
&STI
, MCContext
&Ctx
)
65 : MCDisassembler(STI
, Ctx
) {}
66 ~BPFDisassembler() override
= default;
68 DecodeStatus
getInstruction(MCInst
&Instr
, uint64_t &Size
,
69 ArrayRef
<uint8_t> Bytes
, uint64_t Address
,
70 raw_ostream
&CStream
) const override
;
72 uint8_t getInstClass(uint64_t Inst
) const { return (Inst
>> 56) & 0x7; };
73 uint8_t getInstSize(uint64_t Inst
) const { return (Inst
>> 59) & 0x3; };
74 uint8_t getInstMode(uint64_t Inst
) const { return (Inst
>> 61) & 0x7; };
77 } // end anonymous namespace
79 static MCDisassembler
*createBPFDisassembler(const Target
&T
,
80 const MCSubtargetInfo
&STI
,
82 return new BPFDisassembler(STI
, Ctx
);
86 extern "C" LLVM_EXTERNAL_VISIBILITY
void LLVMInitializeBPFDisassembler() {
87 // Register the disassembler.
88 TargetRegistry::RegisterMCDisassembler(getTheBPFTarget(),
89 createBPFDisassembler
);
90 TargetRegistry::RegisterMCDisassembler(getTheBPFleTarget(),
91 createBPFDisassembler
);
92 TargetRegistry::RegisterMCDisassembler(getTheBPFbeTarget(),
93 createBPFDisassembler
);
96 static const unsigned GPRDecoderTable
[] = {
97 BPF::R0
, BPF::R1
, BPF::R2
, BPF::R3
, BPF::R4
, BPF::R5
,
98 BPF::R6
, BPF::R7
, BPF::R8
, BPF::R9
, BPF::R10
, BPF::R11
};
100 static DecodeStatus
DecodeGPRRegisterClass(MCInst
&Inst
, unsigned RegNo
,
101 uint64_t /*Address*/,
102 const void * /*Decoder*/) {
104 return MCDisassembler::Fail
;
106 unsigned Reg
= GPRDecoderTable
[RegNo
];
107 Inst
.addOperand(MCOperand::createReg(Reg
));
108 return MCDisassembler::Success
;
111 static const unsigned GPR32DecoderTable
[] = {
112 BPF::W0
, BPF::W1
, BPF::W2
, BPF::W3
, BPF::W4
, BPF::W5
,
113 BPF::W6
, BPF::W7
, BPF::W8
, BPF::W9
, BPF::W10
, BPF::W11
};
115 static DecodeStatus
DecodeGPR32RegisterClass(MCInst
&Inst
, unsigned RegNo
,
116 uint64_t /*Address*/,
117 const void * /*Decoder*/) {
119 return MCDisassembler::Fail
;
121 unsigned Reg
= GPR32DecoderTable
[RegNo
];
122 Inst
.addOperand(MCOperand::createReg(Reg
));
123 return MCDisassembler::Success
;
126 static DecodeStatus
decodeMemoryOpValue(MCInst
&Inst
, unsigned Insn
,
127 uint64_t Address
, const void *Decoder
) {
128 unsigned Register
= (Insn
>> 16) & 0xf;
130 return MCDisassembler::Fail
;
132 Inst
.addOperand(MCOperand::createReg(GPRDecoderTable
[Register
]));
133 unsigned Offset
= (Insn
& 0xffff);
134 Inst
.addOperand(MCOperand::createImm(SignExtend32
<16>(Offset
)));
136 return MCDisassembler::Success
;
139 #include "BPFGenDisassemblerTables.inc"
140 static DecodeStatus
readInstruction64(ArrayRef
<uint8_t> Bytes
, uint64_t Address
,
141 uint64_t &Size
, uint64_t &Insn
,
142 bool IsLittleEndian
) {
145 if (Bytes
.size() < 8) {
147 return MCDisassembler::Fail
;
151 if (IsLittleEndian
) {
152 Hi
= (Bytes
[0] << 24) | (Bytes
[1] << 16) | (Bytes
[2] << 0) | (Bytes
[3] << 8);
153 Lo
= (Bytes
[4] << 0) | (Bytes
[5] << 8) | (Bytes
[6] << 16) | (Bytes
[7] << 24);
155 Hi
= (Bytes
[0] << 24) | ((Bytes
[1] & 0x0F) << 20) | ((Bytes
[1] & 0xF0) << 12) |
156 (Bytes
[2] << 8) | (Bytes
[3] << 0);
157 Lo
= (Bytes
[4] << 24) | (Bytes
[5] << 16) | (Bytes
[6] << 8) | (Bytes
[7] << 0);
159 Insn
= Make_64(Hi
, Lo
);
161 return MCDisassembler::Success
;
164 DecodeStatus
BPFDisassembler::getInstruction(MCInst
&Instr
, uint64_t &Size
,
165 ArrayRef
<uint8_t> Bytes
,
167 raw_ostream
&CStream
) const {
168 bool IsLittleEndian
= getContext().getAsmInfo()->isLittleEndian();
172 Result
= readInstruction64(Bytes
, Address
, Size
, Insn
, IsLittleEndian
);
173 if (Result
== MCDisassembler::Fail
) return MCDisassembler::Fail
;
175 uint8_t InstClass
= getInstClass(Insn
);
176 uint8_t InstMode
= getInstMode(Insn
);
177 if ((InstClass
== BPF_LDX
|| InstClass
== BPF_STX
) &&
178 getInstSize(Insn
) != BPF_DW
&&
179 (InstMode
== BPF_MEM
|| InstMode
== BPF_ATOMIC
) &&
180 STI
.getFeatureBits()[BPF::ALU32
])
181 Result
= decodeInstruction(DecoderTableBPFALU3264
, Instr
, Insn
, Address
,
184 Result
= decodeInstruction(DecoderTableBPF64
, Instr
, Insn
, Address
, this,
187 if (Result
== MCDisassembler::Fail
) return MCDisassembler::Fail
;
189 switch (Instr
.getOpcode()) {
191 case BPF::LD_pseudo
: {
192 if (Bytes
.size() < 16) {
194 return MCDisassembler::Fail
;
198 Hi
= (Bytes
[12] << 0) | (Bytes
[13] << 8) | (Bytes
[14] << 16) | (Bytes
[15] << 24);
200 Hi
= (Bytes
[12] << 24) | (Bytes
[13] << 16) | (Bytes
[14] << 8) | (Bytes
[15] << 0);
201 auto& Op
= Instr
.getOperand(1);
202 Op
.setImm(Make_64(Hi
, Op
.getImm()));
210 case BPF::LD_IND_W
: {
211 auto Op
= Instr
.getOperand(0);
213 Instr
.addOperand(MCOperand::createReg(BPF::R6
));
214 Instr
.addOperand(Op
);
222 typedef DecodeStatus (*DecodeFunc
)(MCInst
&MI
, unsigned insn
, uint64_t Address
,
223 const void *Decoder
);