【问题标题】:gdb dump entire memory for bare metal programgdb 为裸机程序转储整个内存
【发布时间】:2021-12-12 11:28:09
【问题描述】:

我有一个简单的C程序如下:

int a = 10;
int b = 20;
int sum = 0;

void add() { sum = a + b; }

int main() {
  add();
  return 0;
}

我使用以下命令为 risc-v 编译它,并指定 .text 段应该从 0x1000 开始。

riscv32-unknown-elf-gcc -static -T elf32lriscv.x -Wl,-Ttext-segment=0x1000 -Wl,-Map=add.elf.map -o add.elf add.c

如果我使用 gdb 打印文件的信息,我会看到以下内容:

(gdb) i files
Symbols from "/home/mango/myp/risc-v/prog/add.elf".
Local exec file:
        `/home/mango/myp/risc-v/prog/add.elf', file type elf32-littleriscv.
        Entry point: 0x108c
        0x00001074 - 0x0000159c is .text
        0x0000259c - 0x000025a0 is .eh_frame
        0x000025a0 - 0x000025a8 is .init_array
        0x000025a8 - 0x000025ac is .fini_array
        0x000025b0 - 0x000029d8 is .data
        0x000029d8 - 0x000029ec is .sdata
        0x000029ec - 0x000029f0 is .sbss
        0x000029f0 - 0x00002a0c is .bss

有没有一种简单的方法可以将内存从0x1074转储到0x2a0c

dump memory 命令需要一个开始和结束地址,但由于这会根据程序而变化,我希望能够自动转储这个值。此外,这在 gdb 中显然可以访问,有没有办法自动获取它?

我的最终目标是为 gdb 创建一个命令文件并按如下方式传递它以自动进行内存转储:

gdb --command=gdb_commands <filename>

【问题讨论】:

    标签: c gdb elf


    【解决方案1】:

    GDB Python API 中似乎没有公开部分。

    您可以按照readelf -WS foo.elf | grep .bss 的行编写一个简单的shell 脚本来提取结束地址并为您编写gdb_commands 文件。

    更好的是:让脚本找出结束地址并为您运行 GDB,不需要 gdb_commandsgdb -ex 'dump binary memory $dump_filename $start $end' $elf

    提取PT_LOAD 段可能会更好,而不是将此脚本基于段以更可靠地防止段重新排序。

    更新:

    我猜你不关心部分,但关心段。

    这很有帮助。它告诉我内存的哪一部分是可写的。但它似乎只包括 data 和 sdata 而不是 bss 和 sbss。这是 gdb 和 readelf 的输出:http://pastebin.com/HdW12MzS

    Local exec file:
            `/home/mango/myp/risc-v/prog/add.elf', file type elf32-littleriscv.
            Entry point: 0x108c
            0x00001074 - 0x0000159c is .text
            0x0000259c - 0x000025a0 is .eh_frame
            0x000025a0 - 0x000025a8 is .init_array
            0x000025a8 - 0x000025ac is .fini_array
            0x000025b0 - 0x000029d8 is .data
            0x000029d8 - 0x000029ec is .sdata
            0x000029ec - 0x000029f0 is .sbss
            0x000029f0 - 0x00002a0c is .bss
    
    readelf -Wl add.elf
    ...
    Program Headers:
      Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
      LOAD           0x000000 0x00001000 0x00001000 0x0059c 0x0059c R E 0x1000
      LOAD           0x00059c 0x0000259c 0x0000259c 0x00450 0x00470 RW  0x1000
     
     Section to Segment mapping:
      Segment Sections...
       00     .text 
       01     .eh_frame .init_array .fini_array .data .sdata .sbss .bss 
    

    输出清楚地表明您关心的所有部分包含在第二个加载段中。

    .bss 的结尾是0x2a0c

    如果我使用具有 内存 大小的第二段,我会得到 0x259c + 0x470 == 0x2a0c -- 正是您正在寻找的答案。

    【讨论】:

    • 谢谢,我想我只需要使用脚本来获取此信息。您能否解释一下我如何获得PT_LOAD 段?我在网上搜索了一下,我并不清楚这是做什么用的以及如何提取它。
    • @PlastyGrove 检查来自readelf -Wl $elf 的输出。我猜你不关心节,但关心可执行和只读段。另见stackoverflow.com/a/14382477/50617
    • 其实我只需要可写段。解释一下,我正在设计自己的 risc-v cpu。我在自己的 cpu(模拟)上运行上面的程序,然后用模拟器(qemu)运行它并比较寄存器和内存。从 gdb 获取寄存器并将它们打印到文件中很容易。但是内存位置取决于程序。所以我想我会转储两者的所有片段并相互比较。
    • @PlastyGrove 可写段应该更容易——通常应该只有一个这样的段。
    • 但可写段由datasdatabsssbss组成。所以我至少需要转储这 4 个部分。为此,我需要知道确切的结束地址。 elf 文件中的这个结束地址因程序而异。
    猜你喜欢
    • 2018-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多