http://www.skyfree.org/linux/references/bfd.pdf
libbfdを使えば、バイナリから情報を引き出し、プログラム中で利用することができる。これを使えば、今開発している命令セットシミュレータに、バイナリの情報を読み込んで、デバッグ情報を出力しながらシミュレーションを実行することができる。 また、現在開発中のluaインタフェースを結合しながら、luaでシミュレータを制御しながら、シミュレーション中にバイナリのデバッグ情報を使いながらシミュレーションができるようになる。
例えば、
- ある変数にアクセスする(グローバル変数の名前をバイナリから逆サーチしてアドレスを算出する)と、ブレークするようにする
- ある変数に10回アクセスするまでシミュレーションを繰替えす
ということが可能になる。
libbfdのインストール
まずは、libbfdをインストールする方法から調べよう。libbfdは、Ubuntuの環境ならば以下のようにしてインストールすることができる。
sudo aptitude install binutils-dev
libbfdを組み込んでコンパイルする場合は、-lbfdをgccのオプションとして追加する。
libbfdファーストインプレッション
普通のやつらの下を行け: BFDでデバッグ情報の取得 - bkブログ
ここらへんを参考にしている。
void show_debug_info (void *address) { asection *section = bfd_get_section_by_name(abfd, ".debug_info"); assert(section != NULL); const char *file_name; const char *function_name; unsigned int lineno; int found = bfd_find_nearest_line(abfd, section, symbols, (long)address, &file_name, &function_name, &lineno); if (found && file_name != NULL && function_name != NULL) { char tmp[strlen(file_name)]; strcpy(tmp, file_name); printf("%s:%s:%d\n", basename(tmp), function_name, lineno); } }
デバッグ情報をバイナリ(上記のコードではabfdというbfd情報)から抽出して、アドレスaddressに最も近い行数を探索している。
上記リンク先のプログラムをコンパイルするためには、以下のようにコンパイルする。
gcc -g bfd_openr.c -o bfd_openr -lbfd
-gを追加することにより、デバッグ情報が追加され、bfd_get_section_by_name()でデバッグ情報を抽出できるようになる。 -lbfdは、/usr/lib/libbfd.soをリンクしている。
libbfdを使って、バイナリ中のシンボル情報を出力してみる
以下のように作った。
#include <assert.h> #include <bfd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <libgen.h> #include <stdint.h> static bfd *abfd; static asymbol **symbols; static int nsymbols; int main (int argc, char *argv[]) { abfd = bfd_openr (argv[1], NULL); fprintf (stdout, "Filename = %s\n", abfd->filename); bfd_check_format (abfd, bfd_object); long storage_needed; asymbol **symbol_table; long number_of_symbols; long i; storage_needed = bfd_get_symtab_upper_bound (abfd); if (storage_needed < 0) { fprintf (stderr, "Error storage_needed < 0\n"); return 0; } if (storage_needed == 0) { fprintf (stderr, "Error storage_needed == 0\n"); return 0; } symbol_table = (asymbol **) malloc (storage_needed); number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); fprintf (stdout, "number_of_symbols=%ld\n", number_of_symbols); if (number_of_symbols < 0) { fprintf (stderr, "Error: number_of_symbols < 0\n"); return 0; } for (i = 0; i < number_of_symbols; i++) { asection *section = symbol_table[i]->section; fprintf (stdout, "SymbolName=%s : ", bfd_asymbol_name (symbol_table[i])); if ((symbol_table[i]->flags & BSF_FUNCTION) != 0x00) { fprintf (stdout, "BSF_Function "); } else if ((symbol_table[i]->flags & BSF_LOCAL) != 0x00) { fprintf (stdout, "BSF_Local "); } else if ((symbol_table[i]->flags & BSF_GLOBAL) != 0x00) { fprintf (stdout, "BSF_global "); } else { fprintf (stdout, "BSF_others "); } fprintf (stdout, "%08x %08x\n", bfd_asymbol_base (symbol_table[i]), bfd_asymbol_value (symbol_table[i])); } return 0; }
- bfd_openr () : バイナリを読み込んで、bfd情報を抽出する。
- bfd_check_format () : bfdのフォーマットをチェックする。
- bfd_get_symtab_upper_bound () : シンボルテーブルをロードするために、ロードする先のメモリの大きさを計算する。storage_neededの分だけmallocでメモリを確保する。
- bfd_cannonicalize_symtab () : 確保したメモリ領域に、シンボル情報をロードする。
number_of_symbolsに、シンボルリストの数が格納されるので、その分だけ後続のfor文をロードする。
- bfd_asymbol_name() : シンボルの名前を読み込む。
- bfd_asymbol_base() : シンボルの存在しているセクションのベースアドレスを取得する。
- bfd_asymbol_value() : シンボルの存在するアドレス情報を出力する。
for文中のcaseでは、フラグ(つまり、シンボルの型)に応じて出力する内容を変更している。
gcc bfd_openr_test.c -o bfd_openr_test -lbfd
このbfd情報はバイナリ間で互換性が取れているため、たとえ上記のプログラムをx86のLinux上でコンパイルしたとしても、例えばRISC-V用にクロスコンパイルしたバイナリファイルを解析することができる。 例えば、RISC-VバイナリとしてコンパイルしたCoremarkのシンボル情報を出力してみる。
./bfd_openr_test ~/benchmarks/coremark_v1.0/coremark.bin Filename = /home/vagrant/benchmarks/coremark_v1.0/coremark.bin number_of_symbols=90 SymbolName=.text.reset : BSF_Local 00000100 00000100 SymbolName=.data : BSF_Local 7f000000 7f000000 SymbolName=.sdata : BSF_Local 7f00000c 7f00000c SymbolName=.bss : BSF_Local 7f000018 7f000018 SymbolName=.sbss : BSF_Local 7f0007e8 7f0007e8 SymbolName=.text : BSF_Local 80000000 80000000 SymbolName=.text.startup : BSF_Local 80002034 80002034 SymbolName=.eh_frame : BSF_Local 8000276c 8000276c SymbolName=.rodata : BSF_Local 80002c08 80002c08 SymbolName=.rodata.str1.4 : BSF_Local 80002ebc 80002ebc SymbolName=.debug_info : BSF_Local 00000000 00000000 SymbolName=.debug_abbrev : BSF_Local 00000000 00000000 SymbolName=.debug_loc : BSF_Local 00000000 00000000 SymbolName=.debug_aranges : BSF_Local 00000000 00000000 SymbolName=.debug_ranges : BSF_Local 00000000 00000000 SymbolName=.debug_line : BSF_Local 00000000 00000000 SymbolName=.debug_str : BSF_Local 00000000 00000000 SymbolName=.comment : BSF_Local 00000000 00000000 SymbolName=./barebones_riscv_O3/startup.o : BSF_Local 00000000 00000000 SymbolName=_start : BSF_Local 00000100 00000100 SymbolName=format_regs : BSF_Local 00000100 00000110 SymbolName=loop : BSF_Local 00000100 00000190 SymbolName=core_list_join.c : BSF_Local 00000000 00000000 SymbolName=core_main.c : BSF_Local 00000000 00000000 SymbolName=list_known_crc : BSF_Local 80002c08 80002c08 SymbolName=matrix_known_crc : BSF_Local 80002c08 80002c14 SymbolName=state_known_crc : BSF_Local 80002c08 80002c20 SymbolName=core_matrix.c : BSF_Local 00000000 00000000 SymbolName=core_state.c : BSF_Local 00000000 00000000 SymbolName=intpat : BSF_Local 80002c08 80002c60 SymbolName=floatpat : BSF_Local 80002c08 80002c70 SymbolName=scipat : BSF_Local 80002c08 80002c80 SymbolName=errpat : BSF_Local 80002c08 80002c90 SymbolName=core_util.c : BSF_Local 00000000 00000000 SymbolName=core_portme.c : BSF_Local 00000000 00000000 SymbolName=start_time_val : BSF_Local 7f0007e8 7f0007ec SymbolName=stop_time_val : BSF_Local 7f0007e8 7f0007e8 SymbolName=ee_printf.c : BSF_Local 00000000 00000000 SymbolName=number : BSF_Function 80000000 80001610 SymbolName=seed1_volatile : BSF_global 7f0007e8 7f0007f8 SymbolName=core_list_init : BSF_Function 80000000 800006bc SymbolName=crcu32 : BSF_Function 80000000 80001568 SymbolName=check_data_types : BSF_Function 80000000 800015a8 SymbolName=stop_time : BSF_Function 80000000 800015c8 SymbolName=mem_name : BSF_global 7f000000 7f000000 SymbolName=core_list_reverse : BSF_Function 80000000 800002e8 SymbolName=crcu16 : BSF_Function 80000000 80001498 SymbolName=matrix_sum : BSF_Function 80000000 800009e4 SymbolName=portable_fini : BSF_Function 80000000 80001608 SymbolName=_gp : BSF_global 7f000000 7f000010 SymbolName=matrix_test : BSF_Function 80000000 80000c0c SymbolName=get_time : BSF_Function 80000000 800015dc SymbolName=core_bench_state : BSF_Function 80000000 8000120c SymbolName=core_bench_list : BSF_Function 80000000 80000454 SymbolName=matrix_mul_const : BSF_Function 80000000 80000a64 SymbolName=ee_printf : BSF_Function 80000000 80001864 SymbolName=seed3_volatile : BSF_global 7f00000c 7f000014 SymbolName=seed4_volatile : BSF_global 7f00000c 7f000010 SymbolName=iterate : BSF_Function 80000000 8000081c SymbolName=matrix_mul_matrix : BSF_Function 80000000 80000b28 SymbolName=cmp_complex : BSF_Function 80000000 80000164 SymbolName=core_state_transition : BSF_Function 80000000 80000fdc SymbolName=core_bench_matrix : BSF_Function 80000000 80000e78 SymbolName=core_list_mergesort : BSF_Function 80000000 8000030c SymbolName=start_time : BSF_Function 80000000 800015b8 SymbolName=seed5_volatile : BSF_global 7f0007e8 7f0007f0 SymbolName=_sp : BSF_global 00000000 7f004008 SymbolName=core_list_remove : BSF_Function 80000000 8000022c SymbolName=crc16 : BSF_Function 80000000 8000159c SymbolName=copy_info : BSF_Function 80000000 800001b4 SymbolName=core_list_undo_remove : BSF_Function 80000000 80000258 SymbolName=static_memblk : BSF_global 7f000018 7f000018 SymbolName=main : BSF_Function 80002034 80002034 SymbolName=barebones_clock : BSF_Function 80000000 800015b0 SymbolName=get_seed_32 : BSF_Function 80000000 800013e0 SymbolName=crcu8 : BSF_Function 80000000 80001430 SymbolName=matrix_mul_matrix_bitextract : BSF_Function 80000000 80000b90 SymbolName=core_list_insert_new : BSF_Function 80000000 800001c8 SymbolName=portable_init : BSF_Function 80000000 800015fc SymbolName=core_init_matrix : BSF_Function 80000000 800008b0 SymbolName=matrix_mul_vect : BSF_Function 80000000 80000adc SymbolName=matrix_add_const : BSF_Function 80000000 80000aa4 SymbolName=core_init_state : BSF_Function 80000000 80000eb8 SymbolName=time_in_secs : BSF_Function 80000000 800015ec SymbolName=uart_send_char : BSF_Function 80000000 80001860 SymbolName=seed2_volatile : BSF_global 7f0007e8 7f0007f4 SymbolName=core_list_find : BSF_Function 80000000 80000278 SymbolName=cmp_idx : BSF_Function 80000000 80000000 SymbolName=calc_func : BSF_Function 80000000 8000005c SymbolName=default_num_contexts : BSF_global 7f00000c 7f00000c
無事に、シンボル名、シンボルタイプ、グローバル変数、関数名の場合はアドレスが出力されている。これを拡張する形で、シミュレータに組み込んでいこう。