Home | History | Annotate | Download | only in OProfileJIT
      1 //===-- OProfileJITEventListener.cpp - Tell OProfile about JITted code ----===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file defines a JITEventListener object that uses OProfileWrapper to tell
     11 // oprofile about JITted functions, including source line information.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "llvm-c/ExecutionEngine.h"
     16 #include "llvm/CodeGen/MachineFunction.h"
     17 #include "llvm/Config/config.h"
     18 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
     19 #include "llvm/ExecutionEngine/JITEventListener.h"
     20 #include "llvm/ExecutionEngine/OProfileWrapper.h"
     21 #include "llvm/ExecutionEngine/RuntimeDyld.h"
     22 #include "llvm/IR/DebugInfo.h"
     23 #include "llvm/IR/Function.h"
     24 #include "llvm/Object/ObjectFile.h"
     25 #include "llvm/Object/SymbolSize.h"
     26 #include "llvm/Support/Debug.h"
     27 #include "llvm/Support/Errno.h"
     28 #include "llvm/Support/raw_ostream.h"
     29 #include <dirent.h>
     30 #include <fcntl.h>
     31 
     32 using namespace llvm;
     33 using namespace llvm::object;
     34 
     35 #define DEBUG_TYPE "oprofile-jit-event-listener"
     36 
     37 namespace {
     38 
     39 class OProfileJITEventListener : public JITEventListener {
     40   std::unique_ptr<OProfileWrapper> Wrapper;
     41 
     42   void initialize();
     43   std::map<const char*, OwningBinary<ObjectFile>> DebugObjects;
     44 
     45 public:
     46   OProfileJITEventListener(std::unique_ptr<OProfileWrapper> LibraryWrapper)
     47     : Wrapper(std::move(LibraryWrapper)) {
     48     initialize();
     49   }
     50 
     51   ~OProfileJITEventListener();
     52 
     53   void NotifyObjectEmitted(const ObjectFile &Obj,
     54                            const RuntimeDyld::LoadedObjectInfo &L) override;
     55 
     56   void NotifyFreeingObject(const ObjectFile &Obj) override;
     57 };
     58 
     59 void OProfileJITEventListener::initialize() {
     60   if (!Wrapper->op_open_agent()) {
     61     const std::string err_str = sys::StrError();
     62     LLVM_DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str
     63                       << "\n");
     64   } else {
     65     LLVM_DEBUG(dbgs() << "Connected to OProfile agent.\n");
     66   }
     67 }
     68 
     69 OProfileJITEventListener::~OProfileJITEventListener() {
     70   if (Wrapper->isAgentAvailable()) {
     71     if (Wrapper->op_close_agent() == -1) {
     72       const std::string err_str = sys::StrError();
     73       LLVM_DEBUG(dbgs() << "Failed to disconnect from OProfile agent: "
     74                         << err_str << "\n");
     75     } else {
     76       LLVM_DEBUG(dbgs() << "Disconnected from OProfile agent.\n");
     77     }
     78   }
     79 }
     80 
     81 void OProfileJITEventListener::NotifyObjectEmitted(
     82                                        const ObjectFile &Obj,
     83                                        const RuntimeDyld::LoadedObjectInfo &L) {
     84   if (!Wrapper->isAgentAvailable()) {
     85     return;
     86   }
     87 
     88   OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj);
     89   const ObjectFile &DebugObj = *DebugObjOwner.getBinary();
     90   std::unique_ptr<DIContext> Context = DWARFContext::create(DebugObj);
     91 
     92   // Use symbol info to iterate functions in the object.
     93   for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) {
     94     SymbolRef Sym = P.first;
     95     if (!Sym.getType() || *Sym.getType() != SymbolRef::ST_Function)
     96       continue;
     97 
     98     Expected<StringRef> NameOrErr = Sym.getName();
     99     if (!NameOrErr)
    100       continue;
    101     StringRef Name = *NameOrErr;
    102     Expected<uint64_t> AddrOrErr = Sym.getAddress();
    103     if (!AddrOrErr)
    104       continue;
    105     uint64_t Addr = *AddrOrErr;
    106     uint64_t Size = P.second;
    107 
    108     if (Wrapper->op_write_native_code(Name.data(), Addr, (void *)Addr, Size) ==
    109         -1) {
    110       LLVM_DEBUG(dbgs() << "Failed to tell OProfile about native function "
    111                         << Name << " at [" << (void *)Addr << "-"
    112                         << ((char *)Addr + Size) << "]\n");
    113       continue;
    114     }
    115 
    116     DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
    117     size_t i = 0;
    118     size_t num_entries = Lines.size();
    119     struct debug_line_info *debug_line;
    120     debug_line = (struct debug_line_info *)calloc(
    121         num_entries, sizeof(struct debug_line_info));
    122 
    123     for (auto& It : Lines) {
    124       debug_line[i].vma = (unsigned long)It.first;
    125       debug_line[i].lineno = It.second.Line;
    126       debug_line[i].filename =
    127           const_cast<char *>(Lines.front().second.FileName.c_str());
    128       ++i;
    129     }
    130 
    131     if (Wrapper->op_write_debug_line_info((void *)Addr, num_entries,
    132                                           debug_line) == -1) {
    133       LLVM_DEBUG(dbgs() << "Failed to tell OProfiler about debug object at ["
    134                         << (void *)Addr << "-" << ((char *)Addr + Size)
    135                         << "]\n");
    136       continue;
    137     }
    138   }
    139 
    140   DebugObjects[Obj.getData().data()] = std::move(DebugObjOwner);
    141 }
    142 
    143 void OProfileJITEventListener::NotifyFreeingObject(const ObjectFile &Obj) {
    144   if (Wrapper->isAgentAvailable()) {
    145 
    146     // If there was no agent registered when the original object was loaded then
    147     // we won't have created a debug object for it, so bail out.
    148     if (DebugObjects.find(Obj.getData().data()) == DebugObjects.end())
    149       return;
    150 
    151     const ObjectFile &DebugObj = *DebugObjects[Obj.getData().data()].getBinary();
    152 
    153     // Use symbol info to iterate functions in the object.
    154     for (symbol_iterator I = DebugObj.symbol_begin(),
    155                          E = DebugObj.symbol_end();
    156          I != E; ++I) {
    157       if (I->getType() && *I->getType() == SymbolRef::ST_Function) {
    158         Expected<uint64_t> AddrOrErr = I->getAddress();
    159         if (!AddrOrErr)
    160           continue;
    161         uint64_t Addr = *AddrOrErr;
    162 
    163         if (Wrapper->op_unload_native_code(Addr) == -1) {
    164           LLVM_DEBUG(
    165               dbgs()
    166               << "Failed to tell OProfile about unload of native function at "
    167               << (void *)Addr << "\n");
    168           continue;
    169         }
    170       }
    171     }
    172   }
    173 
    174   DebugObjects.erase(Obj.getData().data());
    175 }
    176 
    177 }  // anonymous namespace.
    178 
    179 namespace llvm {
    180 JITEventListener *JITEventListener::createOProfileJITEventListener() {
    181   return new OProfileJITEventListener(llvm::make_unique<OProfileWrapper>());
    182 }
    183 
    184 } // namespace llvm
    185 
    186 LLVMJITEventListenerRef LLVMCreateOProfileJITEventListener(void)
    187 {
    188   return wrap(JITEventListener::createOProfileJITEventListener());
    189 }
    190