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