如果用调试信息编译,则通过其名称获取全局变量地址
Get global variable address by its name if compiled with debug information
如果我使用gcc编译一些C/c++程序并打开-g和/或-ggdb,那么如果我使用gdb启动程序,我可以在gdb中打印变量值。
我的问题是,没有gdb,我能从程序内部实现同样的事情吗?在运行时,给定变量的名称(表示为运行时字符串),是否有可能读取调试信息,然后获得变量的地址以及类型信息?
谢谢。
地图文件呢?它将拥有所有全局变量及其地址的信息。你所要做的就是解析映射文件并获取变量的地址(python可以在这里提供帮助)。
在你的程序中写一个小程序来接受地址和返回值。如果你用它来记录日志,你可以用一个新的线程在套接字事件上完成它,这样你就不会和实际的程序有太多的交集。我没有这样做,但与objdump/dltool它应该能够获得变量类型信息,我也不确定如何避免非法地址访问(那些会导致SEG和BUS错误)。
关于第二个想法,是什么阻止您使用GDB本身?您可以使用映像的剥离版本来运行和调试启用系统的映像,以获取变量类型和地址信息。
不需要任何第三方程序或大型库,您可以使用几个宏添加简单的反射,这取决于您希望它有多丑
下面是一个工作示例:
#include <map>
#include <stdio.h>
#include <iostream>
#include <string>
#define DEBUG_VAR_NAMES //undef to remove the tracking
struct GlobalRecord{ //will hold info about variables
const char* name;
const char* type;
const void* addr;
};
#ifdef DEBUG_VAR_NAMES
static const GlobalRecord* global_decl( const char* name, bool set, const GlobalRecord* record ){
static std::map<const char*, const GlobalRecord*> globals; //holds pointers to all record structs
if( set )
globals[name] = record;
const auto it = globals.find( name );
if( it == globals.end() )
return nullptr; //just return nullptr if a var could not be found
else
return it->second;
}
static GlobalRecord global_init( const char* type, const char* name, void* addr, const GlobalRecord* record ) {
global_decl( name, true, record );
return GlobalRecord{ name, type, addr };
}
#define COMMA ,
#define DECLARE_GLOBAL_INIT(type, name, init) type name = init; GlobalRecord name##_rec = global_init( #type, #name, (void*)&name, & name##_rec)
#define DECLARE_GLOBAL(type, name) type name; GlobalRecord name##_rec = global_init( #type, #name, (void*)&name, & name##_rec)
#define GET_GLOBAL(name) global_decl(name, false, nullptr)
#else
#define COMMA ,
#define DECLARE_GLOBAL_INIT(type, name, init) type name = init;
#define DECLARE_GLOBAL(type, name) type name;
#define GET_GLOBAL(name) ((const GlobalRecord*) nullptr) //This is a bad idea(TM).
#endif
//SAMPLE HERE
//Declare 3 global vars for testing.
//declaring a variable is pretty simple.
//it's a macro call with <type>, <name>, <optional init value> as arguments:
DECLARE_GLOBAL_INIT( int, my_int, 5 ); //instead of: int my_int = 5;
DECLARE_GLOBAL_INIT( std::string, my_string, "hi there" ); //instead of std::string my_string = "hi there";
DECLARE_GLOBAL( std::map<int COMMA int>, my_map ); //<- commas must be replaced with a macro
void print_var( const char* name ){
std::cout << 'n';
if( GET_GLOBAL( name ) == nullptr ){
std::cout << "Var " << name << " not found.n";
return;
}
std::cout << "Variable: " << GET_GLOBAL( name )->name << "n";
std::cout << "The address of " << name << " is recorded as: " << GET_GLOBAL( name )->addr << "n";
std::cout << "The type of " << name << " is recorded as : " << GET_GLOBAL( name )->type << "n";
}
int main(int argc, char* argv[])
{
print_var( "my_int" );
print_var( "my_string" );
print_var( "my_map" );
print_var( "my_double" );
return 0;
}
基本上所有全局变量都需要声明为宏,如DECLARE_GLOBAL(type, name)
。关于变量的一些基本信息将自动存储在global_decl
中的std::map
中,并且可以从那里检索。
它涉及一堆琐碎的hack,可能不应该这样使用。它更像是一个指针,让你知道如何做到这一点。
该方法的优点是开销几乎为零。您的程序读/写变量时不需要调用样板代码。最糟糕的部分是宏。
如果您正在寻找一个不需要修改代码的解决方案,您最好使用gdb或类似的工具。
相关文章:
- 如何在C++中获取该对象的类声明中对象的地址?
- 如何使用 Boost Asio 在 Android 上获取我的本地 udp IP 地址?
- 如何获取C++字符数据类型的地址
- 如果 const 不分配内存,为什么我可以获取 const 的地址?
- 如何在 c++ stl 中获取列表中被推回的元素的地址,在常量时间内?
- 是否可以在C++中获取 CHAR 的有效十六进制地址?
- 动态获取 esp32 的 mac 地址并在以太网库中使用它.
- 获取 R 数据帧的内存地址
- 获取通用/前向引用地址有什么意义?
- 获取函数的地址?
- 获取指针的地址会为其分配一个值
- Assimp 库错误:获取打包成员的地址
- 有没有可以直接获取地址的右值?
- 在char*类型上使用static_cast获取地址,并获得24位和48位地址
- 从套接字获取地址系列.Linux
- 为什么在解析 main() 参数时获取地址值
- 获取地址在数组2d中的位置
- 在c++中获取地址的内容
- 如何在c#函数中从委托中获取地址
- 无法获取地址 (wcsstr) - 未定义的变量