如果使用調試信息進行編譯,則按名稱獲取全局變量地址

[英]Get global variable address by its name if compiled with debug information


If I compile some C/C++ program using gcc with -g and/or -ggdb turned on, then if I start the program using gdb, I can print variable value inside gdb.

如果我使用gcc編譯一些C / C ++程序並打開-g和/或-ggdb,那么如果我使用gdb啟動程序,我可以在gdb中打印變量值。

My question is, without gdb, can I achieve the same thing from inside the program? At runtime, given the name of the variable (represented as a runtime string), is it possible to read the debug information and then get the address of the variable as well as the type information?

我的問題是,沒有gdb,我可以從程序內部實現同樣的功能嗎?在運行時,給定變量的名稱(表示為運行時字符串),是否可以讀取調試信息,然后獲取變量的地址以及類型信息?

Thanks.

2 个解决方案

#1


0  

How about about map file ? It will have info of all globals and its address. All you have to do is parse the map file and get address of the variable (python can help here).

關於地圖文件怎么樣?它將包含所有全局變量及其地址的信息。您所要做的就是解析映射文件並獲取變量的地址(python可以在這里提供幫助)。

In your program write a small routine to accept address and return value. If you are using it for logging like purpose you can do it over sockets event with a new thread so you don't interfear much with actual progarm.

在你的程序中寫一個小例程來接受地址和返回值。如果您正在使用它進行類似的日志記錄,則可以使用新線程在套接字事件上執行此操作,這樣您就不會對實際的progarm進行很多干擾。

I have not done this but with objdump / dltool it should be able to get the variable type information, also I am not sure how you can avoid illegal address access (ones that will cause SEG and BUS errors).

我沒有這樣做但是使用objdump / dltool它應該能夠獲取變量類型信息,我也不確定如何避免非法地址訪問(會導致SEG和BUS錯誤)。

On the secod thought what is stopping you from using GDB itself ? You could use stripped version of the image to run and debug sym enabled inage to get variable type and address infomation.

在想法是什么阻止你使用GDB本身?您可以使用圖像的剝離版本來運行並調試sym enabled inage以獲取變量類型和地址信息。

#2


0  

Without any third-party programs or big libraries, you can add simple reflection with a few macros, depending on how ugly you'd like to have it

沒有任何第三方程序或大型庫,您可以使用一些宏添加簡單的反射,具體取決於您想要它的丑陋程度

Here's a working sample:

這是一個工作樣本:

#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;
}

Basically all global variables need to be declared as a macro such as DECLARE_GLOBAL(type, name). Some basic info about the variable will then automatically be stored inside a std::map in global_decl and can be retrieved from there.

基本上所有全局變量都需要聲明為宏,例如DECLARE_GLOBAL(type,name)。然后,關於變量的一些基本信息將自動存儲在global_decl中的std :: map中,並可從那里檢索。

It involves a bunch of petty hackery and should probably not be used just like that. It's more of a pointer to give you an idea of how it could be done.

它涉及一堆小小的hackery,應該不應該像那樣使用。它更像是一個指針,讓您了解如何完成它。

The good part about that method is that the overhead is practically zero. There is no boilerplate code that would have to be called for your program to read/write variables. The bad part is macros.

關於該方法的好處是開銷實際上為零。沒有必須為程序調用讀/寫變量的樣板代碼。壞的部分是宏。

If you are looking for a solution without changing your code at all, you're probably better off using gdb or a similar tool.

如果您正在尋找一個完全沒有改變代碼的解決方案,那么最好使用gdb或類似的工具。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2014/08/08/72f2c3010eca6722523dcea9b338f12a.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com