1234285Sdim//===-- OProfileJITEventListener.cpp - Tell OProfile about JITted code ----===//
2234285Sdim//
3234285Sdim//                     The LLVM Compiler Infrastructure
4234285Sdim//
5234285Sdim// This file is distributed under the University of Illinois Open Source
6234285Sdim// License. See LICENSE.TXT for details.
7234285Sdim//
8234285Sdim//===----------------------------------------------------------------------===//
9234285Sdim//
10234285Sdim// This file defines a JITEventListener object that uses OProfileWrapper to tell
11234285Sdim// oprofile about JITted functions, including source line information.
12234285Sdim//
13234285Sdim//===----------------------------------------------------------------------===//
14234285Sdim
15234285Sdim#include "llvm/Config/config.h"
16234285Sdim#include "llvm/ExecutionEngine/JITEventListener.h"
17234285Sdim
18234285Sdim#define DEBUG_TYPE "oprofile-jit-event-listener"
19239462Sdim#include "llvm/DebugInfo.h"
20249423Sdim#include "llvm/IR/Function.h"
21234285Sdim#include "llvm/ADT/OwningPtr.h"
22234285Sdim#include "llvm/CodeGen/MachineFunction.h"
23263508Sdim#include "llvm/ExecutionEngine/ObjectImage.h"
24234285Sdim#include "llvm/ExecutionEngine/OProfileWrapper.h"
25263508Sdim#include "llvm/Object/ObjectFile.h"
26234285Sdim#include "llvm/Support/Debug.h"
27234285Sdim#include "llvm/Support/raw_ostream.h"
28234285Sdim#include "llvm/Support/Errno.h"
29234285Sdim#include "EventListenerCommon.h"
30234285Sdim
31234285Sdim#include <dirent.h>
32234285Sdim#include <fcntl.h>
33234285Sdim
34234285Sdimusing namespace llvm;
35234285Sdimusing namespace llvm::jitprofiling;
36234285Sdim
37234285Sdimnamespace {
38234285Sdim
39234285Sdimclass OProfileJITEventListener : public JITEventListener {
40234285Sdim  OProfileWrapper& Wrapper;
41234285Sdim
42234285Sdim  void initialize();
43234285Sdim
44234285Sdimpublic:
45234285Sdim  OProfileJITEventListener(OProfileWrapper& LibraryWrapper)
46234285Sdim  : Wrapper(LibraryWrapper) {
47234285Sdim    initialize();
48234285Sdim  }
49234285Sdim
50234285Sdim  ~OProfileJITEventListener();
51234285Sdim
52234285Sdim  virtual void NotifyFunctionEmitted(const Function &F,
53234285Sdim                                void *FnStart, size_t FnSize,
54234285Sdim                                const JITEvent_EmittedFunctionDetails &Details);
55234285Sdim
56234285Sdim  virtual void NotifyFreeingMachineCode(void *OldPtr);
57263508Sdim
58263508Sdim  virtual void NotifyObjectEmitted(const ObjectImage &Obj);
59263508Sdim
60263508Sdim  virtual void NotifyFreeingObject(const ObjectImage &Obj);
61234285Sdim};
62234285Sdim
63234285Sdimvoid OProfileJITEventListener::initialize() {
64234285Sdim  if (!Wrapper.op_open_agent()) {
65234285Sdim    const std::string err_str = sys::StrError();
66234285Sdim    DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str << "\n");
67234285Sdim  } else {
68234285Sdim    DEBUG(dbgs() << "Connected to OProfile agent.\n");
69234285Sdim  }
70234285Sdim}
71234285Sdim
72234285SdimOProfileJITEventListener::~OProfileJITEventListener() {
73234285Sdim  if (Wrapper.isAgentAvailable()) {
74234285Sdim    if (Wrapper.op_close_agent() == -1) {
75234285Sdim      const std::string err_str = sys::StrError();
76234285Sdim      DEBUG(dbgs() << "Failed to disconnect from OProfile agent: "
77234285Sdim                   << err_str << "\n");
78234285Sdim    } else {
79234285Sdim      DEBUG(dbgs() << "Disconnected from OProfile agent.\n");
80234285Sdim    }
81234285Sdim  }
82234285Sdim}
83234285Sdim
84234285Sdimstatic debug_line_info LineStartToOProfileFormat(
85234285Sdim    const MachineFunction &MF, FilenameCache &Filenames,
86234285Sdim    uintptr_t Address, DebugLoc Loc) {
87234285Sdim  debug_line_info Result;
88234285Sdim  Result.vma = Address;
89234285Sdim  Result.lineno = Loc.getLine();
90234285Sdim  Result.filename = Filenames.getFilename(
91234285Sdim    Loc.getScope(MF.getFunction()->getContext()));
92234285Sdim  DEBUG(dbgs() << "Mapping " << reinterpret_cast<void*>(Result.vma) << " to "
93234285Sdim               << Result.filename << ":" << Result.lineno << "\n");
94234285Sdim  return Result;
95234285Sdim}
96234285Sdim
97234285Sdim// Adds the just-emitted function to the symbol table.
98234285Sdimvoid OProfileJITEventListener::NotifyFunctionEmitted(
99234285Sdim    const Function &F, void *FnStart, size_t FnSize,
100234285Sdim    const JITEvent_EmittedFunctionDetails &Details) {
101234285Sdim  assert(F.hasName() && FnStart != 0 && "Bad symbol to add");
102234285Sdim  if (Wrapper.op_write_native_code(F.getName().data(),
103234285Sdim                           reinterpret_cast<uint64_t>(FnStart),
104234285Sdim                           FnStart, FnSize) == -1) {
105234285Sdim    DEBUG(dbgs() << "Failed to tell OProfile about native function "
106234285Sdim          << F.getName() << " at ["
107234285Sdim          << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
108234285Sdim    return;
109234285Sdim  }
110234285Sdim
111234285Sdim  if (!Details.LineStarts.empty()) {
112234285Sdim    // Now we convert the line number information from the address/DebugLoc
113234285Sdim    // format in Details to the address/filename/lineno format that OProfile
114234285Sdim    // expects.  Note that OProfile 0.9.4 has a bug that causes it to ignore
115234285Sdim    // line numbers for addresses above 4G.
116234285Sdim    FilenameCache Filenames;
117234285Sdim    std::vector<debug_line_info> LineInfo;
118234285Sdim    LineInfo.reserve(1 + Details.LineStarts.size());
119234285Sdim
120234285Sdim    DebugLoc FirstLoc = Details.LineStarts[0].Loc;
121234285Sdim    assert(!FirstLoc.isUnknown()
122234285Sdim           && "LineStarts should not contain unknown DebugLocs");
123234285Sdim    MDNode *FirstLocScope = FirstLoc.getScope(F.getContext());
124234285Sdim    DISubprogram FunctionDI = getDISubprogram(FirstLocScope);
125234285Sdim    if (FunctionDI.Verify()) {
126234285Sdim      // If we have debug info for the function itself, use that as the line
127234285Sdim      // number of the first several instructions.  Otherwise, after filling
128234285Sdim      // LineInfo, we'll adjust the address of the first line number to point at
129234285Sdim      // the start of the function.
130234285Sdim      debug_line_info line_info;
131234285Sdim      line_info.vma = reinterpret_cast<uintptr_t>(FnStart);
132234285Sdim      line_info.lineno = FunctionDI.getLineNumber();
133234285Sdim      line_info.filename = Filenames.getFilename(FirstLocScope);
134234285Sdim      LineInfo.push_back(line_info);
135234285Sdim    }
136234285Sdim
137234285Sdim    for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator
138234285Sdim           I = Details.LineStarts.begin(), E = Details.LineStarts.end();
139234285Sdim         I != E; ++I) {
140234285Sdim      LineInfo.push_back(LineStartToOProfileFormat(
141234285Sdim                           *Details.MF, Filenames, I->Address, I->Loc));
142234285Sdim    }
143234285Sdim
144234285Sdim    // In case the function didn't have line info of its own, adjust the first
145234285Sdim    // line info's address to include the start of the function.
146234285Sdim    LineInfo[0].vma = reinterpret_cast<uintptr_t>(FnStart);
147234285Sdim
148234285Sdim    if (Wrapper.op_write_debug_line_info(FnStart, LineInfo.size(),
149234285Sdim                                      &*LineInfo.begin()) == -1) {
150234285Sdim      DEBUG(dbgs()
151234285Sdim            << "Failed to tell OProfile about line numbers for native function "
152234285Sdim            << F.getName() << " at ["
153234285Sdim            << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
154234285Sdim    }
155234285Sdim  }
156234285Sdim}
157234285Sdim
158234285Sdim// Removes the being-deleted function from the symbol table.
159234285Sdimvoid OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
160234285Sdim  assert(FnStart && "Invalid function pointer");
161234285Sdim  if (Wrapper.op_unload_native_code(reinterpret_cast<uint64_t>(FnStart)) == -1) {
162234285Sdim    DEBUG(dbgs()
163234285Sdim          << "Failed to tell OProfile about unload of native function at "
164234285Sdim          << FnStart << "\n");
165234285Sdim  }
166234285Sdim}
167234285Sdim
168263508Sdimvoid OProfileJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) {
169263508Sdim  if (!Wrapper.isAgentAvailable()) {
170263508Sdim    return;
171263508Sdim  }
172263508Sdim
173263508Sdim  // Use symbol info to iterate functions in the object.
174263508Sdim  error_code ec;
175263508Sdim  for (object::symbol_iterator I = Obj.begin_symbols(),
176263508Sdim                               E = Obj.end_symbols();
177263508Sdim                        I != E && !ec;
178263508Sdim                        I.increment(ec)) {
179263508Sdim    object::SymbolRef::Type SymType;
180263508Sdim    if (I->getType(SymType)) continue;
181263508Sdim    if (SymType == object::SymbolRef::ST_Function) {
182263508Sdim      StringRef  Name;
183263508Sdim      uint64_t   Addr;
184263508Sdim      uint64_t   Size;
185263508Sdim      if (I->getName(Name)) continue;
186263508Sdim      if (I->getAddress(Addr)) continue;
187263508Sdim      if (I->getSize(Size)) continue;
188263508Sdim
189263508Sdim      if (Wrapper.op_write_native_code(Name.data(), Addr, (void*)Addr, Size)
190263508Sdim                        == -1) {
191263508Sdim        DEBUG(dbgs() << "Failed to tell OProfile about native function "
192263508Sdim          << Name << " at ["
193263508Sdim          << (void*)Addr << "-" << ((char*)Addr + Size) << "]\n");
194263508Sdim        continue;
195263508Sdim      }
196263508Sdim      // TODO: support line number info (similar to IntelJITEventListener.cpp)
197263508Sdim    }
198263508Sdim  }
199263508Sdim}
200263508Sdim
201263508Sdimvoid OProfileJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) {
202263508Sdim  if (!Wrapper.isAgentAvailable()) {
203263508Sdim    return;
204263508Sdim  }
205263508Sdim
206263508Sdim  // Use symbol info to iterate functions in the object.
207263508Sdim  error_code ec;
208263508Sdim  for (object::symbol_iterator I = Obj.begin_symbols(),
209263508Sdim                               E = Obj.end_symbols();
210263508Sdim                        I != E && !ec;
211263508Sdim                        I.increment(ec)) {
212263508Sdim    object::SymbolRef::Type SymType;
213263508Sdim    if (I->getType(SymType)) continue;
214263508Sdim    if (SymType == object::SymbolRef::ST_Function) {
215263508Sdim      uint64_t   Addr;
216263508Sdim      if (I->getAddress(Addr)) continue;
217263508Sdim
218263508Sdim      if (Wrapper.op_unload_native_code(Addr) == -1) {
219263508Sdim        DEBUG(dbgs()
220263508Sdim          << "Failed to tell OProfile about unload of native function at "
221263508Sdim          << (void*)Addr << "\n");
222263508Sdim        continue;
223263508Sdim      }
224263508Sdim    }
225263508Sdim  }
226263508Sdim}
227263508Sdim
228234285Sdim}  // anonymous namespace.
229234285Sdim
230234285Sdimnamespace llvm {
231234285SdimJITEventListener *JITEventListener::createOProfileJITEventListener() {
232234285Sdim  static OwningPtr<OProfileWrapper> JITProfilingWrapper(new OProfileWrapper);
233234285Sdim  return new OProfileJITEventListener(*JITProfilingWrapper);
234234285Sdim}
235234285Sdim
236234285Sdim// for testing
237234285SdimJITEventListener *JITEventListener::createOProfileJITEventListener(
238234285Sdim                                      OProfileWrapper* TestImpl) {
239234285Sdim  return new OProfileJITEventListener(*TestImpl);
240234285Sdim}
241234285Sdim
242234285Sdim} // namespace llvm
243234285Sdim
244