如何从 DWARF 导出字符串或数组的长度?
How to derive the length of a string or an array from DWARF?
下面的代码,经过GCC编译后,是否可以从DWARF中导出"teststr"和"testarray"变量的长度?
void func(char *str1, char *str2){
...
...
return;
}
int main(void){
char *teststr = "123456";
char testarray[6] = "123456";
func(teststr, testarray);
....
....
return 0;
}
DWARF 几乎代表了编译器对源程序的了解。所以这个问题的一般答案是:如果你能在源代码中找到大小"locally",那么是的;否则没有。
但在这种情况下,如果我们从您的程序中删除 ...
s 并编译它,我们可以直接使用 readelf
.
读取 DWARF
这是 main
中的 testarray
的样子:
<2><5c>: Abbrev Number: 3 (DW_TAG_variable)
<5d> DW_AT_name : (indirect string, offset: 0x5): testarray
<61> DW_AT_decl_file : 1
<62> DW_AT_decl_line : 7
<63> DW_AT_type : <0x7f>
<67> DW_AT_location : 2 byte block: 91 60 (DW_OP_fbreg: -32)
...
<1><7f>: Abbrev Number: 7 (DW_TAG_array_type)
<80> DW_AT_type : <0x78>
<84> DW_AT_sibling : <0x8f>
<2><88>: Abbrev Number: 8 (DW_TAG_subrange_type)
<89> DW_AT_type : <0x8f>
<8d> DW_AT_upper_bound : 5
<2><8e>: Abbrev Number: 0
<1><8f>: Abbrev Number: 6 (DW_TAG_base_type)
<90> DW_AT_byte_size : 8
<91> DW_AT_encoding : 7 (unsigned)
<92> DW_AT_name : (indirect string, offset: 0x60): sizetype
也就是6个字符的数组。所以在这种情况下,您可以找到长度——正是您阅读源代码所期望的长度。
然而 teststr
和 func
中的变量看起来更像:
<2><4e>: Abbrev Number: 3 (DW_TAG_variable)
<4f> DW_AT_name : (indirect string, offset: 0xf): teststr
<53> DW_AT_decl_file : 1
<54> DW_AT_decl_line : 6
<55> DW_AT_type : <0x72>
<59> DW_AT_location : 2 byte block: 91 68 (DW_OP_fbreg: -24)
...
<1><72>: Abbrev Number: 5 (DW_TAG_pointer_type)
<73> DW_AT_byte_size : 8
<74> DW_AT_type : <0x78>
<1><78>: Abbrev Number: 6 (DW_TAG_base_type)
<79> DW_AT_byte_size : 1
<7a> DW_AT_encoding : 6 (signed char)
<7b> DW_AT_name : (indirect string, offset: 0x7d): char
这表示它只是一个指向字符的指针——换句话说,长度不是静态已知的。像 gdb 这样的调试器可以在运行时通过从底层读取内存来找到长度,就像您的程序必须做的那样。
下面的代码,经过GCC编译后,是否可以从DWARF中导出"teststr"和"testarray"变量的长度?
void func(char *str1, char *str2){
...
...
return;
}
int main(void){
char *teststr = "123456";
char testarray[6] = "123456";
func(teststr, testarray);
....
....
return 0;
}
DWARF 几乎代表了编译器对源程序的了解。所以这个问题的一般答案是:如果你能在源代码中找到大小"locally",那么是的;否则没有。
但在这种情况下,如果我们从您的程序中删除 ...
s 并编译它,我们可以直接使用 readelf
.
这是 main
中的 testarray
的样子:
<2><5c>: Abbrev Number: 3 (DW_TAG_variable)
<5d> DW_AT_name : (indirect string, offset: 0x5): testarray
<61> DW_AT_decl_file : 1
<62> DW_AT_decl_line : 7
<63> DW_AT_type : <0x7f>
<67> DW_AT_location : 2 byte block: 91 60 (DW_OP_fbreg: -32)
...
<1><7f>: Abbrev Number: 7 (DW_TAG_array_type)
<80> DW_AT_type : <0x78>
<84> DW_AT_sibling : <0x8f>
<2><88>: Abbrev Number: 8 (DW_TAG_subrange_type)
<89> DW_AT_type : <0x8f>
<8d> DW_AT_upper_bound : 5
<2><8e>: Abbrev Number: 0
<1><8f>: Abbrev Number: 6 (DW_TAG_base_type)
<90> DW_AT_byte_size : 8
<91> DW_AT_encoding : 7 (unsigned)
<92> DW_AT_name : (indirect string, offset: 0x60): sizetype
也就是6个字符的数组。所以在这种情况下,您可以找到长度——正是您阅读源代码所期望的长度。
然而 teststr
和 func
中的变量看起来更像:
<2><4e>: Abbrev Number: 3 (DW_TAG_variable)
<4f> DW_AT_name : (indirect string, offset: 0xf): teststr
<53> DW_AT_decl_file : 1
<54> DW_AT_decl_line : 6
<55> DW_AT_type : <0x72>
<59> DW_AT_location : 2 byte block: 91 68 (DW_OP_fbreg: -24)
...
<1><72>: Abbrev Number: 5 (DW_TAG_pointer_type)
<73> DW_AT_byte_size : 8
<74> DW_AT_type : <0x78>
<1><78>: Abbrev Number: 6 (DW_TAG_base_type)
<79> DW_AT_byte_size : 1
<7a> DW_AT_encoding : 6 (signed char)
<7b> DW_AT_name : (indirect string, offset: 0x7d): char
这表示它只是一个指向字符的指针——换句话说,长度不是静态已知的。像 gdb 这样的调试器可以在运行时通过从底层读取内存来找到长度,就像您的程序必须做的那样。