| 1250 | #ifdef BACKWARD_SYSTEM_LINUX |
| 1251 | |
| 1252 | class TraceResolverLinuxBase : public TraceResolverImplBase { |
| 1253 | public: |
| 1254 | TraceResolverLinuxBase() |
| 1255 | : argv0_(get_argv0()), exec_path_(read_symlink("/proc/self/exe")) {} |
| 1256 | std::string resolve_exec_path(Dl_info &symbol_info) const { |
| 1257 | // mutates symbol_info.dli_fname to be filename to open and returns filename |
| 1258 | // to display |
| 1259 | if (symbol_info.dli_fname == argv0_) { |
| 1260 | // dladdr returns argv[0] in dli_fname for symbols contained in |
| 1261 | // the main executable, which is not a valid path if the |
| 1262 | // executable was found by a search of the PATH environment |
| 1263 | // variable; In that case, we actually open /proc/self/exe, which |
| 1264 | // is always the actual executable (even if it was deleted/replaced!) |
| 1265 | // but display the path that /proc/self/exe links to. |
| 1266 | // However, this right away reduces probability of successful symbol |
| 1267 | // resolution, because libbfd may try to find *.debug files in the |
| 1268 | // same dir, in case symbols are stripped. As a result, it may try |
| 1269 | // to find a file /proc/self/<exe_name>.debug, which obviously does |
| 1270 | // not exist. /proc/self/exe is a last resort. First load attempt |
| 1271 | // should go for the original executable file path. |
| 1272 | symbol_info.dli_fname = "/proc/self/exe"; |
| 1273 | return exec_path_; |
| 1274 | } else { |
| 1275 | return symbol_info.dli_fname; |
| 1276 | } |
| 1277 | } |
| 1278 | |
| 1279 | private: |
| 1280 | std::string argv0_; |
| 1281 | std::string exec_path_; |
| 1282 | |
| 1283 | static std::string get_argv0() { |
| 1284 | std::string argv0; |
| 1285 | std::ifstream ifs("/proc/self/cmdline"); |
| 1286 | std::getline(ifs, argv0, '\0'); |
| 1287 | return argv0; |
| 1288 | } |
| 1289 | |
| 1290 | static std::string read_symlink(std::string const &symlink_path) { |
| 1291 | std::string path; |
| 1292 | path.resize(100); |
| 1293 | |
| 1294 | while (true) { |
| 1295 | ssize_t len = |
| 1296 | ::readlink(symlink_path.c_str(), &*path.begin(), path.size()); |
| 1297 | if (len < 0) { |
| 1298 | return ""; |
| 1299 | } |
| 1300 | if (static_cast<size_t>(len) == path.size()) { |
| 1301 | path.resize(path.size() * 2); |
| 1302 | } else { |
| 1303 | path.resize(static_cast<std::string::size_type>(len)); |
| 1304 | break; |
| 1305 | } |
| 1306 | } |
| 1307 | |
| 1308 | return path; |
| 1309 | } |
nothing calls this directly
no outgoing calls
no test coverage detected