From 1ecbdc649147ef4a8e34d2a61f46a7e211758f2e Mon Sep 17 00:00:00 2001 From: Forrest Voight Date: Mon, 23 Sep 2019 14:15:36 -0500 Subject: [PATCH] Handle executable being deleted or replaced by directly opening `/proc/self/exe` rather than file it links to. Fixes issue #146. --- backward.hpp | 94 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 40 deletions(-) diff --git a/backward.hpp b/backward.hpp index fd1df66..d3f46f4 100644 --- a/backward.hpp +++ b/backward.hpp @@ -811,32 +811,58 @@ private: #ifdef BACKWARD_SYSTEM_LINUX -static std::string get_argv0() { - std::string argv0; - std::getline(std::ifstream("/proc/self/cmdline"), argv0, '\0'); - return argv0; -} - -static std::string read_symlink(std::string const &symlink_path) { - std::string path; - path.resize(100); - - while (true) { - ssize_t len = - ::readlink(symlink_path.c_str(), &*path.begin(), path.size()); - if (len < 0) { - return ""; - } - if (static_cast(len) == path.size()) { - path.resize(path.size() * 2); +class TraceResolverLinuxBase + : public TraceResolverImplBase { +public: + TraceResolverLinuxBase() + : argv0_(get_argv0()), exec_path_(read_symlink("/proc/self/exe")) { + } + std::string resolve_exec_path(Dl_info &symbol_info) const { + // mutates symbol_info.dli_fname to be filename to open and returns filename to display + if(symbol_info.dli_fname == argv0_) { + // dladdr returns argv[0] in dli_fname for symbols contained in + // the main executable, which is not a valid path if the + // executable was found by a search of the PATH environment + // variable; In that case, we actually open /proc/self/exe, which + // is always the actual executable (even if it was deleted/replaced!) + // but display the path that /proc/self/exe links to. + symbol_info.dli_fname = "/proc/self/exe"; + return exec_path_; } else { - path.resize(static_cast(len)); - break; + return symbol_info.dli_fname; } } +private: + std::string argv0_; + std::string exec_path_; - return path; -} + static std::string get_argv0() { + std::string argv0; + std::getline(std::ifstream("/proc/self/cmdline"), argv0, '\0'); + return argv0; + } + + static std::string read_symlink(std::string const &symlink_path) { + std::string path; + path.resize(100); + + while (true) { + ssize_t len = + ::readlink(symlink_path.c_str(), &*path.begin(), path.size()); + if (len < 0) { + return ""; + } + if (static_cast(len) == path.size()) { + path.resize(path.size() * 2); + } else { + path.resize(static_cast(len)); + break; + } + } + + return path; + } +}; template class TraceResolverLinuxImpl; @@ -844,7 +870,7 @@ template class TraceResolverLinuxImpl; template <> class TraceResolverLinuxImpl - : public TraceResolverImplBase { + : public TraceResolverLinuxBase { public: template void load_stacktrace(ST &st) { using namespace details; @@ -887,7 +913,7 @@ private: template <> class TraceResolverLinuxImpl - : public TraceResolverImplBase { + : public TraceResolverLinuxBase { public: TraceResolverLinuxImpl() : _bfd_loaded(false) {} @@ -903,12 +929,6 @@ public: return trace; // dat broken trace... } - std::string tmp; - if (symbol_info.dli_fname == get_argv0()) { - tmp = read_symlink("/proc/self/exe"); - symbol_info.dli_fname = tmp.c_str(); - } - // Now we get in symbol_info: // .dli_fname: // pathname of the shared object that contains the address. @@ -928,7 +948,7 @@ public: return trace; } - trace.object_filename = symbol_info.dli_fname; + trace.object_filename = resolve_exec_path(symbol_info); bfd_fileobject &fobj = load_object_with_bfd(symbol_info.dli_fname); if (!fobj.handle) { return trace; // sad, we couldn't load the object :( @@ -1257,7 +1277,7 @@ private: template <> class TraceResolverLinuxImpl - : public TraceResolverImplBase { + : public TraceResolverLinuxBase { public: TraceResolverLinuxImpl() : _dwfl_handle_initialized(false) {} @@ -1586,7 +1606,7 @@ private: template <> class TraceResolverLinuxImpl - : public TraceResolverImplBase { + : public TraceResolverLinuxBase { public: TraceResolverLinuxImpl() : _dwarf_loaded(false) {} @@ -1613,12 +1633,6 @@ public: return trace; // dat broken trace... } - std::string tmp; - if (symbol_info.dli_fname == get_argv0()) { - tmp = read_symlink("/proc/self/exe"); - symbol_info.dli_fname = tmp.c_str(); - } - // Now we get in symbol_info: // .dli_fname: // pathname of the shared object that contains the address. @@ -1645,7 +1659,7 @@ public: return trace; } - trace.object_filename = symbol_info.dli_fname; + trace.object_filename = resolve_exec_path(symbol_info); dwarf_fileobject &fobj = load_object_with_dwarf(symbol_info.dli_fname); if (!fobj.dwarf_handle) { return trace; // sad, we couldn't load the object :(