我们正在Linux下使用arm-eabi-gcc编译C程序。
我们正在使用一个大型结构的转储,并且我们无法确定应该读取结构的各个字段(例如50个字段)的地址(内存对齐和填充对我来说不太可预测)。
是否有任何方法可以获取由我们的编译器生成的结构的内存映射。 Gdb中的选项?或者任何帮助我们在转储中找到字段和地址对应关系的工具?
您可以使用 gdb
来完成此操作。作为一个例子,我将使用这个源码:
struct A {
int a;
char b;
short c;
};
int main() {
struct A a;
}
在 gdb
中加载二进制文件:
(gdb) print (int)&((struct A*)0)->a
$1 = 0
(gdb) print (int)&((struct A*)0)->b
$2 = 4
(gdb) print (int)&((struct A*)0)->c
$3 = 6
更新:
如果你需要对大量字段进行操作,那么使用GDB的新Python接口可能会很方便(你需要使用最新版本的GDB才能使用它,我正在使用7.4版本)。我创建了offsets.py文件:
import gdb
class Offsets(gdb.Command):
def __init__(self):
super (Offsets, self).__init__ ('offsets-of', gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
argv = gdb.string_to_argv(arg)
if len(argv) != 1:
raise gdb.GdbError('offsets-of takes exactly 1 argument.')
stype = gdb.lookup_type(argv[0])
print argv[0], '{'
for field in stype.fields():
print ' %s => %d' % (field.name, field.bitpos//8)
print '}'
Offsets()
然后你可以在你的 .gdbinit 文件中添加:
python
sys.path.insert(0, '/path/to/script/dir')
import offsets
end
然后在GDB中使用它,如下所示:
(gdb) offsets-of "struct A"
struct A {
a => 0
b => 4
c => 6
}
这个脚本做了一些简化的假设,比如你不使用位域,并且它不会深入嵌套的结构体,但是如果需要,这些更改相对来说还是比较简单的。
.gdbinit
看起来很奇怪。为什么不使用source /path/to/script/dir/offsets.py
呢? - youfu如果有人在几年之后阅读这篇文章,或者通过搜索引擎结果找到了它:自GDB 8.1以来,其内置的ptype
命令具有用于此目的的/o
标志。
它将打印MyType成员的偏移量和大小,还会显示“空洞”(填充),例如:
(gdb) ptype /o MyType
/* offset | size */ type = class MyType {
/* 0 | 4 */ int foo;
/* XXX 4-byte hole */
/* 8 | 8 */ void* ptr;
/* total size (bytes): 16 */
}
您可以使用标准的stddef.h
中定义的offsetof()
宏从C程序中执行此操作。但是我不确定这是否是您想要的,因为您可能无法运行它(在主机上编译将返回错误的偏移量)。
#include <stdio.h>
#include <stddef.h>
struct A {
int a;
char b;
short c;
};
int main() {
printf("Offset of b in A is %zu\n", offsetof(struct A, b));
return 0;
}
然而,您可以使用一些技巧来获取已编译二进制文件的偏移量而不执行它。也许将偏移值分配给静态变量,并找到某种方式来获取其值。
对我来说,你可以编写一些类似于这样的代码来处理必填字段
struct MyStruct S;
int Offset_of_X=((long)&(S.X))-((long)&S);
计算在此编译情况下的字节偏移量。
这应该考虑到编译器可能存在的任何对齐问题。
x
),那么你应该能够在 gdb 中只输入print x
(或者如果是指针,则为print *x
)来转储所有成员。 - Mark Wilkins