GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
Globals.h
Go to the documentation of this file.
1#ifndef GLOBALS_H
2#define GLOBALS_H
3
4// NOLINTBEGIN(cppcoreguidelines-macro-usage)
5#define RESET_COLOR "\033[m"
6#define BLUE "\033[1;34m"
7#define YELLOW "\033[1;33m"
8#define GREEN "\033[1;32m"
9#define RED "\033[1;31m"
10#define BLACK "\033[1;30m"
11#define MAGENTA "\033[1;35m"
12#define CYAN "\033[1;36m"
13#define WHITE "\033[1;37m"
14
15#define DBLUE "\033[0;34m"
16#define DYELLOW "\033[0;33m"
17#define DGREEN "\033[0;32m"
18#define DRED "\033[0;31m"
19#define DBLACK "\033[0;30m"
20#define DMAGENTA "\033[0;35m"
21#define DCYAN "\033[0;36m"
22#define DWHITE "\033[0;37m"
23
24#define BG_WHITE "\033[47m"
25#define BG_RED "\033[41m"
26#define BG_GREEN "\033[42m"
27#define BG_YELLOW "\033[43m"
28#define BG_BLUE "\033[44m"
29#define BG_MAGENTA "\033[45m"
30#define BG_CYAN "\033[46m"
31
32#define HIDE_CURSOR "\033[?25l"
33#define SHOW_CURSOR "\033[?25h"
34
35#define ALERTTEXT "\033[47m\033[0;31m"
36// NOLINTEND(cppcoreguidelines-macro-usage)
37
38#if __APPLE__
39#ifdef __CINT__
40#undef __GNUC__
41typedef char __signed;
42typedef char int8_t;
43#endif
44#endif
45
46#if __APPLE__
47//#include <_types/_uint8_t.h>
48#include <_types/_uint16_t.h>
49#include <_types/_uint32_t.h>
50#include <_types/_uint64_t.h>
51#include <sys/_types/_int16_t.h>
52#endif
53
54#include <iostream>
55#include <iomanip>
56#include <stdexcept>
57#include <string>
58#include <cstdio>
59#include <cstdint>
60#include <cstdlib>
61#include <execinfo.h>
62#include <cxxabi.h>
63#include <sstream>
64#include <array>
65#include <memory>
66#include <unistd.h>
67#include <map>
68#include <fstream>
69#include <algorithm>
70
71const std::string& ProgramName();
72
73namespace grsi {
74struct exit_exception : public std::exception {
75public:
76 explicit exit_exception(int c, const char* msg = "") : code(c), message(msg) {}
77 /* virtual const char* what() const throw {
78 // LOG(what); // write to log file
79 return what.c_str();
80 }*/
81
82 const int code; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
83 const char* message;
84};
85
86void SetGRSIEnv();
87
88//-------------------- three function templates that print all arguments into a string
89// this template uses existing stream and appends the last argument to it
90template <typename T>
91void Append(std::ostringstream& stream, const T& tail)
92{
93 // append last argument
94 stream << tail;
95}
96
97// this template uses existing stream and appends to it
98template <typename T, typename... U>
99void Append(std::ostringstream& stream, const T& head, const U&... tail)
100{
101 // append first argument
102 stream << head;
103
104 // reversely call this template (or the one with the last argument)
105 Append(stream, tail...);
106}
107
108// this function typically gets called by user
109template <typename T, typename... U>
110std::string Stringify(const T& head, const U&... tail)
111{
112 // print first arguments to string
113 std::ostringstream stream;
114 stream << head;
115
116 // call the second template (or the third if tail is just one argument)
117 Append(stream, tail...);
118
119 // append a newline
120 stream << std::endl;
121
122 // return resulting string
123 return stream.str();
124}
125
126} // end of namespace grsi
127
128template <typename T>
129inline std::string hex(T val, int width = -1)
130{
131 std::ostringstream str;
132 str << "0x" << std::hex;
133 if(width > 0) {
134 str << std::setfill('0') << std::setw(width);
135 }
136 str << val;
137 if(width > 0) {
138 str << std::setfill(' ');
139 }
140 return str.str();
141}
142
143enum class EVerbosity : std::uint8_t {
144 kQuiet = 0,
145 kBasicFlow = 1,
146 kSubroutines = 2,
147 kLoops = 3,
148 kAll = 4
149};
150
151static inline std::string getexepath()
152{
153 std::array<char, 1024> result{};
154 ssize_t count = readlink("/proc/self/exe", result.data(), sizeof(result) - 1);
155 return {result.data(), static_cast<size_t>((count > 0) ? count : 0)};
156}
157
158static inline std::string sh(const std::string& cmd)
159{
160 std::array<char, 128> buffer{};
161 std::string result;
162 std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
163 if(!pipe) { throw std::runtime_error("popen() failed!"); }
164 while(feof(pipe.get()) == 0) {
165 if(fgets(buffer.data(), 128, pipe.get()) != nullptr) {
166 result += buffer.data();
167 }
168 }
169 return result;
170}
171
172extern std::map<std::string, uint64_t> gAddressOffset;
173
174inline bool FindAddressOffsets(bool update)
175{
176 if(!update && !gAddressOffset.empty()) {
177 std::cerr << "Warning, already have " << gAddressOffset.size() << " address offsets, not checking again!" << std::endl;
178 return false;
179 }
180
181 // need to read /proc/self should be for this process, but doesn't any grsisort libraries?
182 // so read /proc/<PID>/maps instead
183 //std::stringstream mapName;
184 //mapName << "/proc/" << getpid() << "/maps";
185 //std::ifstream procMap(mapName.str());
186 std::ifstream procMap("/proc/self/maps");
187 if(!procMap.is_open()) {
188 std::cerr << "Failed to open \"/proc/self/maps\"" << std::endl;
189 return false;
190 }
191 std::string line;
192 int counter = 0;
193 while(std::getline(procMap, line)) {
194 // line has format
195 // <start address>-<end address> <four letters for permissions> <offset> <device major>:<device minor> <inode> <so-library>
196 // if <inode> is 0 there is no so-library
197 std::stringstream str(line);
198
199 uint64_t startAddress = 0;
200 char dash = '\0';
201 uint64_t endAddress = 0;
202 std::string permissions;
203 uint64_t offset = 0;
204 std::string device;
205 int inode = 0;
206 std::string soLibrary;
207
208 str >> std::hex >> startAddress >> dash >> endAddress >> permissions >> std::dec >> offset >> device >> inode;
209 //std::cout << counter << ": \"" << line << "\" => " << hex(startAddress) << "-" << hex(endAddress) << " (" << permissions << ") " << offset << " [" << device << "] " << inode;
210
211 if(inode != 0) {
212 str >> soLibrary;
213 //std::cout << " {" << soLibrary << "}, " << gAddressOffset.size();
214
215 // we only keep the first starting address
216 if(gAddressOffset.find(soLibrary) == gAddressOffset.end()) {
217 gAddressOffset[soLibrary] = startAddress;
218 //std::cout << ", keeping " << gAddressOffset.size();
219 }
220 }
221 //std::cout << std::endl;
222 ++counter;
223 }
224
225 //if(update) {
226 // std::cout << "Updated to " << gAddressOffset.size() << " entries using " << counter << " lines" << std::endl;
227 //} else {
228 // std::cout << "Got address offset map with " << gAddressOffset.size() << " entries using " << counter << " lines:" << std::endl;
229 // for(auto& iter : gAddressOffset) {
230 // std::cout << hex(iter.second) << " " << iter.first << std::endl;
231 // }
232 //}
233
234 return true;
235}
236
237// print a demangled stack backtrace of the caller function (copied from https://panthema.net/2008/0901-stacktrace-demangled/)
238static inline void PrintStacktrace(std::ostream& out = std::cout, int maxFrames = 63)
239{
240 if(gAddressOffset.empty()) {
241 if(!FindAddressOffsets(false)) {
242 throw;
243 }
244 }
245 std::ostringstream output;
246 output << "stack trace:" << std::endl;
247
248 // storage array for stack trace address data
249 void** addrlist = new void*[maxFrames + 1];
250
251 // retrieve current stack addresses
252 int addrlen = backtrace(addrlist, maxFrames + 1);
253
254 if(addrlen == 0) {
255 output << " <empty, possibly corrupt>" << std::endl;
256 out << output.str();
257 return;
258 }
259
260 // resolve addresses into strings containing "filename(function+address)",
261 // this array must be free()-ed
262 char** symbollist = backtrace_symbols(addrlist, addrlen);
263
264 // allocate string which will be filled with the demangled function name
265 size_t funcnamesize = 256;
266 auto* funcname = new char[funcnamesize];
267
268 // iterate over the returned symbol lines. skip the first, it is the
269 // address of this function.
270 for(int i = 2; i < addrlen; i++) {
271 char* begin_name = nullptr;
272 char* begin_offset = nullptr;
273
274 // find parentheses and +address offset surrounding the mangled name:
275 // ./module(function+0x15c) [0x8048a6d]
276 for(char* p = symbollist[i]; *p != 0; ++p) {
277 if(*p == '(') {
278 begin_name = p;
279 } else if(*p == '+') {
280 begin_offset = p;
281 break;
282 }
283 }
284
285 // try and decode file and line number (only if we have an absolute path)
286 std::string line;
287 if(symbollist[i][0] == '/') {
288 std::ostringstream command;
289 std::string filename = symbollist[i];
290 filename = filename.substr(0, filename.find_first_of('('));
291 if(gAddressOffset.find(filename) == gAddressOffset.end()) {
292 FindAddressOffsets(true);
293 }
294 // convert addrlist[i] to integer and subtract offset
295 if(gAddressOffset.find(filename) != gAddressOffset.end()) {
296 command << "addr2line " << hex(reinterpret_cast<uint64_t>(addrlist[i]) - gAddressOffset.at(filename)) << " -e " << filename;
297 line = sh(command.str());
298 line.erase(std::remove(line.begin(), line.end(), '\n'), line.end());
299 //std::cout << symbollist[i] << ": (" << addrlist[i] << "/" << hex(reinterpret_cast<uint64_t>(addrlist[i])) << " - " << hex(gAddressOffset.at(filename)) << ") executed command " << command.str() << " = " << line << std::endl;
300 }
301
302 if(begin_name != nullptr && begin_offset != nullptr && begin_name < begin_offset) {
303 *begin_name++ = '\0';
304 *begin_offset++ = '\0';
305
306 // mangled name is now in [begin_name, begin_offset)
307 // now apply __cxa_demangle():
308
309 int status = 0;
310 char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
311 if(status == 0) {
312 funcname = ret; // use possibly realloc()-ed string
313 output << " " << line << " - " << funcname << std::endl;
314 } else {
315 // demangling failed. Output function name as a C function with no arguments.
316 output << " " << line << " - " << begin_name << std::endl;
317 }
318 } else {
319 // couldn't parse the line? print the whole line.
320 output << " " << line << " - " << symbollist[i] << std::endl;
321 }
322 }
323 }
324
325 delete[] funcname;
326 delete symbollist;
327 out << output.str();
328}
329
330#if !__APPLE__
331#include <sys/wait.h>
332#include <sys/prctl.h>
333static inline void PrintGdbStacktrace()
334{
335 std::array<char, 30> pid_buf{};
336 sprintf(pid_buf.data(), "%d", getpid());
337 std::array<char, 512> name_buf{};
338 name_buf[readlink("/proc/self/exe", name_buf.data(), 511)] = 0;
339 prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
340 int child_pid = fork();
341 if(child_pid == 0) {
342 dup2(2, 1); // redirect output to stderr - edit: unnecessary?
343 execl("/usr/bin/gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", name_buf.data(), pid_buf.data(), nullptr);
344 abort(); /* If gdb failed to start */
345 } else {
346 waitpid(child_pid, nullptr, 0);
347 }
348}
349#endif
350
351#endif
static std::string getexepath()
Definition Globals.h:151
static std::string sh(const std::string &cmd)
Definition Globals.h:158
static void PrintGdbStacktrace()
Definition Globals.h:333
static void PrintStacktrace(std::ostream &out=std::cout, int maxFrames=63)
Definition Globals.h:238
std::map< std::string, uint64_t > gAddressOffset
Definition Globals.cxx:5
bool FindAddressOffsets(bool update)
Definition Globals.h:174
std::string hex(T val, int width=-1)
Definition Globals.h:129
EVerbosity
Definition Globals.h:143
const std::string & ProgramName()
Definition Globals.h:73
void Append(std::ostringstream &stream, const T &tail)
Definition Globals.h:91
std::string Stringify(const T &head, const U &... tail)
Definition Globals.h:110
void SetGRSIEnv()
Definition Globals.cxx:7
exit_exception(int c, const char *msg="")
Definition Globals.h:76
const char * message
Definition Globals.h:83