libcsdbg  1.28
C++ exception (and generic) stack trace debug library
plugin.cpp
Go to the documentation of this file.
1 #include "../include/plugin.hpp"
2 #include "../include/string.hpp"
3 #include "../include/util.hpp"
4 
11 namespace csdbg {
12 
19 {
20  if ( likely(m_handle != NULL) )
21  dlclose(m_handle);
22 
23  delete[] m_path;
24  m_path = NULL;
25  m_handle = NULL;
26  m_begin = m_end = NULL;
27 
28  return *this;
29 }
30 
31 
44 plugin::plugin(const i8 *path, const i8 *scope)
45 try:
46 m_begin(NULL),
47 m_end(NULL),
48 m_path(NULL),
49 m_handle(NULL)
50 {
51  if ( unlikely(path == NULL) )
52  throw exception("invalid argument: path (=%p)", path);
53 
54  m_path = new i8[strlen(path) + 1];
55  strcpy(m_path, path);
56 
57  /* Check if the module is already loaded */
58  u32 flags = RTLD_LOCAL | RTLD_LAZY;
59  m_handle = dlopen(m_path, flags | RTLD_NOLOAD);
60 
61  /* If the module is not yet loaded, load it explicitly */
62  if ( likely(m_handle == NULL) ) {
63  dlerror();
64  m_handle = dlopen(m_path, flags);
65  if ( unlikely(m_handle == NULL) )
66  throw exception("failed to load plugin '%s' (%s)", m_path, dlerror());
67 
68  util::dbg_info("plugin '%s' loaded/linked", m_path);
69  }
70 #if CSDBG_DBG_LEVEL & CSDBG_DBGL_INFO
71  else
72  util::dbg_info("plugin '%s' linked", m_path);
73 #endif
74 
75  /* Resolve the instrumentation functions */
76  m_begin = resolve("mod_enter", scope);
77  m_end = resolve("mod_exit", scope);
78 }
79 
80 catch (...) {
81  destroy();
82 }
83 
84 
93 m_begin(bgn),
94 m_end(end),
95 m_path(NULL),
96 m_handle(NULL)
97 {
98 }
99 
100 
110 try:
111 m_begin(NULL),
112 m_end(NULL),
113 m_path(NULL),
114 m_handle(NULL)
115 {
116  *this = src;
117 }
118 
119 catch (...) {
120  destroy();
121 }
122 
123 
128 {
129 #if CSDBG_DBG_LEVEL & CSDBG_DBGL_INFO
130  if ( likely(m_handle != NULL && m_path != NULL) )
131  util::dbg_info("plugin '%s' unlinked", m_path);
132 #endif
133  destroy();
134 }
135 
136 
145 inline plugin* plugin::clone() const
146 {
147  return new plugin(*this);
148 }
149 
150 
156 inline const i8* plugin::path() const
157 {
158  return m_path;
159 }
160 
161 
173 {
174  if ( unlikely(this == &rval) )
175  return *this;
176 
177  m_begin = rval.m_begin;
178  m_end = rval.m_end;
179 
180  /* If this object has called dlopen and holds a handle, close it */
181  if ( likely(m_handle != NULL) ) {
182  dlclose(m_handle);
183  util::dbg_info("plugin '%s' unlinked", m_path);
184 
185  delete[] m_path;
186  m_path = NULL;
187  m_handle = NULL;
188  }
189 
190  if ( unlikely(rval.m_handle == NULL) )
191  return *this;
192 
193  m_path = new i8[strlen(rval.m_path) + 1];
194  strcpy(m_path, rval.m_path);
195 
196  /* Obtain a handle to an already loaded module */
197  dlerror();
198  m_handle = dlopen(m_path, RTLD_LOCAL | RTLD_LAZY | RTLD_NOLOAD);
199  if ( unlikely(m_handle == NULL) )
200  throw exception("failed to link plugin '%s' (%s)", m_path, dlerror());
201 
202  util::dbg_info("plugin '%s' linked", m_path);
203  return *this;
204 }
205 
206 
225 modsym_t plugin::resolve(const i8 *nm, const i8 *scope) const
226 {
227  if ( unlikely(m_handle == NULL) )
228  throw exception("no selected module, this is an inline plugin");
229 
230  if ( unlikely(nm == NULL) )
231  throw exception("invalid argument: nm (=%p)", nm);
232 
233  string *mangled = NULL;
234  if ( likely(scope == NULL) )
235  mangled = new string(nm);
236 
237  /* Mangle the symbol (g++ ABI mangling, Itanium IA64 compatible) */
238  else {
239  string tmp(scope);
240  chain<string> *parts = NULL;
241 
242  try {
243  mangled = new string("_ZN");
244  parts = tmp.split("::");
245 
246  for (u32 i = 0, sz = parts->size(); likely(i < sz); i++) {
247  string *token = parts->at(i);
248  mangled->append("%d%s", token->length(), token->cstr());
249  }
250 
251  mangled->append("%d%s", strlen(nm), nm);
252  mangled->append("EPvS%d_", parts->size() - 1);
253 
254  delete parts;
255  parts = NULL;
256  }
257 
258  catch (...) {
259  delete parts;
260  delete mangled;
261  throw;
262  }
263  }
264 
265  /* Resolve the symbol address */
266  dlerror();
267  void *sym = dlsym(m_handle, mangled->cstr());
268  modsym_t retval = reinterpret_cast<modsym_t> (sym);
269 
270  i8 *err = dlerror();
271  if ( unlikely(err != NULL) ) {
272  exception x(
273  "failed to resolve symbol %s in object '%s' (%s)",
274  mangled->cstr(),
275  m_path,
276  err
277  );
278 
279  delete mangled;
280  throw x;
281  }
282 
283  delete mangled;
284  return retval;
285 }
286 
287 
297 inline plugin& plugin::begin(void *this_fn, void *call_site) const
298 {
299  __D_ASSERT(m_begin != NULL);
300  if ( likely(m_begin != NULL) )
301  m_begin(this_fn, call_site);
302 
303  return const_cast<plugin&> (*this);
304 }
305 
306 
316 inline plugin& plugin::end(void *this_fn, void *call_site) const
317 {
318  __D_ASSERT(m_end != NULL);
319  if ( likely(m_end != NULL) )
320  m_end(this_fn, call_site);
321 
322  return const_cast<plugin&> (*this);
323 }
324 
325 }
326 
modsym_t m_end
Instrumentation ending callback.
Definition: plugin.hpp:50
virtual string & append(const string &)
Append a string.
Definition: string.cpp:404
virtual plugin & begin(void *, void *) const
Begin instrumenting a function.
Definition: plugin.cpp:297
virtual T * at(u32) const
Get the node data pointer at a chain offset.
Definition: chain.hpp:440
virtual plugin * clone() const
Object virtual copy constructor.
Definition: plugin.cpp:145
virtual u32 size() const
Get the chain size (node count)
Definition: chain.hpp:276
virtual const i8 * path() const
Get the module file path.
Definition: plugin.cpp:156
char i8
8-bit signed integer
Definition: config.hpp:72
Function instrumentation plugin.
Definition: plugin.hpp:42
#define likely(expr)
Offer a hint (positive) to the pipeline branch predictor.
Definition: config.hpp:344
virtual plugin & destroy()
Object deconstruction.
Definition: plugin.cpp:18
virtual plugin & operator=(const plugin &)
Assignment operator.
Definition: plugin.cpp:172
virtual ~plugin()
Object destructor.
Definition: plugin.cpp:127
modsym_t m_begin
Instrumentation starting callback.
Definition: plugin.hpp:48
i8 * m_path
Module file path.
Definition: plugin.hpp:52
virtual const i8 * cstr() const
Get the C-string equivalent.
Definition: string.cpp:211
void(* modsym_t)(void *, void *)
Plugin callback.
Definition: config.hpp:152
Lightweight string buffer class (for ISO-8859-1 text)
Definition: string.hpp:36
unsigned int u32
32-bit unsigned integer
Definition: config.hpp:102
virtual u32 length() const
Get the character count.
Definition: string.cpp:222
virtual modsym_t resolve(const i8 *, const i8 *=NULL) const
Resolve a module symbol.
Definition: plugin.cpp:225
plugin(const i8 *, const i8 *=NULL)
Object constructor.
Definition: plugin.cpp:44
void * m_handle
DSO handle (as provided by dlopen)
Definition: plugin.hpp:54
This class is a throwable with a textual description of an error.
Definition: exception.hpp:26
virtual chain< string > * split(const string &, bool=true, bool=false) const
Tokenize using a POSIX extended regular expression.
Definition: string.cpp:642
#define unlikely(expr)
Offer a hint (negative) to the pipeline branch predictor.
Definition: config.hpp:349
static void dbg_info(const i8 *,...)
Print an informational debug message on the standard error stream.
Definition: util.cpp:680
virtual plugin & end(void *, void *) const
End a function instrumentation.
Definition: plugin.cpp:316
#define __D_ASSERT(x)
Assertion macro.
Definition: config.hpp:268