fork download
  1.  
  2. #include <iostream>
  3. #include <cassert>
  4. #include <tuple>
  5.  
  6. //Indecies Trick
  7. template <std::size_t... Is>
  8. struct indices {};
  9.  
  10. template <std::size_t N, std::size_t... Is>
  11. struct build_indices
  12. : build_indices<N-1, N-1, Is...> {};
  13.  
  14. template <std::size_t... Is>
  15. struct build_indices<0, Is...> : indices<Is...> {};
  16.  
  17. template <typename Tuple>
  18. using IndicesFor = build_indices<std::tuple_size<Tuple>::value>;
  19.  
  20.  
  21.  
  22.  
  23.  
  24. class stackelement {
  25. stackelement* caller;
  26. stackelement* callee;
  27. static stackelement*& frameptr()
  28. {
  29. static stackelement* frameptr=NULL;
  30. return frameptr;
  31. }
  32. protected:
  33. virtual const char* get_name() const =0;
  34. virtual void printparams(std::ostream& out,
  35. const char* before_params,
  36. const char* between_params,
  37. const char* after_params) const =0;
  38. public:
  39. stackelement()
  40. : caller(frameptr()), callee(NULL)
  41. { frameptr() = this;}
  42. stackelement(const stackelement& r)
  43. : caller(r.caller), callee(r.callee)
  44. {
  45. assert(frameptr() == &r);
  46. frameptr() = this;
  47. }
  48. stackelement& operator=(const stackelement& r) {
  49. assert(frameptr() == &r);
  50. caller = r.caller;
  51. callee = r.callee;
  52. frameptr() = this;
  53. return *this;
  54. }
  55. virtual ~stackelement() {
  56. if (caller)
  57. caller->callee = NULL;
  58. frameptr() = caller;
  59. }
  60. static void print(std::ostream& out,
  61. const char* begin_line="",
  62. const char* before_params=" with ",
  63. const char* between_params=", ",
  64. const char* after_params=".",
  65. const char* end_line="\n") {
  66. stackelement* self = frameptr();
  67. do {
  68. out << begin_line << self->get_name();
  69. self->printparams(out, before_params, between_params, after_params);
  70. out << end_line;
  71. self = self->caller;
  72. } while(self);
  73. }
  74. };
  75.  
  76. template<class first, class...Ps, std::size_t... Is>
  77. std::ostream& _print_tup(std::ostream& out, const std::tuple<first, Ps...>& tup, const char*sep, indices<Is...>)
  78. {
  79. using for_each = int[];
  80. out << std::get<0>(tup);
  81. if (sizeof...(Ps))
  82. for_each{(out<<sep<<std::get<Is+1>(tup),0)...,0};
  83. return out;
  84. }
  85.  
  86. template<class first, class...Rest>
  87. std::ostream& print_tup(std::ostream& out, const std::tuple<first, Rest...>& tup, const char*sep)
  88. {return _print_tup(out,tup,sep,build_indices<sizeof...(Rest)>{});}
  89. template<class first>
  90. std::ostream& print_tup(std::ostream& out, const std::tuple<first>& tup, const char*sep)
  91. {return out << std::get<0>(tup);}
  92. std::ostream& print_tup(std::ostream& out, const std::tuple<>& tup, const char*sep)
  93. {return out;}
  94.  
  95. template<class...Ps>
  96. struct stackinstance : stackelement {
  97. protected:
  98. const char* name;
  99. std::tuple<Ps&...> ps;
  100. public:
  101. template<int N>
  102. stackinstance(const char(&name_)[N], Ps&...Vs)
  103. :name(name_), ps(Vs...) {}
  104. protected:
  105. virtual const char* get_name() const {return name;}
  106. virtual void printparams(std::ostream& out,
  107. const char* before_params,
  108. const char* between_params,
  109. const char* after_params) const
  110. {
  111. out<<before_params;
  112. print_tup(out,ps,between_params);
  113. out<<after_params;
  114. }
  115. };
  116.  
  117. template<int N, class...Ps>
  118. stackinstance<Ps...> StackTrace(const char(&name_)[N], Ps&...Vs)
  119. {return stackinstance<Ps...>(name_, Vs...);}
  120.  
  121. #ifdef __GNUC__
  122. #define __FUNCSIG__ __PRETTY_FUNCTION__
  123. #endif
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137. #include <iostream>
  138. #include <sstream>
  139. #include <exception>
  140. #include <stdexcept>
  141.  
  142. class stack_aware_exception : public std::runtime_error {
  143. std::string get_stack() {
  144. std::stringstream stacktrace;
  145. stackelement::print(stacktrace);
  146. return stacktrace.str();
  147. }
  148. public:
  149. stack_aware_exception() :std::runtime_error(get_stack()) {}
  150. };
  151.  
  152. unsigned thing(unsigned i) {
  153. auto trace = StackTrace(__FUNCSIG__, i);
  154. if (i==10)
  155. throw stack_aware_exception();
  156. else if (i==0)
  157. return i;
  158. return thing(i-1);
  159. }
  160.  
  161. int Foo() {
  162. auto trace = StackTrace(__FUNCSIG__);
  163. return thing(7) + thing(0) + thing(17);
  164. }
  165.  
  166. int Params(int a, std::string s, void* c)
  167. {
  168. auto trace = StackTrace(__FUNCSIG__, a, s, c);
  169. return Foo();
  170. }
  171.  
  172. int main(int argc, char** argv) {
  173. auto trace = StackTrace(__FUNCSIG__, argc, argv);
  174. try {
  175. Params(3, "HI", nullptr);
  176. } catch(const stack_aware_exception& exc) {
  177. std::cout << exc.what();
  178. }
  179. return 0;
  180. }
Success #stdin #stdout 0s 3436KB
stdin
Standard input is empty
stdout
unsigned int thing(unsigned int) with 10.
unsigned int thing(unsigned int) with 11.
unsigned int thing(unsigned int) with 12.
unsigned int thing(unsigned int) with 13.
unsigned int thing(unsigned int) with 14.
unsigned int thing(unsigned int) with 15.
unsigned int thing(unsigned int) with 16.
unsigned int thing(unsigned int) with 17.
int Foo() with .
int Params(int, std::string, void*) with 3, HI, 0.
int main(int, char**) with 1, 0xbffd4eb4.