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
,
71 raw_ostream
&CStream
) const override
;
73 uint8_t getInstClass(uint64_t Inst
) const { return (Inst
>> 56) & 0x7; };
74 uint8_t getInstSize(uint64_t Inst
) const { return (Inst
>> 59) & 0x3; };
75 uint8_t getInstMode(uint64_t Inst
) const { return (Inst
>> 61) & 0x7; };
78 } // end anonymous namespace
80 static MCDisassembler
*createBPFDisassembler(const Target
&T
,
81 const MCSubtargetInfo
&STI
,
83 return new BPFDisassembler(STI
, Ctx
);
87 extern "C" void LLVMInitializeBPFDisassembler() {
88 // Register the disassembler.
89 TargetRegistry::RegisterMCDisassembler(getTheBPFTarget(),
90 createBPFDisassembler
);
91 TargetRegistry::RegisterMCDisassembler(getTheBPFleTarget(),
92 createBPFDisassembler
);
93 TargetRegistry::RegisterMCDisassembler(getTheBPFbeTarget(),
94 createBPFDisassembler
);
97 static const unsigned GPRDecoderTable
[] = {
98 BPF::R0
, BPF::R1
, BPF::R2
, BPF::R3
, BPF::R4
, BPF::R5
,
99 BPF::R6
, BPF::R7
, BPF::R8
, BPF::R9
, BPF::R10
, BPF::R11
};
101 static DecodeStatus
DecodeGPRRegisterClass(MCInst
&Inst
, unsigned RegNo
,
102 uint64_t /*Address*/,
103 const void * /*Decoder*/) {
105 return MCDisassembler::Fail
;
107 unsigned Reg
= GPRDecoderTable
[RegNo
];
108 Inst
.addOperand(MCOperand::createReg(Reg
));
109 return MCDisassembler::Success
;
112 static const unsigned GPR32DecoderTable
[] = {
113 BPF::W0
, BPF::W1
, BPF::W2
, BPF::W3
, BPF::W4
, BPF::W5
,
114 BPF::W6
, BPF::W7
, BPF::W8
, BPF::W9
, BPF::W10
, BPF::W11
};
116 static DecodeStatus
DecodeGPR32RegisterClass(MCInst
&Inst
, unsigned RegNo
,
117 uint64_t /*Address*/,
118 const void * /*Decoder*/) {
120 return MCDisassembler::Fail
;
122 unsigned Reg
= GPR32DecoderTable
[RegNo
];
123 Inst
.addOperand(MCOperand::createReg(Reg
));
124 return MCDisassembler::Success
;
127 static DecodeStatus
decodeMemoryOpValue(MCInst
&Inst
, unsigned Insn
,
128 uint64_t Address
, const void *Decoder
) {
129 unsigned Register
= (Insn
>> 16) & 0xf;
130 Inst
.addOperand(MCOperand::createReg(GPRDecoderTable
[Register
]));
131 unsigned Offset
= (Insn
& 0xffff);
132 Inst
.addOperand(MCOperand::createImm(SignExtend32
<16>(Offset
)));
134 return MCDisassembler::Success
;
137 #include "BPFGenDisassemblerTables.inc"
138 static DecodeStatus
readInstruction64(ArrayRef
<uint8_t> Bytes
, uint64_t Address
,
139 uint64_t &Size
, uint64_t &Insn
,
140 bool IsLittleEndian
) {
143 if (Bytes
.size() < 8) {
145 return MCDisassembler::Fail
;
149 if (IsLittleEndian
) {
150 Hi
= (Bytes
[0] << 24) | (Bytes
[1] << 16) | (Bytes
[2] << 0) | (Bytes
[3] << 8);
151 Lo
= (Bytes
[4] << 0) | (Bytes
[5] << 8) | (Bytes
[6] << 16) | (Bytes
[7] << 24);
153 Hi
= (Bytes
[0] << 24) | ((Bytes
[1] & 0x0F) << 20) | ((Bytes
[1] & 0xF0) << 12) |
154 (Bytes
[2] << 8) | (Bytes
[3] << 0);
155 Lo
= (Bytes
[4] << 24) | (Bytes
[5] << 16) | (Bytes
[6] << 8) | (Bytes
[7] << 0);
157 Insn
= Make_64(Hi
, Lo
);
159 return MCDisassembler::Success
;
162 DecodeStatus
BPFDisassembler::getInstruction(MCInst
&Instr
, uint64_t &Size
,
163 ArrayRef
<uint8_t> Bytes
,
165 raw_ostream
&VStream
,
166 raw_ostream
&CStream
) const {
167 bool IsLittleEndian
= getContext().getAsmInfo()->isLittleEndian();
171 Result
= readInstruction64(Bytes
, Address
, Size
, Insn
, IsLittleEndian
);
172 if (Result
== MCDisassembler::Fail
) return MCDisassembler::Fail
;
174 uint8_t InstClass
= getInstClass(Insn
);
175 uint8_t InstMode
= getInstMode(Insn
);
176 if ((InstClass
== BPF_LDX
|| InstClass
== BPF_STX
) &&
177 getInstSize(Insn
) != BPF_DW
&&
178 (InstMode
== BPF_MEM
|| InstMode
== BPF_XADD
) &&
179 STI
.getFeatureBits()[BPF::ALU32
])
180 Result
= decodeInstruction(DecoderTableBPFALU3264
, Instr
, Insn
, Address
,
183 Result
= decodeInstruction(DecoderTableBPF64
, Instr
, Insn
, Address
, this,
186 if (Result
== MCDisassembler::Fail
) return MCDisassembler::Fail
;
188 switch (Instr
.getOpcode()) {
190 case BPF::LD_pseudo
: {
191 if (Bytes
.size() < 16) {
193 return MCDisassembler::Fail
;
197 Hi
= (Bytes
[12] << 0) | (Bytes
[13] << 8) | (Bytes
[14] << 16) | (Bytes
[15] << 24);
199 Hi
= (Bytes
[12] << 24) | (Bytes
[13] << 16) | (Bytes
[14] << 8) | (Bytes
[15] << 0);
200 auto& Op
= Instr
.getOperand(1);
201 Op
.setImm(Make_64(Hi
, Op
.getImm()));
209 case BPF::LD_IND_W
: {
210 auto Op
= Instr
.getOperand(0);
212 Instr
.addOperand(MCOperand::createReg(BPF::R6
));
213 Instr
.addOperand(Op
);
221 typedef DecodeStatus (*DecodeFunc
)(MCInst
&MI
, unsigned insn
, uint64_t Address
,
222 const void *Decoder
);