routine_tracer.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. #include "routine_tracer.h"
  2. #include "simulator.h"
  3. #include "magic_server.h"
  4. #include "config.hpp"
  5. #include "routine_tracer_print.h"
  6. #include "routine_tracer_ondemand.h"
  7. #include "routine_tracer_funcstats.h"
  8. #include "memory_tracker.h"
  9. #include <cstring>
  10. RoutineTracerThread::RoutineTracerThread(Thread *thread)
  11. : m_thread(thread)
  12. {
  13. Sim()->getHooksManager()->registerHook(HookType::HOOK_ROI_BEGIN, __hook_roi_begin, (UInt64)this);
  14. Sim()->getHooksManager()->registerHook(HookType::HOOK_ROI_END, __hook_roi_end, (UInt64)this);
  15. }
  16. RoutineTracerThread::~RoutineTracerThread()
  17. {
  18. }
  19. void RoutineTracerThread::routineEnter(IntPtr eip, IntPtr esp, IntPtr callEip)
  20. {
  21. ScopedLock sl(m_lock);
  22. routineEnter_unlocked(eip, esp, callEip);
  23. }
  24. void RoutineTracerThread::routineEnter_unlocked(IntPtr eip, IntPtr esp, IntPtr callEip)
  25. {
  26. if (m_stack.size())
  27. if (Sim()->getMagicServer()->inROI())
  28. functionChildEnter(m_stack.back(), eip);
  29. m_stack.push_back(eip);
  30. m_last_esp = esp;
  31. if (Sim()->getMagicServer()->inROI())
  32. functionEnter(eip, callEip);
  33. }
  34. void RoutineTracerThread::routineExit(IntPtr eip, IntPtr esp)
  35. {
  36. ScopedLock sl(m_lock);
  37. if (m_stack.size() == 0)
  38. return;
  39. bool found = true;
  40. if (m_stack.back() != eip)
  41. {
  42. // If we are returning from a function that's not at the top of the stack, search for it further down
  43. found = unwindTo(eip);
  44. }
  45. if (!found)
  46. {
  47. // Mismatch, ignore
  48. }
  49. else
  50. {
  51. // Unwound into eip, now exit it
  52. if (Sim()->getMagicServer()->inROI())
  53. functionExit(eip);
  54. m_stack.pop_back();
  55. }
  56. m_last_esp = esp;
  57. if (m_stack.size())
  58. if (Sim()->getMagicServer()->inROI())
  59. functionChildExit(m_stack.back(), eip);
  60. }
  61. void RoutineTracerThread::routineAssert(IntPtr eip, IntPtr esp)
  62. {
  63. ScopedLock sl(m_lock);
  64. if (m_stack.size() == 0)
  65. {
  66. // Newly created thread just jumps into the first routine
  67. routineEnter_unlocked(eip, esp, 0);
  68. }
  69. else if (m_stack.back() == eip)
  70. {
  71. // We are where we think we are, no action
  72. }
  73. else if (esp <= m_last_esp)
  74. {
  75. // Stack grew (downwards), or stayed constant (tail call): we entered a new function
  76. routineEnter_unlocked(eip, esp, 0);
  77. }
  78. else
  79. {
  80. bool found = unwindTo(eip);
  81. if (!found)
  82. {
  83. // We now seem to be in a function we haven't been before, enter it (tail call elimination?)
  84. routineEnter_unlocked(eip, esp, 0);
  85. }
  86. else
  87. {
  88. // Jumped back into a function further down the stack (longjmp?)
  89. // unwindTo has already popped the stack
  90. m_last_esp = esp;
  91. }
  92. // After all this, the current function should be at the top of the stack
  93. LOG_ASSERT_ERROR(m_stack.back() == eip, "Expected to be in function %lx but now in %lx", eip, m_stack.back());
  94. }
  95. }
  96. bool RoutineTracerThread::unwindTo(IntPtr eip)
  97. {
  98. for(CallStack::reverse_iterator it = m_stack.rbegin(); it != m_stack.rend(); ++it)
  99. {
  100. if (*it == eip)
  101. {
  102. // We found this eip further down the stack: unwind
  103. while(m_stack.back() != eip)
  104. {
  105. if (Sim()->getMagicServer()->inROI())
  106. functionExit(m_stack.back());
  107. m_stack.pop_back();
  108. if (Sim()->getMagicServer()->inROI())
  109. functionChildExit(m_stack.back(), eip);
  110. }
  111. return true;
  112. }
  113. }
  114. return false;
  115. }
  116. void RoutineTracerThread::hookRoiBegin()
  117. {
  118. ScopedLock sl(m_lock);
  119. IntPtr eip_parent = 0;
  120. for(CallStack::iterator it = m_stack.begin(); it != m_stack.end(); ++it)
  121. {
  122. if (eip_parent)
  123. functionChildEnter(eip_parent, *it);
  124. functionEnter(*it, 0);
  125. eip_parent = *it;
  126. }
  127. }
  128. void RoutineTracerThread::hookRoiEnd()
  129. {
  130. ScopedLock sl(m_lock);
  131. // Call functionExit for all functions that are left on the stack.
  132. // Since functionExit might use m_stack we need to keep it up-to-date by popping items off,
  133. // we'll use stack_save to remember them and restore m_stack to its original state on exit.
  134. CallStack stack_save;
  135. IntPtr eip_child = 0;
  136. while(m_stack.size())
  137. {
  138. if (eip_child)
  139. functionChildExit(m_stack.back(), eip_child);
  140. functionExit(m_stack.back());
  141. eip_child = m_stack.back();
  142. stack_save.push_back(m_stack.back());
  143. m_stack.pop_back();
  144. }
  145. while(stack_save.size())
  146. {
  147. m_stack.push_back(stack_save.back());
  148. stack_save.pop_back();
  149. }
  150. }
  151. RoutineTracer::Routine::Routine(IntPtr eip, const char *name, const char *imgname, IntPtr offset, int column, int line, const char *filename)
  152. : m_eip(eip)
  153. , m_name(NULL)
  154. , m_imgname(NULL)
  155. , m_filename(NULL)
  156. , m_location(NULL)
  157. {
  158. updateLocation(name, imgname, offset, column, line, filename);
  159. }
  160. void RoutineTracer::Routine::updateLocation(const char *name, const char *imgname, IntPtr offset, int column, int line, const char *filename)
  161. {
  162. if (m_name)
  163. free(m_name);
  164. if (m_imgname)
  165. free(m_imgname);
  166. if (m_filename)
  167. free(m_filename);
  168. if (m_location)
  169. free(m_location);
  170. m_name = strdup(name);
  171. m_imgname = strdup(imgname);
  172. m_filename = strdup(filename);
  173. m_offset = offset;
  174. m_column = column;
  175. m_line = line;
  176. char location[4096];
  177. snprintf(location, 4095, "%s:%" PRIdPTR ":%s:%d:%d", imgname, offset, filename, line, column);
  178. location[4095] = '\0';
  179. m_location = strdup(location);
  180. }
  181. RoutineTracer::RoutineTracer()
  182. {
  183. }
  184. RoutineTracer::~RoutineTracer()
  185. {
  186. }
  187. RoutineTracer* RoutineTracer::create()
  188. {
  189. String type = Sim()->getCfg()->getString("routine_tracer/type");
  190. if (type == "none")
  191. return NULL;
  192. else if (type == "print")
  193. return new RoutineTracerPrint::RtnMaster();
  194. else if (type == "ondemand")
  195. return new RoutineTracerOndemand::RtnMaster();
  196. else if (type == "funcstats")
  197. return new RoutineTracerFunctionStats::RtnMaster();
  198. else if (type == "memory_tracker")
  199. return new MemoryTracker::RoutineTracer();
  200. else
  201. LOG_PRINT_ERROR("Unknown routine tracer type %s", type.c_str());
  202. }