libcsdbg  1.28
C++ exception (and generic) stack trace debug library
tracer.cpp
Go to the documentation of this file.
1 #include "../include/tracer.hpp"
2 #include "../include/util.hpp"
3 
10 namespace csdbg {
11 
12 /* Static member variable definition */
13 
14 tracer *tracer::m_iface = NULL;
15 
16 
17 /* Link the instrumentation functions with C-style linking */
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
36 void __cyg_profile_func_enter(void *this_fn, void *call_site)
37 {
38  __D_ASSERT(this_fn != NULL);
39  __D_ASSERT(call_site != NULL);
40 
41  util::lock();
42  tracer *iface = tracer::interface();
43 
44  __D_ASSERT(iface != NULL);
45  if ( unlikely(iface == NULL) ) {
46  util::unlock();
47  return;
48  }
49 
50 #ifdef CSDBG_WITH_PLUGIN
51  /* Call all plugin enter functions in the order they were registered */
52  for (u32 i = 0, sz = iface->plugin_count(); likely(i < sz); i++)
53  try {
54  iface->get_plugin(i)->begin(this_fn, call_site);
55  }
56 
57  catch (exception &x) {
58  std::cerr << x;
59  }
60 
61  catch (std::exception &x) {
62  std::cerr << x;
63  }
64 
65  catch (...) {
66  util::header(std::cerr, "x");
67  std::cerr << "plugin " << std::dec << i << ": unidentified exception\r\n";
68  }
69 #endif
70 
71  try {
72  mem_addr_t addr = reinterpret_cast<mem_addr_t> (this_fn);
73  mem_addr_t site = reinterpret_cast<mem_addr_t> (call_site);
74  process *proc = iface->proc();
75 
76 #ifdef CSDBG_WITH_FILTER
77  mem_addr_t base = 0;
78  const i8 *path = proc->ilookup(addr, base);
79 
80  /* Call all the module filters in the order they were registered */
81  if ( likely(path != NULL) )
82  for (u32 i = 0, sz = iface->filter_count(); likely(i < sz); i++) {
83  filter *filt = iface->get_filter(i);
84  if ( likely(filt->mode()) )
85  continue;
86 
87  if ( unlikely(filt->apply(path)) ) {
88  util::unlock();
89  return;
90  }
91  }
92 #endif
93 
94  /*
95  * Lookup the process namespace to resolve the called function symbol. If it
96  * gets resolved update the simulated call stack of the current thread
97  */
98  const i8 *nm = proc->lookup(addr);
99  if ( likely(nm != NULL) ) {
100 #ifdef CSDBG_WITH_FILTER
101  /* Call all the symbol filters in the order they were registered */
102  for (u32 i = 0, sz = iface->filter_count(); likely(i < sz); i++) {
103  filter *filt = iface->get_filter(i);
104  if ( likely(!filt->mode()) )
105  continue;
106 
107  if ( unlikely(filt->apply(nm)) ) {
108  util::unlock();
109  return;
110  }
111  }
112 #endif
113 
114  proc->current_thread()->called(addr, site, nm);
115  }
116 
117  util::unlock();
118  return;
119  }
120 
121  catch (exception &x) {
122  std::cerr << x;
123  }
124 
125  catch (std::exception &x) {
126  std::cerr << x;
127  }
128 
129  util::unlock();
130  exit(EXIT_FAILURE);
131 }
132 
133 
147 void __cyg_profile_func_exit(void *this_fn, void *call_site)
148 {
149  __D_ASSERT(this_fn != NULL);
150  __D_ASSERT(call_site != NULL);
151 
152  util::lock();
153  tracer *iface = tracer::interface();
154 
155  __D_ASSERT(iface != NULL);
156  if ( unlikely(iface == NULL) ) {
157  util::unlock();
158  return;
159  }
160 
161 #ifdef CSDBG_WITH_PLUGIN
162  /* Call all plugin exit functions in the reverse order they were registered */
163  for (i32 i = iface->plugin_count() - 1; likely(i >= 0); i--)
164  try {
165  iface->get_plugin(i)->end(this_fn, call_site);
166  }
167 
168  catch (exception &x) {
169  std::cerr << x;
170  }
171 
172  catch (std::exception &x) {
173  std::cerr << x;
174  }
175 
176  catch (...) {
177  util::header(std::cerr, "x");
178  std::cerr << "plugin " << std::dec << i << ": unidentified exception\r\n";
179  }
180 #endif
181 
182  try {
183  mem_addr_t addr = reinterpret_cast<mem_addr_t> (this_fn);
184  process *proc = iface->proc();
185 
186 #ifdef CSDBG_WITH_FILTER
187  mem_addr_t base = 0;
188  const i8 *path = proc->ilookup(addr, base);
189 
190  /* Call all the module filters in the order they were registered */
191  if ( likely(path != NULL) )
192  for (u32 i = 0, sz = iface->filter_count(); likely(i < sz); i++) {
193  filter *filt = iface->get_filter(i);
194  if ( likely(filt->mode()) )
195  continue;
196 
197  if ( unlikely(filt->apply(path)) ) {
198  util::unlock();
199  return;
200  }
201  }
202 #endif
203 
204  /*
205  * Lookup the process namespace to resolve the returning function symbol. If
206  * it gets resolved update the simulated call stack of the current thread
207  */
208  const i8 *nm = proc->lookup(addr);
209  if ( likely(nm != NULL) ) {
210 #ifdef CSDBG_WITH_FILTER
211  /* Call all the symbol filters in the order they were registered */
212  for (u32 i = 0, sz = iface->filter_count(); likely(i < sz); i++) {
213  filter *filt = iface->get_filter(i);
214  if ( likely(!filt->mode()) )
215  continue;
216 
217  if ( unlikely(filt->apply(nm)) ) {
218  util::unlock();
219  return;
220  }
221  }
222 #endif
223 
224  proc->current_thread()->returned();
225  }
226 
227  util::unlock();
228  return;
229  }
230 
231  catch (exception x) {
232  std::cerr << x;
233  }
234 
235  catch (std::exception x) {
236  std::cerr << x;
237  }
238 
239  util::unlock();
240  exit(EXIT_FAILURE);
241 }
242 
243 #ifdef __cplusplus
244 }
245 #endif
246 
247 
254 {
255  /* Initialize libbfd internals */
256  bfd_init();
257 
258  try {
259  m_iface = new tracer;
260 
261  /* Load the symbol table of the executable */
262  const i8 *path = util::exec_path();
263  m_iface->m_proc->add_module(path, 0);
264  delete[] path;
265 
266  /* Load the symbol tables of the selected DSO */
268  dl_iterate_phdr(on_dso_load, libs);
269  delete libs;
270 
271  util::dbg_info("libcsdbg.so.%d.%d initialized", g_major, g_minor);
272  return;
273  }
274 
275  catch (exception &x) {
276  std::cerr << x;
277  }
278 
279  catch (std::exception &x) {
280  std::cerr << x;
281  }
282 
283  exit(EXIT_FAILURE);
284 }
285 
286 
291 {
292  delete m_iface;
293  m_iface = NULL;
294  util::dbg_info("libcsdbg.so.%d.%d finalized", g_major, g_minor);
295 }
296 
297 
323 i32 tracer::on_dso_load(dl_phdr_info *dso, size_t sz, void *arg)
324 {
325  try {
326  if ( unlikely(dso == NULL) )
327  throw exception("invalid argument: dso (=%p)", dso);
328 
329  /* If the DSO path is undefined */
330  string path(dso->dlpi_name);
331  if ( unlikely(path.length() == 0) )
332  throw exception("undefined DSO path");
333 
334  /* If the DSO has no segments */
335  if ( unlikely(dso->dlpi_phnum == 0) )
336  throw exception("'%s' has 0 segments", path.cstr());
337 
338  /* Check if the DSO is filtered out */
339  bool found = false;
340  if ( likely(arg != NULL) ) {
341  chain<string> *filters = static_cast<chain<string>*> (arg);
342 
343  for (u32 i = 0, sz = filters->size(); likely(i < sz); i++) {
344  string *filt = filters->at(i);
345  if ( unlikely(path.match(*filt)) ) {
346  found = true;
347  break;
348  }
349  }
350  }
351  else
352  found = true;
353 
354  if ( likely(!found) ) {
355  util::dbg_warn("filtered out '%s'", path.cstr());
356  return 0;
357  }
358 
359  /* Load the DSO symbol table */
360  mem_addr_t base = dso->dlpi_addr + dso->dlpi_phdr[0].p_vaddr;
361  m_iface->m_proc->add_module(path.cstr(), base);
362  }
363 
364  catch (exception &x) {
365  util::dbg_error("in tracer::%s(): %s", __FUNCTION__, x.msg());
366  }
367 
368  catch (std::exception &x) {
369  util::dbg_error("in tracer::%s(): %s", __FUNCTION__, x.what());
370  }
371 
372  return 0;
373 }
374 
375 
398 string& tracer::addr2line(string &dst, const i8 *path, mem_addr_t addr)
399 {
400  __D_ASSERT(path != NULL);
401  if ( unlikely(path == NULL) )
402  return dst;
403 
404  FILE *pipe = NULL;
405  try {
406  /* Command to be executed by the child process */
407  string cmd("addr2line -se %s 0x%x", path, addr);
408 
409  /* Open a readonly pipe to the child process */
410  pipe = popen(cmd.cstr(), "r");
411  if ( unlikely(pipe == NULL) )
412  throw exception(
413  "failed to open pipe for command '%s' (errno %d - %s)",
414  cmd.cstr(),
415  errno,
416  strerror(errno)
417  );
418 
419  /* Read a line of output from the pipe to a buffer */
420  string buf;
421  i8 ch = fgetc(pipe);
422  while ( likely(ch != '\n' && ch != EOF) ) {
423  buf.append(ch);
424  ch = fgetc(pipe);
425  }
426 
427  if ( unlikely(ferror(pipe) != 0) )
428  throw exception("failed to read pipe for command '%s'", cmd.cstr());
429 
430  if ( likely(buf.cmp("??:0") != 0) )
431  dst.append(" (%s)", buf.cstr());
432  }
433 
434  catch (exception &x) {
435  util::dbg_error("in tracer::%s(): %s", __FUNCTION__, x.msg());
436  }
437 
438  catch (std::exception &x) {
439  util::dbg_error("in tracer::%s(): %s", __FUNCTION__, x.what());
440  }
441 
442  if ( likely(pipe != NULL) )
443  pclose(pipe);
444 
445  return dst;
446 }
447 
448 
455 try:
456 m_proc(NULL)
457 #ifdef CSDBG_WITH_PLUGIN
458 ,m_plugins(NULL)
459 #endif
460 #ifdef CSDBG_WITH_FILTER
461 ,m_filters(NULL)
462 #endif
463 {
464 #ifdef CSDBG_WITH_PLUGIN
465  m_plugins = new chain<plugin>;
466 #endif
467 #ifdef CSDBG_WITH_FILTER
468  m_filters = new chain<filter>;
469 #endif
470 
471  m_proc = new process;
472 }
473 
474 catch (...) {
475  destroy();
476 }
477 
478 
487 try:
488 m_proc(NULL)
489 #ifdef CSDBG_WITH_PLUGIN
490 ,m_plugins(NULL)
491 #endif
492 #ifdef CSDBG_WITH_FILTER
493 ,m_filters(NULL)
494 #endif
495 {
496 #ifdef CSDBG_WITH_PLUGIN
497  m_plugins = src.m_plugins->clone();
498 #endif
499 #ifdef CSDBG_WITH_FILTER
500  m_filters = new chain<filter>;
501 #endif
502 
503  m_proc = src.m_proc->clone();
504 }
505 
506 catch (...) {
507  destroy();
508 }
509 
510 
515 {
516  destroy();
517 }
518 
519 
527 inline tracer* tracer::clone() const
528 {
529  return new tracer(*this);
530 }
531 
532 
543 {
544  if ( unlikely(this == &rval) )
545  return *this;
546 
547 #ifdef CSDBG_WITH_PLUGIN
548  *m_plugins = *rval.m_plugins;
549 #endif
550 
551  *m_proc = *rval.m_proc;
552  return *this;
553 }
554 
555 
562 {
563 #ifdef CSDBG_WITH_PLUGIN
564  delete m_plugins;
565  m_plugins = NULL;
566 #endif
567 #ifdef CSDBG_WITH_FILTER
568  delete m_filters;
569  m_filters = NULL;
570 #endif
571 
572  delete m_proc;
573  m_proc = NULL;
574  return *this;
575 }
576 
577 
587 std::ostream& operator<<(std::ostream &lval, tracer &rval)
588 {
589  util::lock();
590  try {
591  string buf;
592  rval.trace(buf);
593  lval << buf;
594 
595  util::unlock();
596  return lval;
597  }
598 
599  catch (exception &x) {
600  lval << x;
601  }
602 
603  catch (std::exception &x) {
604  lval << x;
605  }
606 
607  rval.unwind();
608  util::unlock();
609  return lval;
610 }
611 
612 
618 inline process* tracer::proc() const
619 {
620  return m_proc;
621 }
622 
623 
630 {
631  if ( unlikely(m_iface == NULL || m_iface->m_proc == NULL) )
632  return NULL;
633 
634  else if ( unlikely(m_iface->m_proc->module_count() == 0) )
635  return NULL;
636 
637  return m_iface;
638 }
639 
640 
658 tracer& tracer::trace(string &dst)
659 {
660  /* If an exception occurs, unwind, unlock and rethrow it */
661  try {
662  util::lock();
663  thread *thr = m_proc->current_thread();
664 
665  const i8 *nm = thr->name();
666  if ( likely(nm == NULL) )
667  nm = "anonymous";
668  dst.append("at %s thread (0x%lx) {\r\n", nm, thr->handle());
669 
670  /* For each function call */
671  for (i32 i = thr->lag(); likely(i >= 0); i--) {
672  const call *cur = thr->backtrace(i);
673  dst.append(" at %s", cur->name());
674 
675  /* Append addr2line debug information */
676  u32 prev = i + 1;
677  if ( likely (prev < thr->call_depth()) ) {
678  const call *caller = thr->backtrace(prev);
679  mem_addr_t base = 0;
680 
681  const i8 *path = m_proc->ilookup(caller->addr(), base);
682  addr2line(dst, path, cur->site() - base);
683  }
684 
685  dst.append("\r\n");
686  }
687 
688  dst.append("}\r\n");
689  thr->unwind();
690  util::unlock();
691  return *this;
692  }
693 
694  catch (...) {
695  unwind();
696  util::unlock();
697  throw;
698  }
699 }
700 
701 
716 tracer& tracer::trace(string &dst, pthread_t id) const
717 {
718  /* If an exception occurs, unlock and rethrow it */
719  try {
720  util::lock();
721  thread *thr = m_proc->get_thread(id);
722  if ( unlikely(thr == NULL) ) {
723  util::unlock();
724  return const_cast<tracer&> (*this);
725  }
726 
727  const i8 *nm = thr->name();
728  if ( likely(nm == NULL) )
729  nm = "anonymous";
730  dst.append("at %s thread (0x%lx) {\r\n", nm, thr->handle());
731 
732  /* For each function call */
733  for (i32 i = thr->call_depth() - 1; likely(i >= 0); i--) {
734  const call *cur = thr->backtrace(i);
735  dst.append(" at %s", cur->name());
736 
737  /* Append addr2line debug information */
738  u32 prev = i + 1;
739  if ( likely (prev < thr->call_depth()) ) {
740  const call *caller = thr->backtrace(prev);
741  mem_addr_t base = 0;
742 
743  const i8 *path = m_proc->ilookup(caller->addr(), base);
744  addr2line(dst, path, cur->site() - base);
745  }
746 
747  dst.append("\r\n");
748  }
749 
750  dst.append("}\r\n");
751  util::unlock();
752  return const_cast<tracer&> (*this);
753  }
754 
755  catch (...) {
756  util::unlock();
757  throw;
758  }
759 }
760 
761 
779 {
780  try {
781  util::lock();
783  util::unlock();
784  return *this;
785  }
786 
787  catch (...) {
788  util::unlock();
789  throw;
790  }
791 }
792 
793 
806 tracer& tracer::dump(string &dst) const
807 {
808  try {
809  util::lock();
810 
811  for (u32 i = 0, sz = m_proc->thread_count(); likely(i < sz); i++) {
812  thread *thr = m_proc->get_thread(i);
813  trace(dst, thr->handle());
814 
815  if ( likely(i < sz - 1) )
816  dst.append("\r\n");
817  }
818 
819  util::unlock();
820  return const_cast<tracer&> (*this);
821  }
822 
823  catch (...) {
824  util::unlock();
825  throw;
826  }
827 }
828 
829 
830 #ifdef CSDBG_WITH_PLUGIN
831 
836 inline u32 tracer::plugin_count() const
837 {
838  return m_plugins->size();
839 }
840 
841 
854 const plugin* tracer::add_plugin(const i8 *path, const i8 *scope)
855 {
856  plugin *retval = NULL;
857  try {
858  util::lock();
859  retval = new plugin(path, scope);
860  m_plugins->add(retval);
861  util::unlock();
862  return retval;
863  }
864 
865  catch (...) {
866  delete retval;
867  util::unlock();
868  throw;
869  }
870 }
871 
872 
885 {
886  plugin *retval = NULL;
887  try {
888  util::lock();
889  retval = new plugin(bgn, end);
890  m_plugins->add(retval);
891  util::unlock();
892  return retval;
893  }
894 
895  catch (...) {
896  delete retval;
897  util::unlock();
898  throw;
899  }
900 }
901 
902 
911 {
912  __D_ASSERT(path != NULL);
913  if ( unlikely(path == NULL) )
914  return *this;
915 
916  util::lock();
917  for (u32 i = 0, sz = m_plugins->size(); likely(i < sz); i++) {
918  const plugin *plg = m_plugins->at(i);
919 
920  /* If this is an inline plugin */
921  if ( unlikely(plg->path() == NULL) )
922  continue;
923 
924  if ( unlikely(strcmp(plg->path(), path) == 0) ) {
925  m_plugins->remove(i);
926  break;
927  }
928  }
929 
930  util::unlock();
931  return *this;
932 }
933 
934 
945 {
946  try {
947  util::lock();
948  m_plugins->remove(i);
949  util::unlock();
950  return *this;
951  }
952 
953  catch (...) {
954  util::unlock();
955  throw;
956  }
957 }
958 
959 
967 const plugin* tracer::get_plugin(const i8 *path) const
968 {
969  __D_ASSERT(path != NULL);
970  if ( unlikely(path == NULL) )
971  return NULL;
972 
973  util::lock();
974  for (u32 i = 0, sz = m_plugins->size(); likely(i < sz); i++) {
975  const plugin *plg = m_plugins->at(i);
976 
977  /* If this is an inline plugin */
978  if ( unlikely(plg->path() == NULL) )
979  continue;
980 
981  if ( unlikely(strcmp(plg->path(), path) == 0) ) {
982  util::unlock();
983  return plg;
984  }
985  }
986 
987  util::unlock();
988  return NULL;
989 }
990 
991 
1002 {
1003  try {
1004  util::lock();
1005  const plugin *retval = m_plugins->at(i);
1006  util::unlock();
1007  return retval;
1008  }
1009 
1010  catch (...) {
1011  util::unlock();
1012  throw;
1013  }
1014 }
1015 #endif
1016 
1017 
1018 #ifdef CSDBG_WITH_FILTER
1019 
1025 {
1026  return m_filters->size();
1027 }
1028 
1029 
1044 filter* tracer::add_filter(const i8 *expr, bool icase, bool mode)
1045 {
1046  filter *retval = NULL;
1047  try {
1048  retval = new filter(expr, icase, mode);
1049  m_filters->add(retval);
1050  return retval;
1051  }
1052 
1053  catch (...) {
1054  delete retval;
1055  throw;
1056  }
1057 }
1058 
1059 
1070 {
1071  m_filters->remove(i);
1072  return *this;
1073 }
1074 
1075 
1086 {
1087  return m_filters->at(i);
1088 }
1089 #endif
1090 }
1091 
virtual string & append(const string &)
Append a string.
Definition: string.cpp:404
virtual u32 thread_count() const
Get the active thread count.
Definition: process.cpp:321
virtual plugin & begin(void *, void *) const
Begin instrumenting a function.
Definition: plugin.cpp:297
void __cyg_profile_func_enter(void *this_fn, void *call_site)
In code compiled with -finstrument-functions, g++ injects code to call this function at the beginning...
Definition: tracer.cpp:36
virtual T * at(u32) const
Get the node data pointer at a chain offset.
Definition: chain.hpp:440
virtual const i8 * lookup(mem_addr_t)
Lookup an address to resolve a symbol.
Definition: process.cpp:266
virtual const plugin * get_plugin(const i8 *) const
Get a registered plugin module (DSO)
Definition: tracer.cpp:967
virtual tracer & destroy()
Release object resources.
Definition: tracer.cpp:561
static const i8 * exec_path()
Get the absolute path of the executable.
Definition: util.cpp:87
virtual thread & called(mem_addr_t, mem_addr_t, const i8 *)
Simulate a function call.
Definition: thread.cpp:230
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
virtual pthread_t handle() const
Get the thread handle.
Definition: thread.cpp:109
void __cyg_profile_func_exit(void *this_fn, void *call_site)
In code compiled with -finstrument-functions, g++ injects code to call this function at the end of in...
Definition: tracer.cpp:147
char i8
8-bit signed integer
Definition: config.hpp:72
std::ostream & operator<<(std::ostream &, const std::exception &)
Stream insertion operator for std::exception objects.
Definition: exception.cpp:23
virtual tracer & operator=(const tracer &)
Assignment operator.
Definition: tracer.cpp:542
virtual u32 filter_count() const
Get the number of registered filters.
Definition: tracer.cpp:1024
Function instrumentation plugin.
Definition: plugin.hpp:42
static tracer * interface()
Get the interface object.
Definition: tracer.cpp:629
A tracer object is the default interface to libcsdbg for the instrumentation functions and for the li...
Definition: tracer.hpp:34
static const u16 g_minor
Library version minor.
Definition: config.hpp:195
static i32 on_dso_load(dl_phdr_info *, size_t, void *)
This is a dl_iterate_phdr (libdl) callback, called for each linked shared object. It loads the symbol...
Definition: tracer.cpp:323
virtual filter * get_filter(u32) const
Get a registered filter.
Definition: tracer.cpp:1085
virtual thread * get_thread(pthread_t) const
Get a thread by ID.
Definition: process.cpp:376
static const i8 g_libs_env[]
DSO filtering shell variable.
Definition: config.hpp:185
chain< plugin > * m_plugins
Instrumentation plugins.
Definition: tracer.hpp:48
process * m_proc
Process handle.
Definition: tracer.hpp:45
#define likely(expr)
Offer a hint (positive) to the pipeline branch predictor.
Definition: config.hpp:344
static void dbg_warn(const i8 *,...)
Print a warning debug message on the standard error stream.
Definition: util.cpp:703
This class represents a program/library runtime function call.
Definition: call.hpp:17
virtual bool mode() const
Get the filter type.
Definition: filter.cpp:79
virtual tracer * clone() const
Object virtual copy constructor.
Definition: tracer.cpp:527
virtual ~tracer()
Object destructor.
Definition: tracer.cpp:514
virtual thread & returned()
Simulate a function return.
Definition: thread.cpp:262
static void lock()
Lock the global access mutex.
Definition: util.cpp:397
virtual bool apply(const i8 *) const
Apply the filter to a function signature or a module absolute path.
Definition: filter.cpp:147
This class represents a thread of execution in the instrumented process.
Definition: thread.hpp:27
virtual const i8 * msg() const
Get the exception message.
Definition: exception.cpp:123
static void unlock()
Unlock the global access mutex.
Definition: util.cpp:406
virtual tracer & trace(string &)
Create an exception stack trace using the simulated call stack of the current thread. The trace is appended to a string and the simulated stack is unwinded.
Definition: tracer.cpp:658
virtual filter * add_filter(const i8 *, bool, bool=true)
Register a filter.
Definition: tracer.cpp:1044
virtual i32 cmp(const string &, bool=false) const
Compare to another string.
Definition: string.cpp:470
virtual thread & unwind()
Unwind the simulated call stack to meet the real call stack.
Definition: thread.cpp:283
static void dbg_error(const i8 *,...)
Print an error debug message on the standard error stream.
Definition: util.cpp:726
tracer()
Object default constructor.
Definition: tracer.cpp:454
static void on_lib_load() __attribute((constructor))
Library constructor.
Definition: tracer.cpp:253
virtual u32 call_depth() const
Get the size (call depth) of the simulated call stack.
Definition: thread.cpp:196
virtual i32 lag() const
Get the size (call depth) of the simulated call stack with respect to the real call stack...
Definition: thread.cpp:123
virtual tracer & unwind()
Unwind the simulated call stack of the current thread.
Definition: tracer.cpp:778
virtual const i8 * cstr() const
Get the C-string equivalent.
Definition: string.cpp:211
virtual tracer & remove_plugin(const i8 *)
Unregister a plugin module (DSO)
Definition: tracer.cpp:910
void(* modsym_t)(void *, void *)
Plugin callback.
Definition: config.hpp:152
Instrumentation filter.
Definition: filter.hpp:23
virtual mem_addr_t site() const
Get the call site address.
Definition: call.cpp:71
This class represents a process, its entire namespace and thread group.
Definition: process.hpp:29
virtual bool match(const string &, bool=false) const
Match against a POSIX extended regular expression.
Definition: string.cpp:490
virtual const plugin * add_plugin(const i8 *, const i8 *=NULL)
Register a plugin module (DSO)
Definition: tracer.cpp:854
virtual mem_addr_t addr() const
Get the symbol address.
Definition: symbol.cpp:79
virtual process * clone() const
Object virtual copy constructor.
Definition: process.cpp:147
virtual u32 plugin_count() const
Get the number of registered plugins.
Definition: tracer.cpp:836
virtual process & add_module(const i8 *, mem_addr_t)
Add a symbol table to the namespace. The symbol table is loaded from a non stripped objective code fi...
Definition: process.cpp:236
virtual const i8 * name() const
Get the symbol name.
Definition: symbol.cpp:90
unsigned int u32
32-bit unsigned integer
Definition: config.hpp:102
static string & addr2line(string &, const i8 *, mem_addr_t)
Given an address in an objective code file, extract from the gdb-related debug information, the equivalent source code file name and line and append it to a string buffer.
Definition: tracer.cpp:398
int i32
32-bit signed integer
Definition: config.hpp:82
static chain< string > * getenv(const i8 *)
Parse a shell (environment) variable to its components.
Definition: util.cpp:128
virtual const i8 * ilookup(mem_addr_t, mem_addr_t &) const
Inverse lookup. Find the module (executable or DSO library) that defines a symbol and return its path...
Definition: process.cpp:300
virtual tracer & remove_filter(u32)
Unregister a filter.
Definition: tracer.cpp:1069
virtual u32 length() const
Get the character count.
Definition: string.cpp:222
virtual const call * backtrace(u32) const
Peek at the simulated call stack.
Definition: thread.cpp:211
virtual tracer & dump(string &) const
Create multiple stack traces using the simulated call stack of each thread. The traces are appended t...
Definition: tracer.cpp:806
static void header(std::ostream &, const i8 *)
Print a tagged message header on an output stream.
Definition: util.cpp:594
virtual const i8 * name() const
Get the thread name.
Definition: thread.cpp:98
chain< filter > * m_filters
Instrumentation filters.
Definition: tracer.hpp:51
virtual process * proc() const
Get the process handle.
Definition: tracer.cpp:618
unsigned long long mem_addr_t
64-bit memory address
Definition: config.hpp:120
This class is a throwable with a textual description of an error.
Definition: exception.hpp:26
virtual thread * current_thread()
Get the currently executing thread.
Definition: process.cpp:339
virtual u32 module_count() const
Get the number of modules.
Definition: process.cpp:216
#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
static void on_lib_unload() __attribute((destructor))
Library destructor.
Definition: tracer.cpp:290
static const u16 g_major
Library version major.
Definition: config.hpp:190
#define __D_ASSERT(x)
Assertion macro.
Definition: config.hpp:268
static tracer * m_iface
Interface object.
Definition: tracer.hpp:40