ELFファイルのDWARF情報から、構造体のメンバのアドレスを求める方法

いつもお世話になっております。

マイコン内のROM/RAM内の任意の変数の値をモニタする
PCアプリを作成しようとしています。
手順としては下記を考えています。 

①ビルドして出来上がったabsファイル(ELF形式)に対して、
 objdumpを実行しDWARF情報を取り出す。

②取り出したDWARF情報から、変数のアドレスを求める。

③PCアプリから、求めた変数のアドレスを参照し、
 UARTでマイコンのROM/RAMの変数の値を取得する。

mapファイルからでなく、DWARF情報から変数のアドレスを求めるのは、
他のマイコンでも同じ方法で、アドレスを求めたいからです。

②を効率よくやる方法をご存知であれば、教えていただけないでしょうか?

例えば、下記のようなネストされた構造体の各メンバや、
多次元の配列の各要素のアドレスをDWARF情報から求めたいです。
具体例を出すと、struct2.struct1[10][1][2].b[3][1]
のアドレスを求めたいです。

何かいい方法はありますか?
地道にDWARF情報を解析するしかないのでしょうか。
よろしくお願いいたします。


typedef struct{
unsigned char a[10];
unsigned short b[10][10];
unsigned int c;
unsigned char d;
}struct1_t;

 

typedef struct{
unsigned long e;
unsigned char f[10][3][12][3];
float g;
double h[40];
struct1_t struct1[34][2][3];
}struct2_t;


struct2_t struct2;


参考にしているサイト
https://qiita.com/tobira-code/items/de16088be23021e75c74

 

 

 

  • dracenさん、こんにちは。NoMaYです。#私がリプライするのは半年ぶりぐらいでしょうか。

    それだ!というリプライが無かった場合の代替案としてですが、gdbで以下のようなスクリプトを引数で指定してコマンドライン起動せさるというのはどうでしょうか?

    (1) ELF/DWARFのシンボル情報のみloadする
    (2) print系のコマンドで構造体のメンバのアドレスを表示させる
    (3) 終了コマンドでgdbを終了させる

    もし、targetコマンド無しで思うように出来なければ、target sim(だったかな?)して試してみる。

    というのはどうでしょうか?(すみません、gdbをさわる時はいつもhelpコマンド(だったかな?)とグーグル先生頼りでしたので、具体的なコマンドは提示出来ないですけれど、、、)

  • NoMaYさん、こんにちは。

    半年前は助けていただき、ありがとうございました。

    ご提案ありがとうございます。
    ここらへんの話を聞ける人が周りにいないので、とても嬉しいです。

    記載不足ですみませんが、アドレスを求めたい変数や構造体が
    数個レベルではなく、数千個あります。
    なので、提案いただいた(1)、(2)、(3)を自動化する必要がありそうですね。

    (1)では、ネストされた構造体のメンバや多次元配列の全要素のアドレスを求めるために、
    シンボル情報とデータ構造から下記のように列挙していかないといけませんね。

    struct2.struct1[10][1][2].a[0]
    ・・・
    struct2.struct1[10][1][2].b[3][1]
    ・・・
    struct2.struct1[10][1][2].c
    こんな感じで、ひたすら列挙していく感じでしょうか。

    (2)(3)では、gdbで構造体の各メンバ・配列の各要素のアドレスを自動で収集してくるんですね。
    CS+を使って開発しているので、pythonでCS+を操作する方法を調べてみます。

    シミュレータか実機が必要な方法をご提案いただいたのですが、
    それらが不要な方法を、考えてみます。

    となると、やはりDWARF情報を地道に解析するしかないのか。
    100万行以上あるので、どうやったら楽にできるか悩んでます。


    ありがとうございました。
  • dracenさん、こんにちは。NoMaYです。

    数千個ということは、以下のステップで取得する個々の変数も数千個で、手作業で指定する(入力する)のではない、ということですかね?

    > ③PCアプリから、求めた変数のアドレスを参照し、
    >  UARTでマイコンのROM/RAMの変数の値を取得する。

    それとも、数千個というのは、あくまで候補の数であって、上記ステップで一度に値を取得する変数は数個~十数個なのでしょうか?

  • >数千個ということは、以下のステップで取得する個々の変数も数千個で、手作業で指定する(入力する)のではない、ということですかね?

    その通りです。
    以下のステップで取得する個々の変数も数千個で、手作業で指定する(入力する)のではないです。

    ソフトに存在する全ての変数(数千個)に対して、
    構造体の全メンバ・配列の全要素のアドレスを求めたいです。
  • dracenさん、こんにちは。NoMaYです。

    そういうことでしたか。あとは、私が出せる情報となると、以下の辺りかなと思いました。

    (1) gdbの中でもPythonコマンドを実行させることが出来ます。Pythonスクリプトを実行させることや、そのスクリプトの中でgdbコマンドを実行して実行結果を文字列変数に格納することも出来るのでないだろうかとは思っているのですが、踏み込んだ調査をしたことまではないです。(gdbで今回の件に使えそうなコマンドとしては以下のウェブページのコマンドが考えられます。)

    (2) 或いは、普通にPython(或いは他の種類のスクリプト実行環境や自作のプログラム)からgdbをバックグランドで実行して、gdbの標準入出力をスクリプト実行環境側や自作のプログラム側へリダイレクトすることで、スクリプトからをgdbを制御する手も考えられます。(同上)

    (3) Python上でELF/DWARFを読むPyelftoolsというものがあります。(以下のリンクを参照して下さい。)

    (4) たぶんGCC向けですがELF/DWARFを読むC言語ライブラリのLibdwarfというものがあります。(以下のリンクを参照して下さい。)

    ●Pyelftools

    User's guide
    github.com/eliben/pyelftools/wiki/User's-guide

    Source code
    github.com/eliben/pyelftools

    PyPI
    pypi.org/project/pyelftools

    ●Libdwarf

    Home page
    www.prevanders.net/dwarf.html

    ●GDB
    www.asahi-net.or.jp/~wg5k-ickw/html/online/gdb-4.18/gdb_11.html

    シンボル・テーブルの検査
    ここで説明するコマンドによって、 ユーザ・プログラムの中で定義されているシンボル情報 (変数名、 関数名、 型名) に関する問い合わせを行うことができます。 …以後省略…


    info address symbol → 少し試してみましたが構造体メンバや配列要素には print &symbol を使わないとエラーになりました
    symbolで指定されるシンボルのデータがどこに格納されているかを示します。 …以後省略…


    ptype exp
    式expの型に関する説明を表示します。 単に型の名前を表示するだけではなく、 詳細な説明も表示するという点で、 ptypeはwhatisと異なります。 …以後省略…


    info variables
    関数の外部で宣言されているすべての変数 (つまり、 ローカル変数を除く変数) の名前とデータ型を表示します。


    実行例の画面コピー (なお、ICEにもSimulatorにも接続していません)



     

  • NoMaYさん、こんばんは。
    返信が遅くなってすみません。

    提案していただいた方法で、試してみようと思います。
    また、結果を報告させていただきます
  • こんばんは。お久しぶりです。

    教えていただいた情報をもとに試行錯誤したのですが、
    結局DWARF情報を地道にパースして
    全構造体の全メンバのアドレスのリストを取得しました。

    ありがとうございました!