1 | /* |
2 | * print_stack.hpp |
3 | * |
4 | * Created on: Feb 12, 2017 |
5 | * Author: i-bird |
6 | */ |
7 | |
8 | #ifndef OPENFPM_DATA_SRC_UTIL_PRINT_STACK_HPP_ |
9 | #define OPENFPM_DATA_SRC_UTIL_PRINT_STACK_HPP_ |
10 | |
11 | #include <sstream> |
12 | #include <cstdio> |
13 | #include <iostream> |
14 | #include <memory> |
15 | #include <stdexcept> |
16 | #include <string> |
17 | #include <array> |
18 | #ifndef __CYGWIN__ |
19 | #include <execinfo.h> |
20 | #endif |
21 | |
22 | extern std::string program_name; |
23 | |
24 | /*! \brief Execute a command getting the std::cout |
25 | * |
26 | * |
27 | */ |
28 | static inline std::string exec(const char* cmd) |
29 | { |
30 | std::array<char, 128> buffer; |
31 | std::string result; |
32 | std::shared_ptr<FILE> pipe(popen(cmd, "r" ), pclose); |
33 | if (!pipe) throw std::runtime_error("popen() failed!" ); |
34 | while (!feof(pipe.get())) |
35 | { |
36 | if (fgets(buffer.data(), 128, pipe.get()) != NULL) |
37 | result += buffer.data(); |
38 | } |
39 | return result; |
40 | } |
41 | |
42 | /*! \brief Print the stack trace |
43 | * |
44 | * |
45 | */ |
46 | static inline void print_stack() |
47 | { |
48 | #if defined(PRINT_STACKTRACE) && !defined(__CYGWIN__) |
49 | |
50 | void *trace[256]; |
51 | |
52 | int ncall = backtrace(trace,256); |
53 | char ** messages = backtrace_symbols(trace, ncall); |
54 | |
55 | std::stringstream str; |
56 | |
57 | str << "\033[1;31m*******************************************\033[0m" << std::endl; |
58 | str << "\033[1;31m*********** STACK TRACE *******************\033[0m" << std::endl; |
59 | str << "\033[1;31m*******************************************\033[0m" << std::endl; |
60 | |
61 | str << "\033[1mThe stack trace indicate where in the code happened the error the error " << |
62 | "is in general detected inside the library. In order to find the position " << |
63 | "in your code, follow from top to bottom the list of calls until you find " << |
64 | "a source code familiar to you.\033[0m" << std::endl; |
65 | |
66 | std::string translators[]={"eu-addr2line" ,"addr2line" }; |
67 | std::string translator; |
68 | |
69 | for (size_t i = 0 ; i < sizeof(translators)/sizeof(std::string) ; i++) |
70 | { |
71 | // for for the best address to source code translator |
72 | char syscom[256]; |
73 | sprintf(syscom,"%s --version" ,translators[i].c_str()); |
74 | |
75 | std::string ss = exec(syscom); |
76 | size_t found = ss.find("command not found" ); |
77 | if (found == std::string::npos) |
78 | { |
79 | // command exist |
80 | translator = translators[i]; |
81 | str << "Using translator: " << translator << std::endl; |
82 | break; |
83 | } |
84 | } |
85 | |
86 | if (translator.size() == 0) |
87 | { |
88 | str << "In order to have a more detailed stack-trace with function name and precise location in the source code" << |
89 | "Please install one of the following utils: " ; |
90 | |
91 | str << translators[0]; |
92 | |
93 | for (size_t i = 1 ; i < sizeof(translators)/sizeof(std::string) ; i++) |
94 | str << "," << translators[i]; |
95 | } |
96 | |
97 | for (int i = 0 ; i < ncall ; i++) |
98 | { |
99 | str << "\033[1m" << "CALL(" << i << ")" << "\033[0m" << " Address: " << trace[i] << " " << messages[i] << " " ; |
100 | |
101 | if (translator.size() != 0) |
102 | { |
103 | char syscom[256]; |
104 | sprintf(syscom,"%s %p -f --demangle -e %s" ,translator.c_str(), trace[i],program_name.c_str()); //last parameter is the name of this app |
105 | |
106 | std::string ss = exec(syscom); |
107 | std::stringstream sss(ss); |
108 | std::string sfunc; |
109 | std::string sloc; |
110 | std::getline(sss,sfunc,'\n'); |
111 | std::getline(sss,sloc,'\n'); |
112 | str << std::endl; |
113 | str << "\033[35m" << "Function:" << std::endl << sfunc << "\033[0m" << std::endl; |
114 | str << "\033[1;31m" << "Location:" << std::endl << sloc << "\033[0m" << std::endl; |
115 | } |
116 | else |
117 | { |
118 | str << std::endl; |
119 | } |
120 | } |
121 | |
122 | std::cerr << str.str() << std::endl; |
123 | |
124 | #else |
125 | |
126 | std::cerr << "Stack trace deactivated, use #define PRINT_STACKTRACE to activate" << std::endl; |
127 | |
128 | #endif |
129 | } |
130 | |
131 | |
132 | |
133 | #endif /* OPENFPM_DATA_SRC_UTIL_PRINT_STACK_HPP_ */ |
134 | |