mirror of
https://github.com/boostorg/stacktrace.git
synced 2026-01-27 07:22:09 +00:00
fix addr2line for pie binaries (#138)
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/stacktrace/detail/addr_base.hpp>
|
||||
#include <boost/stacktrace/detail/to_hex_array.hpp>
|
||||
#include <boost/stacktrace/detail/to_dec_array.hpp>
|
||||
#include <boost/stacktrace/detail/try_dec_convert.hpp>
|
||||
@@ -155,6 +156,19 @@ inline std::string addr2line(const char* flag, const void* addr) {
|
||||
return res;
|
||||
}
|
||||
|
||||
inline std::string source_location(const void* addr, bool position_independent) {
|
||||
uintptr_t addr_base = 0;
|
||||
if (position_independent) {
|
||||
addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
|
||||
}
|
||||
const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
|
||||
std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", reinterpret_cast<const void*>(offset));
|
||||
if (source_line.empty() || source_line[0] == '?') {
|
||||
return "";
|
||||
}
|
||||
|
||||
return source_line;
|
||||
}
|
||||
|
||||
struct to_string_using_addr2line {
|
||||
std::string res;
|
||||
@@ -163,9 +177,20 @@ struct to_string_using_addr2line {
|
||||
}
|
||||
|
||||
bool prepare_source_location(const void* addr) {
|
||||
//return addr2line("-Cfipe", addr); // Does not seem to work in all cases
|
||||
std::string source_line = boost::stacktrace::detail::addr2line("-Cpe", addr);
|
||||
if (!source_line.empty() && source_line[0] != '?') {
|
||||
// general idea in all addr2line uses:
|
||||
// in each case:
|
||||
// - try to resolve whole address as if it was a non-pie binary
|
||||
// - if that didn't work, try to resolve just an offset from binary base address
|
||||
// this is needed because:
|
||||
// - in pie binaries just passing an address to addr2line won't work (it needs an offset in this case)
|
||||
// - in non-pie binaries whole address is needed (offset won't work)
|
||||
// - there is no easy way to test if binary is position independent (that I know of)
|
||||
std::string source_line = boost::stacktrace::detail::source_location(addr, false);
|
||||
if(source_line.empty()) {
|
||||
source_line = boost::stacktrace::detail::source_location(addr, true);
|
||||
}
|
||||
|
||||
if (!source_line.empty()) {
|
||||
res += " at ";
|
||||
res += source_line;
|
||||
return true;
|
||||
@@ -178,8 +203,13 @@ struct to_string_using_addr2line {
|
||||
template <class Base> class to_string_impl_base;
|
||||
typedef to_string_impl_base<to_string_using_addr2line> to_string_impl;
|
||||
|
||||
inline std::string name_impl(const void* addr) {
|
||||
std::string res = boost::stacktrace::detail::addr2line("-fe", addr);
|
||||
inline std::string name(const void* addr, bool position_independent) {
|
||||
uintptr_t addr_base = 0;
|
||||
if(position_independent){
|
||||
addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
|
||||
}
|
||||
const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
|
||||
std::string res = boost::stacktrace::detail::addr2line("-fe", offset);
|
||||
res = res.substr(0, res.find_last_of('\n'));
|
||||
res = boost::core::demangle(res.c_str());
|
||||
|
||||
@@ -190,11 +220,23 @@ inline std::string name_impl(const void* addr) {
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
inline std::string name_impl(const void* addr) {
|
||||
std::string res = boost::stacktrace::detail::name(addr, false);
|
||||
if (res.empty()) {
|
||||
res = boost::stacktrace::detail::name(addr, true);
|
||||
}
|
||||
|
||||
std::string frame::source_file() const {
|
||||
return res;
|
||||
}
|
||||
|
||||
inline std::string source_file(const void* addr, bool position_independent) {
|
||||
std::string res;
|
||||
res = boost::stacktrace::detail::addr2line("-e", addr_);
|
||||
uintptr_t addr_base = 0;
|
||||
if(position_independent){
|
||||
addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
|
||||
}
|
||||
const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
|
||||
res = boost::stacktrace::detail::addr2line("-e", offset);
|
||||
res = res.substr(0, res.find_last_of(':'));
|
||||
if (res == "??") {
|
||||
res.clear();
|
||||
@@ -203,10 +245,14 @@ std::string frame::source_file() const {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
inline std::size_t source_line(const void* addr, bool position_independent) {
|
||||
std::size_t line_num = 0;
|
||||
std::string res = boost::stacktrace::detail::addr2line("-e", addr_);
|
||||
uintptr_t addr_base = 0;
|
||||
if(position_independent){
|
||||
addr_base = boost::stacktrace::detail::get_own_proc_addr_base(addr);
|
||||
}
|
||||
const void* offset = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - addr_base);
|
||||
std::string res = boost::stacktrace::detail::addr2line("-e", offset);
|
||||
const std::size_t last = res.find_last_of(':');
|
||||
if (last == std::string::npos) {
|
||||
return 0;
|
||||
@@ -220,6 +266,27 @@ std::size_t frame::source_line() const {
|
||||
return line_num;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
std::string frame::source_file() const {
|
||||
std::string res = boost::stacktrace::detail::source_file(addr_, false);
|
||||
if (res.empty()) {
|
||||
res = boost::stacktrace::detail::source_file(addr_, true);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
std::size_t line_num = boost::stacktrace::detail::source_line(addr_, false);
|
||||
if (line_num == 0) {
|
||||
line_num = boost::stacktrace::detail::source_line(addr_, true);
|
||||
}
|
||||
|
||||
return line_num;
|
||||
}
|
||||
|
||||
|
||||
}} // namespace boost::stacktrace
|
||||
|
||||
|
||||
88
include/boost/stacktrace/detail/addr_base.hpp
Normal file
88
include/boost/stacktrace/detail/addr_base.hpp
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_ADDR_BASE_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_ADDR_BASE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
struct mapping_entry_t {
|
||||
uintptr_t start = 0;
|
||||
uintptr_t end = 0;
|
||||
uintptr_t offset_from_base = 0;
|
||||
|
||||
inline bool contains_addr(const void* addr) const {
|
||||
uintptr_t addr_uint = reinterpret_cast<uintptr_t>(addr);
|
||||
return addr_uint >= start && addr_uint < end;
|
||||
}
|
||||
};
|
||||
|
||||
inline uintptr_t hex_str_to_int(const std::string& str) {
|
||||
uintptr_t out;
|
||||
std::stringstream ss;
|
||||
ss << std::hex << str;
|
||||
ss >> out;
|
||||
if(ss.eof() && !ss.fail()) { // whole stream read, with no errors
|
||||
return out;
|
||||
} else {
|
||||
throw std::invalid_argument(std::string("can't convert '") + str + "' to hex");
|
||||
}
|
||||
}
|
||||
|
||||
// parse line from /proc/<id>/maps
|
||||
// format:
|
||||
// 7fb60d1ea000-7fb60d20c000 r--p 00000000 103:02 120327460 /usr/lib/libc.so.6
|
||||
// only parts 0 and 2 are interesting, these are:
|
||||
// 0. mapping address range
|
||||
// 2. mapping offset from base
|
||||
inline mapping_entry_t parse_proc_maps_line(const std::string& line) {
|
||||
std::string mapping_range_str, permissions_str, offset_from_base_str;
|
||||
std::istringstream line_stream(line);
|
||||
if(!std::getline(line_stream, mapping_range_str, ' ') ||
|
||||
!std::getline(line_stream, permissions_str, ' ') ||
|
||||
!std::getline(line_stream, offset_from_base_str, ' ')) {
|
||||
return mapping_entry_t{};
|
||||
}
|
||||
std::string mapping_start_str, mapping_end_str;
|
||||
std::istringstream mapping_range_stream(mapping_range_str);
|
||||
if(!std::getline(mapping_range_stream, mapping_start_str, '-') ||
|
||||
!std::getline(mapping_range_stream, mapping_end_str)) {
|
||||
return mapping_entry_t{};
|
||||
}
|
||||
mapping_entry_t mapping{};
|
||||
try {
|
||||
mapping.start = hex_str_to_int(mapping_start_str);
|
||||
mapping.end = hex_str_to_int(mapping_end_str);
|
||||
mapping.offset_from_base = hex_str_to_int(offset_from_base_str);
|
||||
return mapping;
|
||||
} catch(std::invalid_argument& e) {
|
||||
return mapping_entry_t{};
|
||||
}
|
||||
}
|
||||
|
||||
inline uintptr_t get_own_proc_addr_base(const void* addr) {
|
||||
std::ifstream maps_file("/proc/self/maps");
|
||||
for (std::string line; std::getline(maps_file, line); ) {
|
||||
const mapping_entry_t mapping = parse_proc_maps_line(line);
|
||||
if (mapping.contains_addr(addr)) {
|
||||
return mapping.start - mapping.offset_from_base;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_ADDR_BASE_HPP
|
||||
Reference in New Issue
Block a user