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/Config/config.h"
     16 #include "llvm/CodeGen/MachineFunction.h"
     17 #include "llvm/ExecutionEngine/JITEventListener.h"
     18 #include "llvm/ExecutionEngine/OProfileWrapper.h"
     19 #include "llvm/ExecutionEngine/RuntimeDyld.h"
     20 #include "llvm/IR/DebugInfo.h"
     21 #include "llvm/IR/Function.h"
     22 #include "llvm/Object/ObjectFile.h"
     23 #include "llvm/Object/SymbolSize.h"
     24 #include "llvm/Support/Debug.h"
     25 #include "llvm/Support/Errno.h"
     26 #include "llvm/Support/raw_ostream.h"
     27 #include <dirent.h>
     28 #include <fcntl.h>
     29 
     30 using namespace llvm;
     31 using namespace llvm::object;
     32 
     33 #define DEBUG_TYPE "oprofile-jit-event-listener"
     34 
     35 namespace {
     36 
     37 class OProfileJITEventListener : public JITEventListener {
     38   std::unique_ptr<OProfileWrapper> Wrapper;
     39 
     40   void initialize();
     41   std::map<const char*, OwningBinary<ObjectFile>> DebugObjects;
     42 
     43 public:
     44   OProfileJITEventListener(std::unique_ptr<OProfileWrapper> LibraryWrapper)
     45     : Wrapper(std::move(LibraryWrapper)) {
     46     initialize();
     47   }
     48 
     49   ~OProfileJITEventListener();
     50 
     51   void NotifyObjectEmitted(const ObjectFile &Obj,
     52                            const RuntimeDyld::LoadedObjectInfo &L) override;
     53 
     54   void NotifyFreeingObject(const ObjectFile &Obj) override;
     55 };
     56 
     57 void OProfileJITEventListener::initialize() {
     58   if (!Wrapper->op_open_agent()) {
     59     const std::string err_str = sys::StrError();
     60     DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str << "\n");
     61   } else {
     62     DEBUG(dbgs() << "Connected to OProfile agent.\n");
     63   }
     64 }
     65 
     66 OProfileJITEventListener::~OProfileJITEventListener() {
     67   if (Wrapper->isAgentAvailable()) {
     68     if (Wrapper->op_close_agent() == -1) {
     69       const std::string err_str = sys::StrError();
     70       DEBUG(dbgs() << "Failed to disconnect from OProfile agent: "
     71                    << err_str << "\n");
     72     } else {
     73       DEBUG(dbgs() << "Disconnected from OProfile agent.\n");
     74     }
     75   }
     76 }
     77 
     78 void OProfileJITEventListener::NotifyObjectEmitted(
     79                                        const ObjectFile &Obj,
     80                                        const RuntimeDyld::LoadedObjectInfo &L) {
     81   if (!Wrapper->isAgentAvailable()) {
     82     return;
     83   }
     84 
     85   OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj);
     86   const ObjectFile &DebugObj = *DebugObjOwner.getBinary();
     87 
     88   // Use symbol info to iterate functions in the object.
     89   for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) {
     90     SymbolRef Sym = P.first;
     91     if (Sym.getType() != SymbolRef::ST_Function)
     92       continue;
     93 
     94     ErrorOr<StringRef> NameOrErr = Sym.getName();
     95     if (NameOrErr.getError())
     96       continue;
     97     StringRef Name = *NameOrErr;
     98     ErrorOr<uint64_t> AddrOrErr = Sym.getAddress();
     99     if (AddrOrErr.getError())
    100       continue;
    101     uint64_t Addr = *AddrOrErr;
    102     uint64_t Size = P.second;
    103 
    104     if (Wrapper->op_write_native_code(Name.data(), Addr, (void *)Addr, Size) ==
    105         -1) {
    106       DEBUG(dbgs() << "Failed to tell OProfile about native function " << Name
    107                    << " at [" << (void *)Addr << "-" << ((char *)Addr + Size)
    108                    << "]\n");
    109       continue;
    110     }
    111     // TODO: support line number info (similar to IntelJITEventListener.cpp)
    112   }
    113 
    114   DebugObjects[Obj.getData().data()] = std::move(DebugObjOwner);
    115 }
    116 
    117 void OProfileJITEventListener::NotifyFreeingObject(const ObjectFile &Obj) {
    118   if (Wrapper->isAgentAvailable()) {
    119 
    120     // If there was no agent registered when the original object was loaded then
    121     // we won't have created a debug object for it, so bail out.
    122     if (DebugObjects.find(Obj.getData().data()) == DebugObjects.end())
    123       return;
    124 
    125     const ObjectFile &DebugObj = *DebugObjects[Obj.getData().data()].getBinary();
    126 
    127     // Use symbol info to iterate functions in the object.
    128     for (symbol_iterator I = DebugObj.symbol_begin(),
    129                          E = DebugObj.symbol_end();
    130          I != E; ++I) {
    131       if (I->getType() == SymbolRef::ST_Function) {
    132         ErrorOr<uint64_t> AddrOrErr = I->getAddress();
    133         if (AddrOrErr.getError())
    134           continue;
    135         uint64_t Addr = *AddrOrErr;
    136 
    137         if (Wrapper->op_unload_native_code(Addr) == -1) {
    138           DEBUG(dbgs()
    139                 << "Failed to tell OProfile about unload of native function at "
    140                 << (void*)Addr << "\n");
    141           continue;
    142         }
    143       }
    144     }
    145   }
    146 
    147   DebugObjects.erase(Obj.getData().data());
    148 }
    149 
    150 }  // anonymous namespace.
    151 
    152 namespace llvm {
    153 JITEventListener *JITEventListener::createOProfileJITEventListener() {
    154   return new OProfileJITEventListener(llvm::make_unique<OProfileWrapper>());
    155 }
    156 
    157 } // namespace llvm
    158 
    159