Add get_object_info method to stacktrace frames, adding onto the previous work for #97
This commit is contained in:
parent
123e7df4f4
commit
389f788b57
@ -169,6 +169,7 @@ namespace cpptrace {
|
|||||||
bool is_inline;
|
bool is_inline;
|
||||||
bool operator==(const stacktrace_frame& other) const;
|
bool operator==(const stacktrace_frame& other) const;
|
||||||
bool operator!=(const stacktrace_frame& other) const;
|
bool operator!=(const stacktrace_frame& other) const;
|
||||||
|
object_frame get_object_info() const; // object_address is stored but if the object_path is needed this can be used
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
/* operator<<(ostream, ..) and std::format support exist for this object */
|
/* operator<<(ostream, ..) and std::format support exist for this object */
|
||||||
};
|
};
|
||||||
|
|||||||
@ -52,6 +52,9 @@ ctrace_stacktrace ctrace_generate_trace(size_t skip, size_t max_depth);
|
|||||||
ctrace_owning_string ctrace_stacktrace_to_string(const ctrace_stacktrace* trace, ctrace_bool use_color);
|
ctrace_owning_string ctrace_stacktrace_to_string(const ctrace_stacktrace* trace, ctrace_bool use_color);
|
||||||
void ctrace_print_stacktrace(const ctrace_stacktrace* trace, FILE* to, ctrace_bool use_color);
|
void ctrace_print_stacktrace(const ctrace_stacktrace* trace, FILE* to, ctrace_bool use_color);
|
||||||
void ctrace_free_stacktrace(ctrace_stacktrace* trace);
|
void ctrace_free_stacktrace(ctrace_stacktrace* trace);
|
||||||
|
|
||||||
|
// object_address is stored but if the object_path is needed this can be used
|
||||||
|
ctrace_object_frame ctrace_get_object_info(const ctrace_stacktrace_frame* frame);
|
||||||
```
|
```
|
||||||
|
|
||||||
### Object Traces
|
### Object Traces
|
||||||
|
|||||||
@ -168,6 +168,8 @@ namespace cpptrace {
|
|||||||
return !operator==(other);
|
return !operator==(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object_frame get_object_info() const;
|
||||||
|
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
friend std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame);
|
friend std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -143,6 +143,8 @@ CTRACE_BEGIN_DEFINITIONS
|
|||||||
CPPTRACE_EXPORT int ctrace_stdout_fileno(void);
|
CPPTRACE_EXPORT int ctrace_stdout_fileno(void);
|
||||||
CPPTRACE_EXPORT ctrace_bool ctrace_isatty(int fd);
|
CPPTRACE_EXPORT ctrace_bool ctrace_isatty(int fd);
|
||||||
|
|
||||||
|
CPPTRACE_EXPORT ctrace_object_frame ctrace_get_object_info(const ctrace_stacktrace_frame* frame);
|
||||||
|
|
||||||
/* ctrace::config: */
|
/* ctrace::config: */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* Only minimal lookup tables */
|
/* Only minimal lookup tables */
|
||||||
|
|||||||
@ -65,57 +65,47 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef CPPTRACE_HAS_DL_FIND_OBJECT
|
#ifdef CPPTRACE_HAS_DL_FIND_OBJECT
|
||||||
inline std::vector<object_frame> get_frames_object_info(const std::vector<frame_ptr>& addrs) {
|
inline object_frame get_frame_object_info(frame_ptr address) {
|
||||||
// Use _dl_find_object when we can, it's orders of magnitude faster
|
// Use _dl_find_object when we can, it's orders of magnitude faster
|
||||||
std::vector<object_frame> frames;
|
object_frame frame;
|
||||||
frames.reserve(addrs.size());
|
frame.raw_address = address;
|
||||||
for(const frame_ptr addr : addrs) {
|
frame.object_address = 0;
|
||||||
object_frame frame;
|
dl_find_object result;
|
||||||
frame.raw_address = addr;
|
if(_dl_find_object(reinterpret_cast<void*>(address), &result) == 0) { // thread safe
|
||||||
frame.object_address = 0;
|
if(result.dlfo_link_map->l_name != nullptr && result.dlfo_link_map->l_name[0] != 0) {
|
||||||
dl_find_object result;
|
frame.object_path = result.dlfo_link_map->l_name;
|
||||||
if(_dl_find_object(reinterpret_cast<void*>(addr), &result) == 0) { // thread safe
|
} else {
|
||||||
if(result.dlfo_link_map->l_name != nullptr && result.dlfo_link_map->l_name[0] != 0) {
|
// empty l_name, this means it's the currently running executable
|
||||||
frame.object_path = result.dlfo_link_map->l_name;
|
// TODO: Caching and proper handling
|
||||||
|
char buffer[CPPTRACE_PATH_MAX + 1]{};
|
||||||
|
auto res = readlink("/proc/self/exe", buffer, CPPTRACE_PATH_MAX);
|
||||||
|
if(res == -1) {
|
||||||
|
// error handling?
|
||||||
} else {
|
} else {
|
||||||
// empty l_name, this means it's the currently running executable
|
frame.object_path = buffer;
|
||||||
// TODO: Caching and proper handling
|
|
||||||
char buffer[CPPTRACE_PATH_MAX + 1]{};
|
|
||||||
auto res = readlink("/proc/self/exe", buffer, CPPTRACE_PATH_MAX);
|
|
||||||
if(res == -1) {
|
|
||||||
// error handling?
|
|
||||||
} else {
|
|
||||||
frame.object_path = buffer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
frame.object_address = addr
|
|
||||||
- to_frame_ptr(result.dlfo_link_map->l_addr)
|
|
||||||
+ get_module_image_base(frame.object_path);
|
|
||||||
}
|
}
|
||||||
frames.push_back(frame);
|
frame.object_address = address
|
||||||
|
- to_frame_ptr(result.dlfo_link_map->l_addr)
|
||||||
|
+ get_module_image_base(frame.object_path);
|
||||||
}
|
}
|
||||||
return frames;
|
return frame;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// aladdr queries are needed to get pre-ASLR addresses and targets to run addr2line on
|
// dladdr queries are needed to get pre-ASLR addresses and targets to run addr2line on
|
||||||
inline std::vector<object_frame> get_frames_object_info(const std::vector<frame_ptr>& addrs) {
|
inline object_frame get_frame_object_info(frame_ptr address) {
|
||||||
// reference: https://github.com/bminor/glibc/blob/master/debug/backtracesyms.c
|
// reference: https://github.com/bminor/glibc/blob/master/debug/backtracesyms.c
|
||||||
std::vector<object_frame> frames;
|
Dl_info info;
|
||||||
frames.reserve(addrs.size());
|
object_frame frame;
|
||||||
for(const frame_ptr addr : addrs) {
|
frame.raw_address = address;
|
||||||
Dl_info info;
|
frame.object_address = 0;
|
||||||
object_frame frame;
|
if(dladdr(reinterpret_cast<void*>(address), &info)) { // thread safe
|
||||||
frame.raw_address = addr;
|
frame.object_path = info.dli_fname;
|
||||||
frame.object_address = 0;
|
frame.object_address = address
|
||||||
if(dladdr(reinterpret_cast<void*>(addr), &info)) { // thread safe
|
- reinterpret_cast<std::uintptr_t>(info.dli_fbase)
|
||||||
frame.object_path = info.dli_fname;
|
+ get_module_image_base(info.dli_fname);
|
||||||
frame.object_address = addr
|
|
||||||
- reinterpret_cast<std::uintptr_t>(info.dli_fbase)
|
|
||||||
+ get_module_image_base(info.dli_fname);
|
|
||||||
}
|
|
||||||
frames.push_back(frame);
|
|
||||||
}
|
}
|
||||||
return frames;
|
return frame;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
@ -156,34 +146,36 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// aladdr queries are needed to get pre-ASLR addresses and targets to run addr2line on
|
inline object_frame get_frame_object_info(frame_ptr address) {
|
||||||
inline std::vector<object_frame> get_frames_object_info(const std::vector<frame_ptr>& addrs) {
|
object_frame frame;
|
||||||
// reference: https://github.com/bminor/glibc/blob/master/debug/backtracesyms.c
|
frame.raw_address = address;
|
||||||
|
frame.object_address = 0;
|
||||||
|
HMODULE handle;
|
||||||
|
// Multithread safe as long as another thread doesn't come along and free the module
|
||||||
|
if(GetModuleHandleExA(
|
||||||
|
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||||
|
reinterpret_cast<const char*>(address),
|
||||||
|
&handle
|
||||||
|
)) {
|
||||||
|
frame.object_path = get_module_name(handle);
|
||||||
|
frame.object_address = address
|
||||||
|
- reinterpret_cast<std::uintptr_t>(handle)
|
||||||
|
+ get_module_image_base(frame.object_path);
|
||||||
|
} else {
|
||||||
|
std::fprintf(stderr, "%s\n", std::system_error(GetLastError(), std::system_category()).what());
|
||||||
|
}
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline std::vector<object_frame> get_frames_object_info(const std::vector<frame_ptr>& addresses) {
|
||||||
std::vector<object_frame> frames;
|
std::vector<object_frame> frames;
|
||||||
frames.reserve(addrs.size());
|
frames.reserve(addresses.size());
|
||||||
for(const frame_ptr addr : addrs) {
|
for(const frame_ptr address : addresses) {
|
||||||
object_frame frame;
|
frames.push_back(get_frame_object_info(address));
|
||||||
frame.raw_address = addr;
|
|
||||||
frame.object_address = 0;
|
|
||||||
HMODULE handle;
|
|
||||||
// Multithread safe as long as another thread doesn't come along and free the module
|
|
||||||
if(GetModuleHandleExA(
|
|
||||||
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
|
||||||
reinterpret_cast<const char*>(addr),
|
|
||||||
&handle
|
|
||||||
)) {
|
|
||||||
frame.object_path = get_module_name(handle);
|
|
||||||
frame.object_address = addr
|
|
||||||
- reinterpret_cast<std::uintptr_t>(handle)
|
|
||||||
+ get_module_image_base(frame.object_path);
|
|
||||||
} else {
|
|
||||||
std::fprintf(stderr, "%s\n", std::system_error(GetLastError(), std::system_category()).what());
|
|
||||||
}
|
|
||||||
frames.push_back(frame);
|
|
||||||
}
|
}
|
||||||
return frames;
|
return frames;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
inline object_frame resolve_safe_object_frame(const safe_object_frame& frame) {
|
inline object_frame resolve_safe_object_frame(const safe_object_frame& frame) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -100,6 +100,10 @@ namespace cpptrace {
|
|||||||
return frames.empty();
|
return frames.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object_frame stacktrace_frame::get_object_info() const {
|
||||||
|
return detail::get_frame_object_info(raw_address);
|
||||||
|
}
|
||||||
|
|
||||||
std::string stacktrace_frame::to_string() const {
|
std::string stacktrace_frame::to_string() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << *this;
|
oss << *this;
|
||||||
|
|||||||
@ -88,18 +88,15 @@ CTRACE_FORMAT_EPILOGUE
|
|||||||
free_owning_string(owned_string.data);
|
free_owning_string(owned_string.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ctrace_object_frame convert_object_frame(const cpptrace::object_frame& frame) {
|
||||||
|
const char* new_path = generate_owning_string(frame.object_path).data;
|
||||||
|
return { frame.raw_address, frame.object_address, new_path };
|
||||||
|
}
|
||||||
|
|
||||||
static ctrace_object_trace c_convert(const std::vector<cpptrace::object_frame>& trace) {
|
static ctrace_object_trace c_convert(const std::vector<cpptrace::object_frame>& trace) {
|
||||||
std::size_t count = trace.size();
|
std::size_t count = trace.size();
|
||||||
auto* frames = new ctrace_object_frame[count];
|
auto* frames = new ctrace_object_frame[count];
|
||||||
std::transform(
|
std::transform(trace.begin(), trace.end(), frames, convert_object_frame);
|
||||||
trace.begin(),
|
|
||||||
trace.end(),
|
|
||||||
frames,
|
|
||||||
[] (const cpptrace::object_frame& frame) -> ctrace_object_frame {
|
|
||||||
const char* new_path = generate_owning_string(frame.object_path).data;
|
|
||||||
return { frame.raw_address, frame.object_address, new_path };
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return { frames, count };
|
return { frames, count };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,4 +422,13 @@ extern "C" {
|
|||||||
void ctrace_enable_inlined_call_resolution(ctrace_bool enable) {
|
void ctrace_enable_inlined_call_resolution(ctrace_bool enable) {
|
||||||
cpptrace::enable_inlined_call_resolution(enable);
|
cpptrace::enable_inlined_call_resolution(enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctrace_object_frame ctrace_get_object_info(const ctrace_stacktrace_frame* frame) {
|
||||||
|
try {
|
||||||
|
cpptrace::object_frame new_frame = cpptrace::detail::get_frame_object_info(frame->raw_address);
|
||||||
|
return ctrace::convert_object_frame(new_frame);
|
||||||
|
} catch(...) {
|
||||||
|
return {0, 0, nullptr};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user