brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.5 KiB · 0bc5a06 Raw
246 lines · cpp
1//===- bolt/Passes/AsmDump.cpp - Dump BinaryFunction into assembly --------===//2//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the AsmDumpPass class.10//11//===----------------------------------------------------------------------===//12 13#include "bolt/Passes/AsmDump.h"14#include "llvm/CodeGen/AsmPrinter.h"15#include "llvm/MC/TargetRegistry.h"16#include "llvm/Support/FileSystem.h"17#include "llvm/Support/Path.h"18#include "llvm/Target/TargetMachine.h"19#include <unordered_set>20 21#define DEBUG_TYPE "asm-dump"22 23using namespace llvm;24 25namespace opts {26extern bool shouldPrint(const bolt::BinaryFunction &Function);27extern cl::OptionCategory BoltCategory;28extern cl::opt<unsigned> Verbosity;29 30cl::opt<std::string> AsmDump("asm-dump",31                             cl::desc("dump function into assembly"),32                             cl::value_desc("dump folder"), cl::ValueOptional,33                             cl::Hidden, cl::cat(BoltCategory));34} // end namespace opts35 36namespace llvm {37namespace bolt {38 39void dumpCFI(const BinaryFunction &BF, const MCInst &Instr, AsmPrinter &MAP) {40  const MCCFIInstruction *CFIInstr = BF.getCFIFor(Instr);41  switch (CFIInstr->getOperation()) {42  // Skip unsupported CFI instructions.43  case MCCFIInstruction::OpRememberState:44  case MCCFIInstruction::OpRestoreState:45    if (opts::Verbosity >= 2)46      BF.getBinaryContext().errs()47          << "BOLT-WARNING: AsmDump: skipping unsupported CFI instruction in "48          << BF << ".\n";49 50    return;51 52  default:53    // Emit regular CFI instructions.54    MAP.emitCFIInstruction(*CFIInstr);55  }56}57 58void dumpTargetFunctionStub(raw_ostream &OS, const BinaryContext &BC,59                            const MCSymbol *CalleeSymb,60                            const BinarySection *&LastCS) {61  const BinaryFunction *CalleeFunc = BC.getFunctionForSymbol(CalleeSymb);62  if (!CalleeFunc || CalleeFunc->isPLTFunction())63    return;64 65  if (CalleeFunc->getOriginSection() != LastCS) {66    OS << ".section " << CalleeFunc->getOriginSectionName() << '\n';67    LastCS = CalleeFunc->getOriginSection();68  }69  StringRef CalleeName = CalleeFunc->getOneName();70  OS << ".set \"" << CalleeName << "\", 0\n";71}72 73void dumpJumpTableSymbols(raw_ostream &OS, const JumpTable *JT, AsmPrinter &MAP,74                          const BinarySection *&LastBS) {75  if (&JT->getSection() != LastBS) {76    OS << ".section " << JT->getSectionName() << '\n';77    LastBS = &JT->getSection();78  }79  OS << "\"" << JT->getName() << "\":\n";80  for (MCSymbol *JTEntry : JT->Entries)81    MAP.OutStreamer->emitSymbolValue(JTEntry, JT->OutputEntrySize);82  OS << '\n';83}84 85void dumpBinaryDataSymbols(raw_ostream &OS, const BinaryData *BD,86                           const BinarySection *&LastBS) {87  if (BD->isJumpTable())88    return;89  if (&BD->getSection() != LastBS) {90    OS << ".section " << BD->getSectionName() << '\n';91    LastBS = &BD->getSection();92  }93  OS << "\"" << BD->getName() << "\": ";94  OS << '\n';95}96 97void dumpFunction(const BinaryFunction &BF) {98  const BinaryContext &BC = BF.getBinaryContext();99  if (!opts::shouldPrint(BF))100    return;101 102  // Make sure the new directory exists, creating it if necessary.103  if (!opts::AsmDump.empty()) {104    if (std::error_code EC = sys::fs::create_directories(opts::AsmDump)) {105      BC.errs() << "BOLT-ERROR: could not create directory '" << opts::AsmDump106                << "': " << EC.message() << '\n';107      return;108    }109  }110 111  std::string PrintName = BF.getPrintName();112  llvm::replace(PrintName, '/', '-');113  std::string Filename =114      opts::AsmDump.empty()115          ? (PrintName + ".s")116          : (opts::AsmDump + sys::path::get_separator() + PrintName + ".s")117                .str();118  BC.outs() << "BOLT-INFO: Dumping function assembly to " << Filename << "\n";119 120  std::error_code EC;121  raw_fd_ostream OS(Filename, EC, sys::fs::OF_None);122  if (EC) {123    BC.errs() << "BOLT-ERROR: " << EC.message() << ", unable to open "124              << Filename << " for output.\n";125    return;126  }127  OS.SetUnbuffered();128 129  // Create local MC context to isolate the effect of ephemeral assembly130  // emission.131  BinaryContext::IndependentCodeEmitter MCEInstance =132      BC.createIndependentMCCodeEmitter();133  MCContext *LocalCtx = MCEInstance.LocalCtx.get();134  std::unique_ptr<MCAsmBackend> MAB(135      BC.TheTarget->createMCAsmBackend(*BC.STI, *BC.MRI, MCTargetOptions()));136  int AsmPrinterVariant = BC.AsmInfo->getAssemblerDialect();137  std::unique_ptr<MCInstPrinter> InstructionPrinter(138      BC.TheTarget->createMCInstPrinter(*BC.TheTriple, AsmPrinterVariant,139                                        *BC.AsmInfo, *BC.MII, *BC.MRI));140  auto FOut = std::make_unique<formatted_raw_ostream>(OS);141  FOut->SetUnbuffered();142  std::unique_ptr<MCStreamer> AsmStreamer(createAsmStreamer(143      *LocalCtx, std::move(FOut), std::move(InstructionPrinter),144      std::move(MCEInstance.MCE), std::move(MAB)));145  AsmStreamer->initSections(true, *BC.STI);146  std::unique_ptr<TargetMachine> TM(BC.TheTarget->createTargetMachine(147      *BC.TheTriple, "", "", TargetOptions(), std::nullopt));148  std::unique_ptr<AsmPrinter> MAP(149      BC.TheTarget->createAsmPrinter(*TM, std::move(AsmStreamer)));150 151  StringRef FunctionName = BF.getOneName();152  OS << "  .globl " << FunctionName << '\n';153  OS << "  .type " << FunctionName << ", %function\n";154  OS << FunctionName << ":\n";155 156  // FDATA for the entry point157  if (uint64_t EntryExecCount = BF.getKnownExecutionCount())158    OS << "# FDATA: 0 [unknown] 0 "159       << "1 " << FunctionName << " 0 "160       << "0 " << EntryExecCount << '\n';161 162  // Binary data references from the function.163  std::unordered_set<const BinaryData *> BDReferences;164  // Function references from the function (to avoid constructing call graph).165  std::unordered_set<const MCSymbol *> CallReferences;166 167  MAP->OutStreamer->emitCFIStartProc(/*IsSimple=*/false);168  for (const BinaryBasicBlock *BB : BF.getLayout().blocks()) {169    OS << BB->getName() << ": \n";170 171    const std::string BranchLabel = Twine(BB->getName(), "_br").str();172    const MCInst *LastInst = BB->getLastNonPseudoInstr();173 174    for (const MCInst &Instr : *BB) {175      // Dump pseudo instructions (CFI)176      if (BC.MIB->isPseudo(Instr)) {177        if (BC.MIB->isCFI(Instr))178          dumpCFI(BF, Instr, *MAP);179        continue;180      }181 182      // Analyze symbol references (data, functions) from the instruction.183      bool IsCall = BC.MIB->isCall(Instr);184      for (const MCOperand &Operand : MCPlus::primeOperands(Instr)) {185        if (Operand.isExpr() &&186            Operand.getExpr()->getKind() == MCExpr::SymbolRef) {187          std::pair<const MCSymbol *, uint64_t> TSI =188              BC.MIB->getTargetSymbolInfo(Operand.getExpr());189          const MCSymbol *Symbol = TSI.first;190          if (IsCall)191            CallReferences.insert(Symbol);192          else if (const BinaryData *BD =193                       BC.getBinaryDataByName(Symbol->getName()))194            BDReferences.insert(BD);195        }196      }197 198      if (&Instr == LastInst && (BB->succ_size() || IsCall))199        OS << BranchLabel << ":\n";200 201      BC.InstPrinter->printInst(&Instr, 0, "", *BC.STI, OS);202      OS << '\n';203    }204 205    // Dump profile data in FDATA format (as parsed by link_fdata).206    for (const BinaryBasicBlock *Succ : BB->successors()) {207      const BinaryBasicBlock::BinaryBranchInfo BI = BB->getBranchInfo(*Succ);208      if (!BI.MispredictedCount && !BI.Count)209        continue;210 211      OS << "# FDATA: 1 " << FunctionName << " #" << BranchLabel << "# "212         << "1 " << FunctionName << " #" << Succ->getName() << "# "213         << BI.MispredictedCount << " " << BI.Count << '\n';214    }215 216    OS << '\n';217  }218  MAP->OutStreamer->emitCFIEndProc();219 220  OS << ".size " << FunctionName << ", .-" << FunctionName << '\n';221 222  const BinarySection *LastSection = BF.getOriginSection();223  // Print stubs for all target functions.224  for (const MCSymbol *CalleeSymb : CallReferences)225    dumpTargetFunctionStub(OS, BC, CalleeSymb, LastSection);226 227  OS << "# Jump tables\n";228  // Print all jump tables.229  for (auto &JTI : BF.jumpTables())230    dumpJumpTableSymbols(OS, JTI.second, *MAP, LastSection);231 232  OS << "# BinaryData\n";233  // Print data references.234  for (const BinaryData *BD : BDReferences)235    dumpBinaryDataSymbols(OS, BD, LastSection);236}237 238Error AsmDumpPass::runOnFunctions(BinaryContext &BC) {239  for (const auto &BFIt : BC.getBinaryFunctions())240    dumpFunction(BFIt.second);241  return Error::success();242}243 244} // namespace bolt245} // namespace llvm246