C

时间:2016-09-15 07:49:15

标签: c linux gdb bfd dladdr

在C程序中是否可以在运行时知道函数参数和变量的名称类型?例如,如果我有一个函数:

int abc(int x, float y , somestruct z ){
    char a;
    int b ;
}

我可以在这个函数abc()中知道,参数和变量的名称是什么在这种情况下是xy,{{1 }},za,它们的类型为bintfloatsomestructchar。< / p>

说是否还有其他功能:

int

我应该知道参数名称是float some_func(specialstruct my_struct, int index){ } my_struct,类型是indexspecialstruct

我在运行时需要这些信息吗?

我可以访问基指针和返回地址,我可以使用上面的指针获取所需的信息。

我能够使用返回地址和int函数提取函数名称。

我看到dladdr()这样做了,所以应该可以提取这些信息吗?

4 个答案:

答案 0 :(得分:1)

C中没有任何反射或类似的东西。如果你想要这样的设施 - 你应该为此目的设计一些实用程序,宏,并使用特殊的编码规则来达到预期的效果。但IMO - 它不是一个可读且易于理解的C代码。

答案 1 :(得分:1)

在C中实现这一点并不是真正的本地方式。在其他语言中,你要寻找的就是反思。你可以用宏和一些技巧来干酪,但是基于一个基本原则,你需要在编译时知道变量名和参数。

答案 2 :(得分:0)

共享库函数dlsymdladdr提供了一种有限的内省方式,提供了一个名称到地址,反之亦然。但是,这不是C语言的一部分,而是OS动态加载程序提供的功能。但是,您不能扣除,例如,您找到的符号是变量还是函数。

backtrace等构成了标准的GNU扩展,允许分析函数的调用堆栈(调用历史)。如果二进制文件中仍然存在符号(函数名称),backtrace_symbols将允许您检索它们。

__LINE____FILE__预定义宏提供了一种转储方式,也可以作为一些非常有用的跟踪宏的基础。

就是这样。 C不提供任何更多的内省。参数名称和类型在二进制文件中消失,函数签名也消失了,函数结果类型也消失了。

答案 3 :(得分:0)

正如其他人所说,反射不是内置于C或C ++语言中。有各种各样的想法here

但是,可以在C / C ++中使用第三方库并在可执行文件或外部文件中调试符号。

dwarfdump可执行文件或多或少可以满足您的需求。使用DWARF信息详细信息可以使用函数,变量,类型等。以类似的方式,进程可以使用libdwarfdump功能来检查自身。

以下是一个简单的手动示例:

typedef struct somestruct 
{
   int i;
   int j;
} somestruct ;

int abc(int x, float y , struct somestruct z ){
    char a;
    int b ;
}


int main(int argc, char* argv[])
{

   struct somestruct z;
   abc(1,1.0f,z);
   return 0;
}

和dwarfdump的部分输出

< 1><0x00000055>    DW_TAG_subprogram
                      DW_AT_external              yes(1)
                      DW_AT_name                  "abc"
                      DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                      DW_AT_decl_line             0x00000009
                      DW_AT_prototyped            yes(1)
                      DW_AT_type                  <0x0000004e>
                      DW_AT_low_pc                0x004004ed
                      DW_AT_high_pc               <offset-from-lowpc>18
                      DW_AT_frame_base            len 0x0001: 9c: DW_OP_call_frame_cfa
                      DW_AT_GNU_all_call_sites    yes(1)
                      DW_AT_sibling               <0x000000ad>
< 2><0x00000076>      DW_TAG_formal_parameter
                        DW_AT_name                  "x"
                        DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                        DW_AT_decl_line             0x00000009
                        DW_AT_type                  <0x0000004e>
                        DW_AT_location              len 0x0002: 916c: DW_OP_fbreg -20
< 2><0x00000082>      DW_TAG_formal_parameter
                        DW_AT_name                  "y"
                        DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                        DW_AT_decl_line             0x00000009
                        DW_AT_type                  <0x000000ad>
                        DW_AT_location              len 0x0002: 9168: DW_OP_fbreg -24
< 2><0x0000008e>      DW_TAG_formal_parameter
                        DW_AT_name                  "z"
                        DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                        DW_AT_decl_line             0x00000009
                        DW_AT_type                  <0x0000002d>
                        DW_AT_location              len 0x0002: 9160:        DW_OP_fbreg -32

通过仔细研究,我们可以看到片段定义了函数&abc&#39;与争论x,y和z。

参数x的类型是与键0x4e的类型表的间接。

在输出的其他地方,我们可以看到类型0x4e的定义。类型0x2d是连接到参数z的somestruct。

< 1><0x0000002d>    DW_TAG_structure_type
                      DW_AT_name                  "somestruct"
                      DW_AT_byte_size             0x00000008
                      DW_AT_decl_file             0x00000001 /tmp/dwarf.c
                      DW_AT_decl_line             0x00000003
                      DW_AT_sibling               <0x0000004e>

< 1><0x0000004e>    DW_TAG_base_type
                      DW_AT_byte_size             0x00000004
                      DW_AT_encoding              DW_ATE_signed
                      DW_AT_name                  "int"

ptrace,ELF,DWARF和/ proc文件系统的组合允许gdb读取进程的静态和动态信息。另一个进程可以使用类似的功能来创建Reflection功能。

我使用此策略的变体来创建自定义调试器和内存泄漏检测器。我从未见过这种用于业务逻辑的策略。