Path: blob/main/contrib/llvm-project/llvm/lib/MC/MCDisassembler/Disassembler.cpp
35266 views
//===-- lib/MC/Disassembler.cpp - Disassembler Public C Interface ---------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Disassembler.h"9#include "llvm-c/Disassembler.h"10#include "llvm/ADT/ArrayRef.h"11#include "llvm/ADT/SmallVector.h"12#include "llvm/MC/MCAsmInfo.h"13#include "llvm/MC/MCContext.h"14#include "llvm/MC/MCDisassembler/MCDisassembler.h"15#include "llvm/MC/MCDisassembler/MCRelocationInfo.h"16#include "llvm/MC/MCDisassembler/MCSymbolizer.h"17#include "llvm/MC/MCInst.h"18#include "llvm/MC/MCInstPrinter.h"19#include "llvm/MC/MCInstrDesc.h"20#include "llvm/MC/MCInstrInfo.h"21#include "llvm/MC/MCInstrItineraries.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"31#include <cassert>32#include <cstring>3334using namespace llvm;3536// LLVMCreateDisasm() creates a disassembler for the TripleName. Symbolic37// disassembly is supported by passing a block of information in the DisInfo38// parameter and specifying the TagType and callback functions as described in39// the header llvm-c/Disassembler.h . The pointer to the block and the40// functions can all be passed as NULL. If successful, this returns a41// disassembler context. If not, it returns NULL.42//43LLVMDisasmContextRef44LLVMCreateDisasmCPUFeatures(const char *TT, const char *CPU,45const char *Features, void *DisInfo, int TagType,46LLVMOpInfoCallback GetOpInfo,47LLVMSymbolLookupCallback SymbolLookUp) {48// Get the target.49std::string Error;50const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);51if (!TheTarget)52return nullptr;5354std::unique_ptr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));55if (!MRI)56return nullptr;5758MCTargetOptions MCOptions;59// Get the assembler info needed to setup the MCContext.60std::unique_ptr<const MCAsmInfo> MAI(61TheTarget->createMCAsmInfo(*MRI, TT, MCOptions));62if (!MAI)63return nullptr;6465std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());66if (!MII)67return nullptr;6869std::unique_ptr<const MCSubtargetInfo> STI(70TheTarget->createMCSubtargetInfo(TT, CPU, Features));71if (!STI)72return nullptr;7374// Set up the MCContext for creating symbols and MCExpr's.75std::unique_ptr<MCContext> Ctx(76new MCContext(Triple(TT), MAI.get(), MRI.get(), STI.get()));77if (!Ctx)78return nullptr;7980// Set up disassembler.81std::unique_ptr<MCDisassembler> DisAsm(82TheTarget->createMCDisassembler(*STI, *Ctx));83if (!DisAsm)84return nullptr;8586std::unique_ptr<MCRelocationInfo> RelInfo(87TheTarget->createMCRelocationInfo(TT, *Ctx));88if (!RelInfo)89return nullptr;9091std::unique_ptr<MCSymbolizer> Symbolizer(TheTarget->createMCSymbolizer(92TT, GetOpInfo, SymbolLookUp, DisInfo, Ctx.get(), std::move(RelInfo)));93DisAsm->setSymbolizer(std::move(Symbolizer));9495// Set up the instruction printer.96int AsmPrinterVariant = MAI->getAssemblerDialect();97std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(98Triple(TT), AsmPrinterVariant, *MAI, *MII, *MRI));99if (!IP)100return nullptr;101102LLVMDisasmContext *DC = new LLVMDisasmContext(103TT, DisInfo, TagType, GetOpInfo, SymbolLookUp, TheTarget, std::move(MAI),104std::move(MRI), std::move(STI), std::move(MII), std::move(Ctx),105std::move(DisAsm), std::move(IP));106if (!DC)107return nullptr;108109DC->setCPU(CPU);110return DC;111}112113LLVMDisasmContextRef114LLVMCreateDisasmCPU(const char *TT, const char *CPU, void *DisInfo, int TagType,115LLVMOpInfoCallback GetOpInfo,116LLVMSymbolLookupCallback SymbolLookUp) {117return LLVMCreateDisasmCPUFeatures(TT, CPU, "", DisInfo, TagType, GetOpInfo,118SymbolLookUp);119}120121LLVMDisasmContextRef LLVMCreateDisasm(const char *TT, void *DisInfo,122int TagType, LLVMOpInfoCallback GetOpInfo,123LLVMSymbolLookupCallback SymbolLookUp) {124return LLVMCreateDisasmCPUFeatures(TT, "", "", DisInfo, TagType, GetOpInfo,125SymbolLookUp);126}127128//129// LLVMDisasmDispose() disposes of the disassembler specified by the context.130//131void LLVMDisasmDispose(LLVMDisasmContextRef DCR){132LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);133delete DC;134}135136/// Emits the comments that are stored in \p DC comment stream.137/// Each comment in the comment stream must end with a newline.138static void emitComments(LLVMDisasmContext *DC,139formatted_raw_ostream &FormattedOS) {140// Flush the stream before taking its content.141StringRef Comments = DC->CommentsToEmit.str();142// Get the default information for printing a comment.143const MCAsmInfo *MAI = DC->getAsmInfo();144StringRef CommentBegin = MAI->getCommentString();145unsigned CommentColumn = MAI->getCommentColumn();146bool IsFirst = true;147while (!Comments.empty()) {148if (!IsFirst)149FormattedOS << '\n';150// Emit a line of comments.151FormattedOS.PadToColumn(CommentColumn);152size_t Position = Comments.find('\n');153FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position);154// Move after the newline character.155Comments = Comments.substr(Position+1);156IsFirst = false;157}158FormattedOS.flush();159160// Tell the comment stream that the vector changed underneath it.161DC->CommentsToEmit.clear();162}163164/// Gets latency information for \p Inst from the itinerary165/// scheduling model, based on \p DC information.166/// \return The maximum expected latency over all the operands or -1167/// if no information is available.168static int getItineraryLatency(LLVMDisasmContext *DC, const MCInst &Inst) {169const int NoInformationAvailable = -1;170171// Check if we have a CPU to get the itinerary information.172if (DC->getCPU().empty())173return NoInformationAvailable;174175// Get itinerary information.176const MCSubtargetInfo *STI = DC->getSubtargetInfo();177InstrItineraryData IID = STI->getInstrItineraryForCPU(DC->getCPU());178// Get the scheduling class of the requested instruction.179const MCInstrDesc& Desc = DC->getInstrInfo()->get(Inst.getOpcode());180unsigned SCClass = Desc.getSchedClass();181182unsigned Latency = 0;183184for (unsigned Idx = 0, IdxEnd = Inst.getNumOperands(); Idx != IdxEnd; ++Idx)185if (std::optional<unsigned> OperCycle = IID.getOperandCycle(SCClass, Idx))186Latency = std::max(Latency, *OperCycle);187188return (int)Latency;189}190191/// Gets latency information for \p Inst, based on \p DC information.192/// \return The maximum expected latency over all the definitions or -1193/// if no information is available.194static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) {195// Try to compute scheduling information.196const MCSubtargetInfo *STI = DC->getSubtargetInfo();197const MCSchedModel SCModel = STI->getSchedModel();198const int NoInformationAvailable = -1;199200// Check if we have a scheduling model for instructions.201if (!SCModel.hasInstrSchedModel())202// Try to fall back to the itinerary model if the scheduling model doesn't203// have a scheduling table. Note the default does not have a table.204return getItineraryLatency(DC, Inst);205206// Get the scheduling class of the requested instruction.207const MCInstrDesc& Desc = DC->getInstrInfo()->get(Inst.getOpcode());208unsigned SCClass = Desc.getSchedClass();209const MCSchedClassDesc *SCDesc = SCModel.getSchedClassDesc(SCClass);210// Resolving the variant SchedClass requires an MI to pass to211// SubTargetInfo::resolveSchedClass.212if (!SCDesc || !SCDesc->isValid() || SCDesc->isVariant())213return NoInformationAvailable;214215// Compute output latency.216int16_t Latency = 0;217for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries;218DefIdx != DefEnd; ++DefIdx) {219// Lookup the definition's write latency in SubtargetInfo.220const MCWriteLatencyEntry *WLEntry = STI->getWriteLatencyEntry(SCDesc,221DefIdx);222Latency = std::max(Latency, WLEntry->Cycles);223}224225return Latency;226}227228/// Emits latency information in DC->CommentStream for \p Inst, based229/// on the information available in \p DC.230static void emitLatency(LLVMDisasmContext *DC, const MCInst &Inst) {231int Latency = getLatency(DC, Inst);232233// Report only interesting latencies.234if (Latency < 2)235return;236237DC->CommentStream << "Latency: " << Latency << '\n';238}239240//241// LLVMDisasmInstruction() disassembles a single instruction using the242// disassembler context specified in the parameter DC. The bytes of the243// instruction are specified in the parameter Bytes, and contains at least244// BytesSize number of bytes. The instruction is at the address specified by245// the PC parameter. If a valid instruction can be disassembled its string is246// returned indirectly in OutString which whos size is specified in the247// parameter OutStringSize. This function returns the number of bytes in the248// instruction or zero if there was no valid instruction. If this function249// returns zero the caller will have to pick how many bytes they want to step250// over by printing a .byte, .long etc. to continue.251//252size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR, uint8_t *Bytes,253uint64_t BytesSize, uint64_t PC, char *OutString,254size_t OutStringSize){255LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);256// Wrap the pointer to the Bytes, BytesSize and PC in a MemoryObject.257ArrayRef<uint8_t> Data(Bytes, BytesSize);258259uint64_t Size;260MCInst Inst;261const MCDisassembler *DisAsm = DC->getDisAsm();262MCInstPrinter *IP = DC->getIP();263MCDisassembler::DecodeStatus S;264SmallVector<char, 64> InsnStr;265raw_svector_ostream Annotations(InsnStr);266S = DisAsm->getInstruction(Inst, Size, Data, PC, Annotations);267switch (S) {268case MCDisassembler::Fail:269case MCDisassembler::SoftFail:270// FIXME: Do something different for soft failure modes?271return 0;272273case MCDisassembler::Success: {274StringRef AnnotationsStr = Annotations.str();275276SmallVector<char, 64> InsnStr;277raw_svector_ostream OS(InsnStr);278formatted_raw_ostream FormattedOS(OS);279IP->printInst(&Inst, PC, AnnotationsStr, *DC->getSubtargetInfo(),280FormattedOS);281282if (DC->getOptions() & LLVMDisassembler_Option_PrintLatency)283emitLatency(DC, Inst);284285emitComments(DC, FormattedOS);286287assert(OutStringSize != 0 && "Output buffer cannot be zero size");288size_t OutputSize = std::min(OutStringSize-1, InsnStr.size());289std::memcpy(OutString, InsnStr.data(), OutputSize);290OutString[OutputSize] = '\0'; // Terminate string.291292return Size;293}294}295llvm_unreachable("Invalid DecodeStatus!");296}297298//299// LLVMSetDisasmOptions() sets the disassembler's options. It returns 1 if it300// can set all the Options and 0 otherwise.301//302int LLVMSetDisasmOptions(LLVMDisasmContextRef DCR, uint64_t Options){303if (Options & LLVMDisassembler_Option_UseMarkup){304LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);305MCInstPrinter *IP = DC->getIP();306IP->setUseMarkup(true);307DC->addOptions(LLVMDisassembler_Option_UseMarkup);308Options &= ~LLVMDisassembler_Option_UseMarkup;309}310if (Options & LLVMDisassembler_Option_PrintImmHex){311LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);312MCInstPrinter *IP = DC->getIP();313IP->setPrintImmHex(true);314DC->addOptions(LLVMDisassembler_Option_PrintImmHex);315Options &= ~LLVMDisassembler_Option_PrintImmHex;316}317if (Options & LLVMDisassembler_Option_AsmPrinterVariant){318LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);319// Try to set up the new instruction printer.320const MCAsmInfo *MAI = DC->getAsmInfo();321const MCInstrInfo *MII = DC->getInstrInfo();322const MCRegisterInfo *MRI = DC->getRegisterInfo();323int AsmPrinterVariant = MAI->getAssemblerDialect();324AsmPrinterVariant = AsmPrinterVariant == 0 ? 1 : 0;325MCInstPrinter *IP = DC->getTarget()->createMCInstPrinter(326Triple(DC->getTripleName()), AsmPrinterVariant, *MAI, *MII, *MRI);327if (IP) {328DC->setIP(IP);329DC->addOptions(LLVMDisassembler_Option_AsmPrinterVariant);330Options &= ~LLVMDisassembler_Option_AsmPrinterVariant;331}332}333if (Options & LLVMDisassembler_Option_SetInstrComments) {334LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);335MCInstPrinter *IP = DC->getIP();336IP->setCommentStream(DC->CommentStream);337DC->addOptions(LLVMDisassembler_Option_SetInstrComments);338Options &= ~LLVMDisassembler_Option_SetInstrComments;339}340if (Options & LLVMDisassembler_Option_PrintLatency) {341LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);342DC->addOptions(LLVMDisassembler_Option_PrintLatency);343Options &= ~LLVMDisassembler_Option_PrintLatency;344}345return (Options == 0);346}347348349