FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

libbfdを使ってバイナリのデータをダンプするプログラムを書く

Luaを使ってシミュレータの制御ができるようになったので、次はlibbfdを使ってバイナリファイルからデータを取得してシミュレータに流し込めるようにしよう。

現在のシミュレータはsrecファイルを使っているので、取り扱いとしては簡単だが、情報が限定されているので、バイナリから様々な情報を取得することができない。

そこで、bfdからバイナリデータを取得してシミュレータに流し込み、デバッグに活用できるようにする。

github.com

とりあえず、サンプルプログラムを書いてみた。./bfd_test/bfd_symbol.cpp だ。このプログラムは、バイナリファイルを読み込んで、そのプログラムとデータをダンプするプログラムだ。

これは、ほぼ全てが、以下の書籍に書いてあることを参考してある。唯一違うのは、コードのダンプ部分を省略して、コード部分はバイナリのみ表示している点だ。

books.google.co.jp

プログラムの肝となるのは、おそらく以下のところだと思う。

  1. プログラム中のセクションをtraverseする これは、以下のプログラムで実行可能らしい。
    // disasemble
    bfd_map_over_sections (abfd, disasm_section, NULL);

Untitled Document

Call the provided function func for each section attached to the BFD abfd, passing obj as an argument. The function will be called as if by
  1. テキストセクションか、データセクションかを判定する

セクションに付属しているflags変数を利用すれば良いらしい。

    if (section->flags & SEC_CODE) {
        if (!strncmp (".plt", section->name, 4) ||
            !strncmp (".got", section->name, 4)) {
            return;
        }
        disasm_section_code (b, section);
    } else if (section->flags & SEC_DATA ||
               section->flags & SEC_HAS_CONTENTS) {
        disasm_section_data (b, section);
    }
  1. セクション内のデータをロードする。

bfd_section_sizeでセクションの大きさを取得し、bfd_get_section_contentsでそのセクション内の情報を取得するようだ。

static void disasm_section_code (bfd *b, asection *section)
{
    int size;
    unsigned char *buf;

    size = bfd_section_size (b, section);
    buf = static_cast<unsigned char *>(calloc (size, 1));
    if (!buf || !bfd_get_section_contents (b, section, buf, 0, size))
...
}

static void disasm_section_data (bfd *b, asection *section)
{
    int i, j, size;
    unsigned char *buf;
    size = bfd_section_size (b, section);
    buf = static_cast<unsigned char *>(calloc (size, 1));
    if (!bfd_get_section_contents (b, section, buf, 0, size))
...
}
  1. データをダンプして表示する。

データセクションの方が分かりやすい。bfd_get_section_contents()によって取得したバッファを、順番に表示している。

    /* do hex dump of data */
    for (int i = 0; i < size; i+= 16) {
        printf ( "%08x:  ", section->vma + i);
        for (j = 0; j < 16 && j + 1 < size; j++) {
            printf ("%02x ", buf[i+j]);
        }
        for (; j < 16; j++) {
            printf ("    ");
        }
        printf ("  ");
        for (j = 0; j < 16 && j+i < size; j++) {
            printf ("%c", isprint (buf[i+j]) ? buf[i+j] : '.');
        }
        printf ("\n");
    }

テキストセクションは、逆アセンブルのための情報を出力する必要があるため多少複雑になってはいるが、やっていることはほぼ同じである。

    while (bytes < info->buffer_length) {
        // memset (&curr_insn, 0, sizeof (struct ASM_INSN));
        // size = (*disassemble_fn) (info->buffer_vma + bytes, info);
        size = 4;

        printf ("%8X:   ", info->buffer_vma + bytes);

        for (i = 0; i < 8; i++) {
            if (i < size) {
                printf ("%02x ", info->buffer[bytes + i]);
            } else {
                printf ("      ");
            }
        }
        printf ("\n");
        bytes += size;

このプログラムをコンパイルし(コンパイルにはlibbfdが必要)、バイナリファイルを読み込ませて実行すると、以下のような出力結果が得られる。

$ make
g++ -o bfd_symbol bfd_symbol.cpp -lbfd
bfd_symbol.cpp: In function ‘int main(int, char**)’:
bfd_symbol.cpp:77:112: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘bfd_vma {aka long unsigned int}’ [-Wformat=]
         fprintf (stdout, "%08x %08x\n", bfd_asymbol_base (symbol_table[i]), bfd_asymbol_value (symbol_table[i]));
                                                                                                                ^
bfd_symbol.cpp:77:112: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘bfd_vma {aka long unsigned int}’ [-Wformat=]
bfd_symbol.cpp: In function ‘void disasm_section_data(bfd*, asection*)’:
bfd_symbol.cpp:137:45: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘bfd_vma {aka long unsigned int}’ [-Wformat=]
         printf ( "%08x:  ", section->vma + i);
                                             ^
bfd_symbol.cpp: In function ‘void print_section_header(asection*, const char*)’:
bfd_symbol.cpp:159:46: warning: format ‘%o’ expects argument of type ‘unsigned int’, but argument 2 has type ‘bfd_vma {aka long unsigned int}’ [-Wformat=]
             s->vma, s->lma, s->flags, s->size);
                                              ^
bfd_symbol.cpp:159:46: warning: format ‘%o’ expects argument of type ‘unsigned int’, but argument 3 has type ‘bfd_vma {aka long unsigned int}’ [-Wformat=]
bfd_symbol.cpp:159:46: warning: format ‘%X’ expects argument of type ‘unsigned int’, but argument 5 has type ‘bfd_size_type {aka long unsigned int}’ [-Wformat=]
bfd_symbol.cpp: In function ‘int disassemble_buffer(disassembler_ftype, disassemble_info*)’:
bfd_symbol.cpp:206:52: warning: format ‘%X’ expects argument of type ‘unsigned int’, but argument 2 has type ‘bfd_vma {aka long unsigned int}’ [-Wformat=]
         printf ("%8X:   ", info->buffer_vma + bytes);
                                                    ^
$ make run
...
Disassembly of section .data as data
RVA: 177000000008X LMA: 177000000008X Flags: 4438X Size: C
-------------------------------------------------------
7f000000:  d0 30 00 80 d8 30 00 80 e0 30 00                       .0...0...0..
Disassembly of section .sdata as data
RVA: 177000000148X LMA: 177000000148X Flags: 4438X Size: C
-------------------------------------------------------
7f00000c:  01 00 00 00 01 00 00 00 66 00 00                       ........f...
Disassembly of section .text as code
RVA: 200000000008X LMA: 200000000008X Flags: 4338X Size: 22E8
-------------------------------------------------------
80000000:   63 0a 06 00
80000004:   03 15 25 00
80000008:   83 97 25 00
8000000C:   33 05 f5 40
80000010:   67 80 00 00
80000014:   03 17 05 00
80000018:   93 17 07 01
8000001C:   93 d7 07 01
80000020:   13 77 07 f0
80000024:   93 d7 87 00
80000028:   b3 67 f7 00
8000002C:   23 10 f5 00
80000030:   03 97 05 00
80000034:   03 15 25 00
80000038:   93 17 07 01
8000003C:   93 d7 07 01
80000040:   13 77 07 f0
80000044:   93 d7 87 00
80000048:   b3 67 f7 00
8000004C:   23 90 f5 00
80000050:   83 97 25 00
80000054:   33 05 f5 40
80000058:   67 80 00 00
8000005C:   13 01 01 fe
80000060:   23 2c 81 00
80000064:   03 14 05 00
80000068:   23 2e 11 00
8000006C:   23 2a 91 00
80000070:   93 57 74 40
80000074:   93 f7 17 00
80000078:   23 28 21 01
8000007C:   23 26 31 01
80000080:   63 98 07 0c
80000084:   93 57 34 40
80000088:   93 f7 f7 00
8000008C:   13 97 47 00
80000090:   93 76 74 00
80000094:   13 89 05 00
80000098:   93 09 05 00
8000009C:   33 e7 e7 00
800000A0:   63 8a 06 06
800000A4:   93 07 10 00
800000A8:   63 98 f6 0a
800000AC:   03 d6 85 03
...


Disassembly of section .rodata as data
RVA: 200000250508X LMA: 200000250508X Flags: 4538X Size: 294
-------------------------------------------------------
80002a28:  b0 d4 40 33 79 6a 14 e7 c1 e3 00 00 52 be 99 11   ..@3yj......R...
80002a38:  08 56 d7 1f 47 07 00 00 47 5e bf 39 a4 e5 3a 8e   .V..G...G^.9..:.
80002a48:  84 8d 00 00 08 11 00 80 08 11 00 80 44 11 00 80   ............D...
80002a58:  44 11 00 80 50 11 00 80 78 31 00 80 80 31 00 80   D...P...x1...1..
80002a68:  88 31 00 80 90 31 00 80 48 31 00 80 54 31 00 80   .1...1..H1..T1..
80002a78:  60 31 00 80 6c 31 00 80 18 31 00 80 24 31 00 80   `1..l1...1..$1..
80002a88:  30 31 00 80 3c 31 00 80 e8 30 00 80 f4 30 00 80   01..<1...0...0..
80002a98:  00 31 00 80 0c 31 00 80 f4 16 00 80 d4 16 00 80   .1...1..........
80002aa8:  dc 16 00 80 e4 16 00 80 ec 16 00 80 cc 16 00 80   ................
80002ab8:  d0 1c 00 80 38 1c 00 80 38 1c 00 80 c4 1c 00 80   ....8...8.......
...

おおー、出力できた!今度は、これをISS側から参照できるようにすれば良いのか。