-
Notifications
You must be signed in to change notification settings - Fork 80
Use Relative Virtual Addresses to allow their decoding without knowing the base address #200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
95312e7
a15867f
75aefd3
9df0f24
412167d
9c2bfa2
bf9b566
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// Copyright Antony Polukhin, 2016-2024. | ||
// | ||
// 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_MSVC_HPP | ||
#define BOOST_STACKTRACE_DETAIL_ADDR_BASE_MSVC_HPP | ||
|
||
#include <boost/config.hpp> | ||
#ifdef BOOST_HAS_PRAGMA_ONCE | ||
# pragma once | ||
#endif | ||
|
||
#include <cstdio> | ||
#include <memory> | ||
|
||
#ifdef WIN32_LEAN_AND_MEAN | ||
#include <windows.h> | ||
#include <psapi.h> | ||
#else | ||
// Prevent inclusion of extra Windows SDK headers which can cause conflict | ||
// with other code using Windows SDK | ||
#define WIN32_LEAN_AND_MEAN | ||
#include <windows.h> | ||
#include <psapi.h> | ||
#undef WIN32_LEAN_AND_MEAN | ||
#endif | ||
|
||
namespace boost { namespace stacktrace { namespace detail { | ||
inline std::uintptr_t get_own_proc_addr_base(const void* addr) { | ||
// Try to avoid allocating memory for the modules array if possible. | ||
// The stack buffer should be large enough for most processes. | ||
HMODULE modules_stack[1024]; | ||
std::unique_ptr<HMODULE[]> modules_allocated; | ||
HMODULE* modules = modules_stack; | ||
|
||
DWORD needed_bytes = 0; | ||
uintptr_t addr_base = 0; | ||
|
||
HANDLE process_handle = GetCurrentProcess(); | ||
bool enum_process_result = EnumProcessModules(process_handle, modules, sizeof(modules), &needed_bytes); | ||
|
||
// Check if the error is because the buffer is too small. | ||
if (!enum_process_result && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { | ||
modules_allocated.reset(new HMODULE[needed_bytes / sizeof(HMODULE)]); | ||
modules = modules_allocated.get(); | ||
enum_process_result = EnumProcessModules(process_handle, modules, needed_bytes, &needed_bytes); | ||
} | ||
|
||
if (enum_process_result) { | ||
for (std::size_t i = 0; i < (needed_bytes / sizeof(HMODULE)); ++i) { | ||
MODULEINFO module_info; | ||
|
||
// Get the module name | ||
if (GetModuleInformation(process_handle, modules[i], &module_info, sizeof(module_info)) | ||
&& module_info.lpBaseOfDll <= addr && addr < LPBYTE(module_info.lpBaseOfDll) + module_info.SizeOfImage) { | ||
// Module contains the address | ||
addr_base = reinterpret_cast<std::uintptr_t>(module_info.lpBaseOfDll); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
CloseHandle(process_handle); | ||
|
||
return addr_base; | ||
} | ||
|
||
}}} // namespace boost::stacktrace::detail | ||
|
||
#endif // BOOST_STACKTRACE_DETAIL_ADDR_BASE_MSVC_HPP |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
|
||
#include <boost/stacktrace.hpp> | ||
#include <stdexcept> | ||
#include <fstream> | ||
#include <iostream> | ||
#include <sstream> | ||
#include <cctype> | ||
|
@@ -263,7 +264,51 @@ void test_stacktrace_limits() | |
BOOST_TEST_EQ(boost::stacktrace::stacktrace(1, 1).size(), 1); | ||
} | ||
|
||
int main() { | ||
std::size_t get_file_size(const char* file_name) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should these helper functions be here or you prefer to move them to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is fine to remain here |
||
std::ifstream file(file_name, std::ios::binary | std::ios::ate); | ||
const auto file_size = file.tellg(); | ||
BOOST_TEST(file_size > 0); | ||
return static_cast<std::size_t>(file_size); | ||
} | ||
|
||
uintptr_t get_address_from_frame(const std::string& frame) { | ||
std::size_t address = 0; | ||
std::string hex_address; | ||
std::size_t pos = frame.find("0x"); | ||
|
||
if (pos != std::string::npos) { | ||
// Extract the hex address substring | ||
hex_address = frame.substr(pos + 2); // Skip "0x" | ||
|
||
// Convert hex string to std::size_t | ||
std::stringstream ss; | ||
ss << std::hex << hex_address; | ||
ss >> address; | ||
} | ||
|
||
return address; | ||
} | ||
|
||
void test_relative_virtual_address(const char* file_path) | ||
{ | ||
const auto frame = to_string(boost::stacktrace::stacktrace(0, 1).as_vector().front()); | ||
|
||
// Skip the test if the frame does not contain an address | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was trying to use |
||
if (frame.find("0x") == std::string::npos) { | ||
return; | ||
} | ||
|
||
const auto file_size = get_file_size(file_path); | ||
BOOST_TEST(file_size > 0); | ||
|
||
const auto address = get_address_from_frame(frame); | ||
BOOST_TEST(address > 0); | ||
|
||
// Verify that the address is within the binary | ||
BOOST_TEST(address <= file_size); | ||
} | ||
|
||
int main(const int, const char* argv[]) { | ||
test_deeply_nested_namespaces(); | ||
test_frames_string_data_validity(); | ||
test_nested<15>(); | ||
|
@@ -283,6 +328,7 @@ int main() { | |
test_nested<260>(false); | ||
|
||
test_stacktrace_limits(); | ||
test_relative_virtual_address(argv[0]); | ||
|
||
return boost::report_errors(); | ||
} |
Uh oh!
There was an error while loading. Please reload this page.