156static inline std::string
sh(
const std::string& cmd)
158 std::array<char, 128> buffer{};
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();
175 std::cerr <<
"Warning, already have " <<
gAddressOffset.size() <<
" address offsets, not checking again!" << std::endl;
184 std::ifstream procMap(
"/proc/self/maps");
185 if(!procMap.is_open()) {
186 std::cerr <<
"Failed to open \"/proc/self/maps\"" << std::endl;
190 while(std::getline(procMap, line)) {
194 std::stringstream str(line);
196 uint64_t startAddress = 0;
198 uint64_t endAddress = 0;
199 std::string permissions;
203 std::string soLibrary;
205 str >> std::hex >> startAddress >> dash >> endAddress >> permissions >> std::dec >> offset >> device >> inode;
228 std::ostringstream output;
229 output <<
"stack trace:" << std::endl;
232 void** addrlist =
new void*[maxFrames + 1];
235 int addrlen = backtrace(addrlist, maxFrames + 1);
238 output <<
" <empty, possibly corrupt>" << std::endl;
245 char** symbollist = backtrace_symbols(addrlist, addrlen);
248 size_t funcnamesize = 256;
249 auto* funcname =
new char[funcnamesize];
253 for(
int i = 2; i < addrlen; i++) {
254 char* begin_name =
nullptr;
255 char* begin_offset =
nullptr;
259 for(
char* p = symbollist[i]; *p != 0; ++p) {
262 }
else if(*p ==
'+') {
270 if(symbollist[i][0] ==
'/') {
271 std::ostringstream command;
272 std::string filename = symbollist[i];
273 filename = filename.substr(0, filename.find_first_of(
'('));
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());
285 if(begin_name !=
nullptr && begin_offset !=
nullptr && begin_name < begin_offset) {
286 *begin_name++ =
'\0';
287 *begin_offset++ =
'\0';
293 char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
296 output <<
" " << line <<
" - " << funcname << std::endl;
299 output <<
" " << line <<
" - " << begin_name << std::endl;
303 output <<
" " << line <<
" - " << symbollist[i] << std::endl;
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();
326 execl(
"/usr/bin/gdb",
"gdb",
"--batch",
"-n",
"-ex",
"thread",
"-ex",
"bt", name_buf.data(), pid_buf.data(),
nullptr);
329 waitpid(child_pid,
nullptr, 0);