Implement signal-safe resolution of basic object information
This commit is contained in:
parent
327a6e8318
commit
ac13e71877
@ -484,4 +484,8 @@ if(CPPTRACE_BUILD_TESTING)
|
||||
COMMAND dsymutil $<TARGET_FILE:demo>
|
||||
)
|
||||
endif()
|
||||
|
||||
add_executable(signal_tracer test/signal_tracer.cpp)
|
||||
target_compile_features(signal_tracer PRIVATE cxx_std_11)
|
||||
target_link_libraries(signal_tracer PRIVATE ${target_name})
|
||||
endif()
|
||||
|
||||
@ -148,6 +148,15 @@ namespace detail {
|
||||
return frames;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline object_frame resolve_minimal_object_frame(const minimal_object_frame& frame) {
|
||||
return {
|
||||
frame.object_path,
|
||||
"",
|
||||
frame.raw_address,
|
||||
frame.address_relative_to_object_base_in_memory + get_module_image_base(frame.object_path)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
59
src/binary/safe_dl.hpp
Normal file
59
src/binary/safe_dl.hpp
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef SAFE_DL_HPP
|
||||
#define SAFE_DL_HPP
|
||||
|
||||
#include "../utils/common.hpp"
|
||||
#include "../utils/utils.hpp"
|
||||
#include "../utils/program_name.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#if IS_LINUX || IS_APPLE
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
inline void get_minimal_object_frame(frame_ptr address, minimal_object_frame* out) {
|
||||
dl_find_object result;
|
||||
if(_dl_find_object(reinterpret_cast<void*>(address), &result) == 0) {
|
||||
out->raw_address = address;
|
||||
out->address_relative_to_object_base_in_memory = address - reinterpret_cast<frame_ptr>(result.dlfo_map_start);
|
||||
if(result.dlfo_link_map->l_name != nullptr && result.dlfo_link_map->l_name[0] != 0) {
|
||||
std::size_t path_length = std::strlen(result.dlfo_link_map->l_name);
|
||||
std::memcpy(
|
||||
out->object_path,
|
||||
result.dlfo_link_map->l_name,
|
||||
std::min(path_length + 1, std::size_t(CPPTRACE_PATH_MAX + 1))
|
||||
);
|
||||
} else {
|
||||
// empty l_name, this means it's the currently running executable
|
||||
memset(out->object_path, 0, PATH_MAX + 1);
|
||||
auto res = readlink("/proc/self/exe", out->object_path, PATH_MAX);
|
||||
if(res == -1) {
|
||||
// error handling?
|
||||
}
|
||||
// TODO: Special handling for /proc/pid/exe unlink edge case
|
||||
}
|
||||
} else {
|
||||
// std::cout<<"error"<<std::endl;
|
||||
out->raw_address = address;
|
||||
out->address_relative_to_object_base_in_memory = 0;
|
||||
out->object_path[0] = 0;
|
||||
}
|
||||
// TODO: Handle this part of the documentation?
|
||||
// The address can be a code address or data address. On architectures using function descriptors, no attempt is
|
||||
// made to decode the function descriptor. Depending on how these descriptors are implemented, _dl_find_object
|
||||
// may return the object that defines the function descriptor (and not the object that contains the code
|
||||
// implementing the function), or fail to find any object at all.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -19,6 +19,7 @@
|
||||
#include "utils/common.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
#include "binary/object.hpp"
|
||||
#include "binary/safe_dl.hpp"
|
||||
|
||||
#define ESC "\033["
|
||||
#define RESET ESC "0m"
|
||||
@ -342,6 +343,14 @@ namespace cpptrace {
|
||||
}
|
||||
}
|
||||
|
||||
object_frame minimal_object_frame::resolve() const {
|
||||
return detail::resolve_minimal_object_frame(*this);
|
||||
}
|
||||
|
||||
void get_minimal_object_frame(frame_ptr address, minimal_object_frame* out) {
|
||||
detail::get_minimal_object_frame(address, out);
|
||||
}
|
||||
|
||||
std::string demangle(const std::string& name) {
|
||||
return detail::demangle(name);
|
||||
}
|
||||
|
||||
@ -41,7 +41,6 @@ namespace detail {
|
||||
std::size_t safe_capture_frames(frame_ptr* buffer, std::size_t size, std::size_t skip, std::size_t max_depth) {
|
||||
// some code duplication, but whatever
|
||||
skip++;
|
||||
std::vector<frame_ptr> frames;
|
||||
unw_context_t context;
|
||||
unw_cursor_t cursor;
|
||||
// thread and signal-safe https://www.nongnu.org/libunwind/man/unw_getcontext(3).html
|
||||
|
||||
28
test/signal_tracer.cpp
Normal file
28
test/signal_tracer.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
|
||||
int main() {
|
||||
cpptrace::object_trace trace;
|
||||
while(true) {
|
||||
cpptrace::minimal_object_frame frame;
|
||||
// std::size_t res = read(STDIN_FILENO, &frame, sizeof(frame));
|
||||
std::size_t res = fread(&frame, sizeof(frame), 1, stdin);
|
||||
if(res == 0) {
|
||||
break;
|
||||
} else if(res == -1) {
|
||||
perror("Oops");
|
||||
break;
|
||||
//} else if(res != sizeof(frame)) {
|
||||
} else if(res != 1) {
|
||||
std::cerr<<"Oops, size mismatch "<<res<<" "<<sizeof(frame)<<std::endl;
|
||||
break;
|
||||
} else {
|
||||
trace.frames.push_back(frame.resolve());
|
||||
}
|
||||
}
|
||||
trace.resolve().print();
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user