17a7e6055SDimitry Andric //===- FaultMaps.cpp ------------------------------------------------------===//
28f0fd8f6SDimitry Andric //
38f0fd8f6SDimitry Andric //                     The LLVM Compiler Infrastructure
48f0fd8f6SDimitry Andric //
58f0fd8f6SDimitry Andric // This file is distributed under the University of Illinois Open Source
68f0fd8f6SDimitry Andric // License. See LICENSE.TXT for details.
78f0fd8f6SDimitry Andric //
88f0fd8f6SDimitry Andric //===----------------------------------------------------------------------===//
98f0fd8f6SDimitry Andric 
10db17bf38SDimitry Andric #include "llvm/CodeGen/FaultMaps.h"
117a7e6055SDimitry Andric #include "llvm/ADT/Twine.h"
128f0fd8f6SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
138f0fd8f6SDimitry Andric #include "llvm/MC/MCContext.h"
148f0fd8f6SDimitry Andric #include "llvm/MC/MCExpr.h"
158f0fd8f6SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h"
168f0fd8f6SDimitry Andric #include "llvm/MC/MCStreamer.h"
178f0fd8f6SDimitry Andric #include "llvm/Support/Debug.h"
187a7e6055SDimitry Andric #include "llvm/Support/ErrorHandling.h"
197a7e6055SDimitry Andric #include "llvm/Support/Format.h"
207a7e6055SDimitry Andric #include "llvm/Support/raw_ostream.h"
218f0fd8f6SDimitry Andric 
228f0fd8f6SDimitry Andric using namespace llvm;
238f0fd8f6SDimitry Andric 
248f0fd8f6SDimitry Andric #define DEBUG_TYPE "faultmaps"
258f0fd8f6SDimitry Andric 
268f0fd8f6SDimitry Andric static const int FaultMapVersion = 1;
278f0fd8f6SDimitry Andric const char *FaultMaps::WFMP = "Fault Maps: ";
288f0fd8f6SDimitry Andric 
FaultMaps(AsmPrinter & AP)298f0fd8f6SDimitry Andric FaultMaps::FaultMaps(AsmPrinter &AP) : AP(AP) {}
308f0fd8f6SDimitry Andric 
recordFaultingOp(FaultKind FaultTy,const MCSymbol * HandlerLabel)318f0fd8f6SDimitry Andric void FaultMaps::recordFaultingOp(FaultKind FaultTy,
328f0fd8f6SDimitry Andric                                  const MCSymbol *HandlerLabel) {
338f0fd8f6SDimitry Andric   MCContext &OutContext = AP.OutStreamer->getContext();
348f0fd8f6SDimitry Andric   MCSymbol *FaultingLabel = OutContext.createTempSymbol();
358f0fd8f6SDimitry Andric 
368f0fd8f6SDimitry Andric   AP.OutStreamer->EmitLabel(FaultingLabel);
378f0fd8f6SDimitry Andric 
388f0fd8f6SDimitry Andric   const MCExpr *FaultingOffset = MCBinaryExpr::createSub(
398f0fd8f6SDimitry Andric       MCSymbolRefExpr::create(FaultingLabel, OutContext),
408f0fd8f6SDimitry Andric       MCSymbolRefExpr::create(AP.CurrentFnSymForSize, OutContext), OutContext);
418f0fd8f6SDimitry Andric 
428f0fd8f6SDimitry Andric   const MCExpr *HandlerOffset = MCBinaryExpr::createSub(
438f0fd8f6SDimitry Andric       MCSymbolRefExpr::create(HandlerLabel, OutContext),
448f0fd8f6SDimitry Andric       MCSymbolRefExpr::create(AP.CurrentFnSymForSize, OutContext), OutContext);
458f0fd8f6SDimitry Andric 
468f0fd8f6SDimitry Andric   FunctionInfos[AP.CurrentFnSym].emplace_back(FaultTy, FaultingOffset,
478f0fd8f6SDimitry Andric                                               HandlerOffset);
488f0fd8f6SDimitry Andric }
498f0fd8f6SDimitry Andric 
serializeToFaultMapSection()508f0fd8f6SDimitry Andric void FaultMaps::serializeToFaultMapSection() {
518f0fd8f6SDimitry Andric   if (FunctionInfos.empty())
528f0fd8f6SDimitry Andric     return;
538f0fd8f6SDimitry Andric 
548f0fd8f6SDimitry Andric   MCContext &OutContext = AP.OutStreamer->getContext();
558f0fd8f6SDimitry Andric   MCStreamer &OS = *AP.OutStreamer;
568f0fd8f6SDimitry Andric 
578f0fd8f6SDimitry Andric   // Create the section.
588f0fd8f6SDimitry Andric   MCSection *FaultMapSection =
598f0fd8f6SDimitry Andric       OutContext.getObjectFileInfo()->getFaultMapSection();
608f0fd8f6SDimitry Andric   OS.SwitchSection(FaultMapSection);
618f0fd8f6SDimitry Andric 
628f0fd8f6SDimitry Andric   // Emit a dummy symbol to force section inclusion.
638f0fd8f6SDimitry Andric   OS.EmitLabel(OutContext.getOrCreateSymbol(Twine("__LLVM_FaultMaps")));
648f0fd8f6SDimitry Andric 
65*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "********** Fault Map Output **********\n");
668f0fd8f6SDimitry Andric 
678f0fd8f6SDimitry Andric   // Header
688f0fd8f6SDimitry Andric   OS.EmitIntValue(FaultMapVersion, 1); // Version.
698f0fd8f6SDimitry Andric   OS.EmitIntValue(0, 1);               // Reserved.
708f0fd8f6SDimitry Andric   OS.EmitIntValue(0, 2);               // Reserved.
718f0fd8f6SDimitry Andric 
72*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << WFMP << "#functions = " << FunctionInfos.size() << "\n");
738f0fd8f6SDimitry Andric   OS.EmitIntValue(FunctionInfos.size(), 4);
748f0fd8f6SDimitry Andric 
75*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << WFMP << "functions:\n");
768f0fd8f6SDimitry Andric 
778f0fd8f6SDimitry Andric   for (const auto &FFI : FunctionInfos)
788f0fd8f6SDimitry Andric     emitFunctionInfo(FFI.first, FFI.second);
798f0fd8f6SDimitry Andric }
808f0fd8f6SDimitry Andric 
emitFunctionInfo(const MCSymbol * FnLabel,const FunctionFaultInfos & FFI)818f0fd8f6SDimitry Andric void FaultMaps::emitFunctionInfo(const MCSymbol *FnLabel,
828f0fd8f6SDimitry Andric                                  const FunctionFaultInfos &FFI) {
838f0fd8f6SDimitry Andric   MCStreamer &OS = *AP.OutStreamer;
848f0fd8f6SDimitry Andric 
85*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << WFMP << "  function addr: " << *FnLabel << "\n");
868f0fd8f6SDimitry Andric   OS.EmitSymbolValue(FnLabel, 8);
878f0fd8f6SDimitry Andric 
88*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << WFMP << "  #faulting PCs: " << FFI.size() << "\n");
898f0fd8f6SDimitry Andric   OS.EmitIntValue(FFI.size(), 4);
908f0fd8f6SDimitry Andric 
918f0fd8f6SDimitry Andric   OS.EmitIntValue(0, 4); // Reserved
928f0fd8f6SDimitry Andric 
938f0fd8f6SDimitry Andric   for (auto &Fault : FFI) {
94*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << WFMP << "    fault type: "
958f0fd8f6SDimitry Andric                       << faultTypeToString(Fault.Kind) << "\n");
968f0fd8f6SDimitry Andric     OS.EmitIntValue(Fault.Kind, 4);
978f0fd8f6SDimitry Andric 
98*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << WFMP << "    faulting PC offset: "
998f0fd8f6SDimitry Andric                       << *Fault.FaultingOffsetExpr << "\n");
1008f0fd8f6SDimitry Andric     OS.EmitValue(Fault.FaultingOffsetExpr, 4);
1018f0fd8f6SDimitry Andric 
102*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << WFMP << "    fault handler PC offset: "
1038f0fd8f6SDimitry Andric                       << *Fault.HandlerOffsetExpr << "\n");
1048f0fd8f6SDimitry Andric     OS.EmitValue(Fault.HandlerOffsetExpr, 4);
1058f0fd8f6SDimitry Andric   }
1068f0fd8f6SDimitry Andric }
1078f0fd8f6SDimitry Andric 
faultTypeToString(FaultMaps::FaultKind FT)1088f0fd8f6SDimitry Andric const char *FaultMaps::faultTypeToString(FaultMaps::FaultKind FT) {
1098f0fd8f6SDimitry Andric   switch (FT) {
1108f0fd8f6SDimitry Andric   default:
1118f0fd8f6SDimitry Andric     llvm_unreachable("unhandled fault type!");
1128f0fd8f6SDimitry Andric   case FaultMaps::FaultingLoad:
1138f0fd8f6SDimitry Andric     return "FaultingLoad";
1147a7e6055SDimitry Andric   case FaultMaps::FaultingLoadStore:
1157a7e6055SDimitry Andric     return "FaultingLoadStore";
1167a7e6055SDimitry Andric   case FaultMaps::FaultingStore:
1177a7e6055SDimitry Andric     return "FaultingStore";
1188f0fd8f6SDimitry Andric   }
1198f0fd8f6SDimitry Andric }
1203dac3a9bSDimitry Andric 
1213dac3a9bSDimitry Andric raw_ostream &llvm::
operator <<(raw_ostream & OS,const FaultMapParser::FunctionFaultInfoAccessor & FFI)1223dac3a9bSDimitry Andric operator<<(raw_ostream &OS,
1233dac3a9bSDimitry Andric            const FaultMapParser::FunctionFaultInfoAccessor &FFI) {
1243dac3a9bSDimitry Andric   OS << "Fault kind: "
1253dac3a9bSDimitry Andric      << FaultMaps::faultTypeToString((FaultMaps::FaultKind)FFI.getFaultKind())
1263dac3a9bSDimitry Andric      << ", faulting PC offset: " << FFI.getFaultingPCOffset()
1273dac3a9bSDimitry Andric      << ", handling PC offset: " << FFI.getHandlerPCOffset();
1283dac3a9bSDimitry Andric   return OS;
1293dac3a9bSDimitry Andric }
1303dac3a9bSDimitry Andric 
1313dac3a9bSDimitry Andric raw_ostream &llvm::
operator <<(raw_ostream & OS,const FaultMapParser::FunctionInfoAccessor & FI)1323dac3a9bSDimitry Andric operator<<(raw_ostream &OS, const FaultMapParser::FunctionInfoAccessor &FI) {
1333dac3a9bSDimitry Andric   OS << "FunctionAddress: " << format_hex(FI.getFunctionAddr(), 8)
1343dac3a9bSDimitry Andric      << ", NumFaultingPCs: " << FI.getNumFaultingPCs() << "\n";
1353dac3a9bSDimitry Andric   for (unsigned i = 0, e = FI.getNumFaultingPCs(); i != e; ++i)
1363dac3a9bSDimitry Andric     OS << FI.getFunctionFaultInfoAt(i) << "\n";
1373dac3a9bSDimitry Andric   return OS;
1383dac3a9bSDimitry Andric }
1393dac3a9bSDimitry Andric 
operator <<(raw_ostream & OS,const FaultMapParser & FMP)1403dac3a9bSDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const FaultMapParser &FMP) {
1413dac3a9bSDimitry Andric   OS << "Version: " << format_hex(FMP.getFaultMapVersion(), 2) << "\n";
1423dac3a9bSDimitry Andric   OS << "NumFunctions: " << FMP.getNumFunctions() << "\n";
1433dac3a9bSDimitry Andric 
1443dac3a9bSDimitry Andric   if (FMP.getNumFunctions() == 0)
1453dac3a9bSDimitry Andric     return OS;
1463dac3a9bSDimitry Andric 
1473dac3a9bSDimitry Andric   FaultMapParser::FunctionInfoAccessor FI;
1483dac3a9bSDimitry Andric 
1493dac3a9bSDimitry Andric   for (unsigned i = 0, e = FMP.getNumFunctions(); i != e; ++i) {
1503dac3a9bSDimitry Andric     FI = (i == 0) ? FMP.getFirstFunctionInfo() : FI.getNextFunctionInfo();
1513dac3a9bSDimitry Andric     OS << FI;
1523dac3a9bSDimitry Andric   }
1533dac3a9bSDimitry Andric 
1543dac3a9bSDimitry Andric   return OS;
1553dac3a9bSDimitry Andric }
156