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 while(std::getline(procMap, line)) {
193 // line has format
194 // <start address>-<end address> <four letters for permissions> <offset> <device major>:<device minor> <inode> <so-library>
195 // if <inode> is 0 there is no so-library
196 std::stringstream str(line);
197
198 uint64_t startAddress = 0;
199 char dash = '\0';
200 uint64_t endAddress = 0;
201 std::string permissions;
202 uint64_t offset = 0;
203 std::string device;
204 int inode = 0;
205 std::string soLibrary;
206
207 str >> std::hex >> startAddress >> dash >> endAddress >> permissions >> std::dec >> offset >> device >> inode;
208
209 if(inode != 0) {
210 str >> soLibrary;
211
212 // we only keep the first starting address
213 if(gAddressOffset.find(soLibrary) == gAddressOffset.end()) {
214 gAddressOffset[soLibrary] = startAddress;
215 }
216 }
217 }
218
219 return true;
220}
221
222// print a demangled stack backtrace of the caller function (copied from https://panthema.net/2008/0901-stacktrace-demangled/)
223static inline void PrintStacktrace(std::ostream& out = std::cout, int maxFrames = 63)
224{
225 if(gAddressOffset.empty()) {
226 if(!FindAddressOffsets(false)) {
227 throw;
228 }
229 }
230 std::ostringstream output;
231 output << "stack trace:" << std::endl;
232
233 // storage array for stack trace address data
234 void** addrlist = new void*[maxFrames + 1];
235
236 // retrieve current stack addresses
237 int addrlen = backtrace(addrlist, maxFrames + 1);
238
239 if(addrlen == 0) {
240 output << " <empty, possibly corrupt>" << std::endl;
241 out << output.str();
242 return;
243 }
244
245 // resolve addresses into strings containing "filename(function+address)",
246 // this array must be free()-ed
247 char** symbollist = backtrace_symbols(addrlist, addrlen);
248
249 // allocate string which will be filled with the demangled function name
250 size_t funcnamesize = 256;
251 auto* funcname = new char[funcnamesize];
252
253 // iterate over the returned symbol lines. skip the first, it is the
254 // address of this function.
255 for(int i = 2; i < addrlen; i++) {
256 char* begin_name = nullptr;
257 char* begin_offset = nullptr;
258
259 // find parentheses and +address offset surrounding the mangled name:
260 // ./module(function+0x15c) [0x8048a6d]
261 for(char* p = symbollist[i]; *p != 0; ++p) {
262 if(*p == '(') {
263 begin_name = p;
264 } else if(*p == '+') {
265 begin_offset = p;
266 break;
267 }
268 }
269
270 // try and decode file and line number (only if we have an absolute path)
271 std::string line;
272 if(symbollist[i][0] == '/') {
273 std::ostringstream command;
274 std::string filename = symbollist[i];
275 filename = filename.substr(0, filename.find_first_of('('));
276 if(gAddressOffset.find(filename) == gAddressOffset.end()) {
277 FindAddressOffsets(true);
278 }
279 // convert addrlist[i] to integer and subtract offset
280 if(gAddressOffset.find(filename) != gAddressOffset.end()) {
281 command << "addr2line " << hex(reinterpret_cast<uint64_t>(addrlist[i]) - gAddressOffset.at(filename)) << " -e " << filename;
282 line = sh(command.str());
283 line.erase(std::remove(line.begin(), line.end(), '\n'), line.end());
284 //std::cout << symbollist[i] << ": (" << addrlist[i] << "/" << hex(reinterpret_cast<uint64_t>(addrlist[i])) << " - " << hex(gAddressOffset.at(filename)) << ") executed command " << command.str() << " = " << line << std::endl;
285 }
286
287 if(begin_name != nullptr && begin_offset != nullptr && begin_name < begin_offset) {
288 *begin_name++ = '\0';
289 *begin_offset++ = '\0';
290
291 // mangled name is now in [begin_name, begin_offset)
292 // now apply __cxa_demangle():
293
294 int status = 0;
295 char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
296 if(status == 0) {
297 funcname = ret; // use possibly realloc()-ed string
298 output << " " << line << " - " << funcname << std::endl;
299 } else {
300 // demangling failed. Output function name as a C function with no arguments.
301 output << " " << line << " - " << begin_name << std::endl;
302 }
303 } else {
304 // couldn't parse the line? print the whole line.
305 output << " " << line << " - " << symbollist[i] << std::endl;
306 }
307 }
308 }
309
310 delete[] funcname;
311 delete symbollist;
312 out << output.str();
313}
314
315#if !__APPLE__
316#include <sys/wait.h>
317#include <sys/prctl.h>
318static inline void PrintGdbStacktrace()
319{
320 std::array<char, 30> pid_buf{};
321 sprintf(pid_buf.data(), "%d", getpid());
322 std::array<char, 512> name_buf{};
323 name_buf[readlink("/proc/self/exe", name_buf.data(), 511)] = 0;
324 prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
325 int child_pid = fork();
326 if(child_pid == 0) {
327 dup2(2, 1); // redirect output to stderr - edit: unnecessary?
328 execl("/usr/bin/gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", name_buf.data(), pid_buf.data(), nullptr);
329 abort(); /* If gdb failed to start */
330 } else {
331 waitpid(child_pid, nullptr, 0);
332 }
333}
334#endif
335
336#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:318
static void PrintStacktrace(std::ostream &out=std::cout, int maxFrames=63)
Definition Globals.h:223
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