1 //===-- lib/MC/Disassembler.cpp - Disassembler Public C Interface ---------===//
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 #include "Disassembler.h"
10 #include "llvm-c/Disassembler.h"
11 #include "llvm/ADT/ArrayRef.h"
12 #include "llvm/ADT/SmallVector.h"
13 #include "llvm/MC/MCAsmInfo.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
16 #include "llvm/MC/MCDisassembler/MCRelocationInfo.h"
17 #include "llvm/MC/MCDisassembler/MCSymbolizer.h"
18 #include "llvm/MC/MCInst.h"
19 #include "llvm/MC/MCInstPrinter.h"
20 #include "llvm/MC/MCInstrDesc.h"
21 #include "llvm/MC/MCInstrInfo.h"
22 #include "llvm/MC/MCRegisterInfo.h"
23 #include "llvm/MC/MCSchedule.h"
24 #include "llvm/MC/MCSubtargetInfo.h"
25 #include "llvm/MC/MCTargetOptions.h"
26 #include "llvm/MC/TargetRegistry.h"
27 #include "llvm/Support/ErrorHandling.h"
28 #include "llvm/Support/FormattedStream.h"
29 #include "llvm/Support/raw_ostream.h"
30 #include "llvm/TargetParser/Triple.h"
36 // LLVMCreateDisasm() creates a disassembler for the TripleName. Symbolic
37 // disassembly is supported by passing a block of information in the DisInfo
38 // parameter and specifying the TagType and callback functions as described in
39 // the header llvm-c/Disassembler.h . The pointer to the block and the
40 // functions can all be passed as NULL. If successful, this returns a
41 // disassembler context. If not, it returns NULL.
44 LLVMCreateDisasmCPUFeatures(const char *TT
, const char *CPU
,
45 const char *Features
, void *DisInfo
, int TagType
,
46 LLVMOpInfoCallback GetOpInfo
,
47 LLVMSymbolLookupCallback SymbolLookUp
) {
50 const Target
*TheTarget
= TargetRegistry::lookupTarget(TT
, Error
);
54 std::unique_ptr
<const MCRegisterInfo
> MRI(TheTarget
->createMCRegInfo(TT
));
58 MCTargetOptions MCOptions
;
59 // Get the assembler info needed to setup the MCContext.
60 std::unique_ptr
<const MCAsmInfo
> MAI(
61 TheTarget
->createMCAsmInfo(*MRI
, TT
, MCOptions
));
65 std::unique_ptr
<const MCInstrInfo
> MII(TheTarget
->createMCInstrInfo());
69 std::unique_ptr
<const MCSubtargetInfo
> STI(
70 TheTarget
->createMCSubtargetInfo(TT
, CPU
, Features
));
74 // Set up the MCContext for creating symbols and MCExpr's.
75 std::unique_ptr
<MCContext
> Ctx(
76 new MCContext(Triple(TT
), MAI
.get(), MRI
.get(), STI
.get()));
80 // Set up disassembler.
81 std::unique_ptr
<MCDisassembler
> DisAsm(
82 TheTarget
->createMCDisassembler(*STI
, *Ctx
));
86 std::unique_ptr
<MCRelocationInfo
> RelInfo(
87 TheTarget
->createMCRelocationInfo(TT
, *Ctx
));
91 std::unique_ptr
<MCSymbolizer
> Symbolizer(TheTarget
->createMCSymbolizer(
92 TT
, GetOpInfo
, SymbolLookUp
, DisInfo
, Ctx
.get(), std::move(RelInfo
)));
93 DisAsm
->setSymbolizer(std::move(Symbolizer
));
95 // Set up the instruction printer.
96 int AsmPrinterVariant
= MAI
->getAssemblerDialect();
97 std::unique_ptr
<MCInstPrinter
> IP(TheTarget
->createMCInstPrinter(
98 Triple(TT
), AsmPrinterVariant
, *MAI
, *MII
, *MRI
));
102 LLVMDisasmContext
*DC
= new LLVMDisasmContext(
103 TT
, DisInfo
, TagType
, GetOpInfo
, SymbolLookUp
, TheTarget
, std::move(MAI
),
104 std::move(MRI
), std::move(STI
), std::move(MII
), std::move(Ctx
),
105 std::move(DisAsm
), std::move(IP
));
114 LLVMCreateDisasmCPU(const char *TT
, const char *CPU
, void *DisInfo
, int TagType
,
115 LLVMOpInfoCallback GetOpInfo
,
116 LLVMSymbolLookupCallback SymbolLookUp
) {
117 return LLVMCreateDisasmCPUFeatures(TT
, CPU
, "", DisInfo
, TagType
, GetOpInfo
,
121 LLVMDisasmContextRef
LLVMCreateDisasm(const char *TT
, void *DisInfo
,
122 int TagType
, LLVMOpInfoCallback GetOpInfo
,
123 LLVMSymbolLookupCallback SymbolLookUp
) {
124 return LLVMCreateDisasmCPUFeatures(TT
, "", "", DisInfo
, TagType
, GetOpInfo
,
129 // LLVMDisasmDispose() disposes of the disassembler specified by the context.
131 void LLVMDisasmDispose(LLVMDisasmContextRef DCR
){
132 LLVMDisasmContext
*DC
= static_cast<LLVMDisasmContext
*>(DCR
);
136 /// Emits the comments that are stored in \p DC comment stream.
137 /// Each comment in the comment stream must end with a newline.
138 static void emitComments(LLVMDisasmContext
*DC
,
139 formatted_raw_ostream
&FormattedOS
) {
140 // Flush the stream before taking its content.
141 StringRef Comments
= DC
->CommentsToEmit
.str();
142 // Get the default information for printing a comment.
143 const MCAsmInfo
*MAI
= DC
->getAsmInfo();
144 StringRef CommentBegin
= MAI
->getCommentString();
145 unsigned CommentColumn
= MAI
->getCommentColumn();
147 while (!Comments
.empty()) {
150 // Emit a line of comments.
151 FormattedOS
.PadToColumn(CommentColumn
);
152 size_t Position
= Comments
.find('\n');
153 FormattedOS
<< CommentBegin
<< ' ' << Comments
.substr(0, Position
);
154 // Move after the newline character.
155 Comments
= Comments
.substr(Position
+1);
160 // Tell the comment stream that the vector changed underneath it.
161 DC
->CommentsToEmit
.clear();
164 /// Emits latency information in DC->CommentStream for \p Inst, based
165 /// on the information available in \p DC.
166 static void emitLatency(LLVMDisasmContext
*DC
, const MCInst
&Inst
) {
167 const MCSubtargetInfo
*STI
= DC
->getSubtargetInfo();
168 const MCInstrInfo
*MCII
= DC
->getInstrInfo();
169 const MCSchedModel
&SCModel
= STI
->getSchedModel();
170 int Latency
= SCModel
.computeInstrLatency(*STI
, *MCII
, Inst
);
172 // Report only interesting latencies.
176 DC
->CommentStream
<< "Latency: " << Latency
<< '\n';
180 // LLVMDisasmInstruction() disassembles a single instruction using the
181 // disassembler context specified in the parameter DC. The bytes of the
182 // instruction are specified in the parameter Bytes, and contains at least
183 // BytesSize number of bytes. The instruction is at the address specified by
184 // the PC parameter. If a valid instruction can be disassembled its string is
185 // returned indirectly in OutString which whos size is specified in the
186 // parameter OutStringSize. This function returns the number of bytes in the
187 // instruction or zero if there was no valid instruction. If this function
188 // returns zero the caller will have to pick how many bytes they want to step
189 // over by printing a .byte, .long etc. to continue.
191 size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR
, uint8_t *Bytes
,
192 uint64_t BytesSize
, uint64_t PC
, char *OutString
,
193 size_t OutStringSize
){
194 LLVMDisasmContext
*DC
= static_cast<LLVMDisasmContext
*>(DCR
);
195 // Wrap the pointer to the Bytes, BytesSize and PC in a MemoryObject.
196 ArrayRef
<uint8_t> Data(Bytes
, BytesSize
);
200 const MCDisassembler
*DisAsm
= DC
->getDisAsm();
201 MCInstPrinter
*IP
= DC
->getIP();
202 MCDisassembler::DecodeStatus S
;
203 SmallVector
<char, 64> InsnStr
;
204 raw_svector_ostream
Annotations(InsnStr
);
205 S
= DisAsm
->getInstruction(Inst
, Size
, Data
, PC
, Annotations
);
207 case MCDisassembler::Fail
:
208 case MCDisassembler::SoftFail
:
209 // FIXME: Do something different for soft failure modes?
212 case MCDisassembler::Success
: {
213 StringRef AnnotationsStr
= Annotations
.str();
215 SmallVector
<char, 64> InsnStr
;
216 raw_svector_ostream
OS(InsnStr
);
217 formatted_raw_ostream
FormattedOS(OS
);
219 if (DC
->getOptions() & LLVMDisassembler_Option_Color
) {
220 FormattedOS
.enable_colors(true);
221 IP
->setUseColor(true);
224 IP
->printInst(&Inst
, PC
, AnnotationsStr
, *DC
->getSubtargetInfo(),
227 if (DC
->getOptions() & LLVMDisassembler_Option_PrintLatency
)
228 emitLatency(DC
, Inst
);
230 emitComments(DC
, FormattedOS
);
232 assert(OutStringSize
!= 0 && "Output buffer cannot be zero size");
233 size_t OutputSize
= std::min(OutStringSize
-1, InsnStr
.size());
234 std::memcpy(OutString
, InsnStr
.data(), OutputSize
);
235 OutString
[OutputSize
] = '\0'; // Terminate string.
240 llvm_unreachable("Invalid DecodeStatus!");
244 // LLVMSetDisasmOptions() sets the disassembler's options. It returns 1 if it
245 // can set all the Options and 0 otherwise.
247 int LLVMSetDisasmOptions(LLVMDisasmContextRef DCR
, uint64_t Options
){
248 if (Options
& LLVMDisassembler_Option_UseMarkup
){
249 LLVMDisasmContext
*DC
= static_cast<LLVMDisasmContext
*>(DCR
);
250 MCInstPrinter
*IP
= DC
->getIP();
251 IP
->setUseMarkup(true);
252 DC
->addOptions(LLVMDisassembler_Option_UseMarkup
);
253 Options
&= ~LLVMDisassembler_Option_UseMarkup
;
255 if (Options
& LLVMDisassembler_Option_PrintImmHex
){
256 LLVMDisasmContext
*DC
= static_cast<LLVMDisasmContext
*>(DCR
);
257 MCInstPrinter
*IP
= DC
->getIP();
258 IP
->setPrintImmHex(true);
259 DC
->addOptions(LLVMDisassembler_Option_PrintImmHex
);
260 Options
&= ~LLVMDisassembler_Option_PrintImmHex
;
262 if (Options
& LLVMDisassembler_Option_AsmPrinterVariant
){
263 LLVMDisasmContext
*DC
= static_cast<LLVMDisasmContext
*>(DCR
);
264 // Try to set up the new instruction printer.
265 const MCAsmInfo
*MAI
= DC
->getAsmInfo();
266 const MCInstrInfo
*MII
= DC
->getInstrInfo();
267 const MCRegisterInfo
*MRI
= DC
->getRegisterInfo();
268 int AsmPrinterVariant
= MAI
->getAssemblerDialect();
269 AsmPrinterVariant
= AsmPrinterVariant
== 0 ? 1 : 0;
270 MCInstPrinter
*IP
= DC
->getTarget()->createMCInstPrinter(
271 Triple(DC
->getTripleName()), AsmPrinterVariant
, *MAI
, *MII
, *MRI
);
274 DC
->addOptions(LLVMDisassembler_Option_AsmPrinterVariant
);
275 Options
&= ~LLVMDisassembler_Option_AsmPrinterVariant
;
278 if (Options
& LLVMDisassembler_Option_SetInstrComments
) {
279 LLVMDisasmContext
*DC
= static_cast<LLVMDisasmContext
*>(DCR
);
280 MCInstPrinter
*IP
= DC
->getIP();
281 IP
->setCommentStream(DC
->CommentStream
);
282 DC
->addOptions(LLVMDisassembler_Option_SetInstrComments
);
283 Options
&= ~LLVMDisassembler_Option_SetInstrComments
;
285 if (Options
& LLVMDisassembler_Option_PrintLatency
) {
286 LLVMDisasmContext
*DC
= static_cast<LLVMDisasmContext
*>(DCR
);
287 DC
->addOptions(LLVMDisassembler_Option_PrintLatency
);
288 Options
&= ~LLVMDisassembler_Option_PrintLatency
;
290 if (Options
& LLVMDisassembler_Option_Color
) {
291 LLVMDisasmContext
*DC
= static_cast<LLVMDisasmContext
*>(DCR
);
292 DC
->addOptions(LLVMDisassembler_Option_Color
);
293 Options
&= ~LLVMDisassembler_Option_Color
;
295 return (Options
== 0);