158static inline std::string
sh(
const std::string& cmd)
160 std::array<char, 128> buffer{};
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();
177 std::cerr <<
"Warning, already have " <<
gAddressOffset.size() <<
" address offsets, not checking again!" << std::endl;
186 std::ifstream procMap(
"/proc/self/maps");
187 if(!procMap.is_open()) {
188 std::cerr <<
"Failed to open \"/proc/self/maps\"" << std::endl;
193 while(std::getline(procMap, line)) {
197 std::stringstream str(line);
199 uint64_t startAddress = 0;
201 uint64_t endAddress = 0;
202 std::string permissions;
206 std::string soLibrary;
208 str >> std::hex >> startAddress >> dash >> endAddress >> permissions >> std::dec >> offset >> device >> inode;
245 std::ostringstream output;
246 output <<
"stack trace:" << std::endl;
249 void** addrlist =
new void*[maxFrames + 1];
252 int addrlen = backtrace(addrlist, maxFrames + 1);
255 output <<
" <empty, possibly corrupt>" << std::endl;
262 char** symbollist = backtrace_symbols(addrlist, addrlen);
265 size_t funcnamesize = 256;
266 auto* funcname =
new char[funcnamesize];
270 for(
int i = 2; i < addrlen; i++) {
271 char* begin_name =
nullptr;
272 char* begin_offset =
nullptr;
276 for(
char* p = symbollist[i]; *p != 0; ++p) {
279 }
else if(*p ==
'+') {
287 if(symbollist[i][0] ==
'/') {
288 std::ostringstream command;
289 std::string filename = symbollist[i];
290 filename = filename.substr(0, filename.find_first_of(
'('));
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());
302 if(begin_name !=
nullptr && begin_offset !=
nullptr && begin_name < begin_offset) {
303 *begin_name++ =
'\0';
304 *begin_offset++ =
'\0';
310 char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
313 output <<
" " << line <<
" - " << funcname << std::endl;
316 output <<
" " << line <<
" - " << begin_name << std::endl;
320 output <<
" " << line <<
" - " << symbollist[i] << std::endl;
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();
343 execl(
"/usr/bin/gdb",
"gdb",
"--batch",
"-n",
"-ex",
"thread",
"-ex",
"bt", name_buf.data(), pid_buf.data(),
nullptr);
346 waitpid(child_pid,
nullptr, 0);