2013-07-14 10 views
6

バイナリにビルド情報を追加するためにldの--build-idオプションを使いたいと思います。しかし、私はどのようにプログラム内でこの情報を利用できるようにするか分からない。例外が発生するたびにバックトレースを書き込むプログラムと、この情報を解析するスクリプトを記述したいとします。スクリプトはプログラムのシンボルテーブルを読み込み、バックトレースに表示されているアドレスを検索します(プログラムが静的にリンクされ、backtrace_symbolsが機能しないため、このようなスクリプトを使用することを余儀なくされます)。スクリプトが正しく動作するためには、バックトレースを作成したプログラムのビルドバージョンとプログラムのビルドバージョンを一致させる必要があります。 .note.gnu.build-id elfセクションにあるプログラムのビルド版をプログラム自体から印刷するにはどうすればよいですか?プログラムは独自のelfセクションを読むことができますか?

答えて

5

プログラムのビルドバージョン(.note.gnu.build-id elfセクションにあります)をプログラム自体から印刷するにはどうすればよいですか?

  1. はあなたが読む必要がElfW(Ehdr)にプログラムヘッダを見つけるために(ファイルの先頭)あなたのバイナリ(.e_phoff.e_phnumはプログラムヘッダがどこにあるかを教えてくれますし、それらを読むためにどのように多くの) 。

  2. 次に、プログラムのPT_NOTEセグメントが見つかるまで、プログラムヘッダーを読み取ります。そのセグメントは、バイナリ内のすべてのノートの先頭にオフセットするよう指示します。

  3. .n_type == NT_GNU_BUILD_IDでノートが見つかるまで、ElfW(Nhdr)を読み、残りのメモ(合計ノートサイズはsizeof(Nhdr) + .n_namesz + .n_descsz、正しく整列されています)をスキップする必要があります。

  4. NT_GNU_BUILD_IDというメモが見つかったら、その.n_nameszをスキップし、.n_descszバイトを読み取って実際のビルドIDを読み取ります。

あなたは、あなたがreadelf -n a.outの出力と読んだものと比較することによって、右のデータを読んでいることを確認することができます。

P.S.代わりに

あなたの実行ファイルが取り除かれていない場合はあなただけのデコードおよび印刷するためにあなたは、上記のように、ビルドIDをデコードする手間を通過しよう、とされている場合、それは良いかもしれシンボル名(すなわちへbacktrace_symbolsを複製する) - 実際には、シンボルテーブルに固定サイズのエントリが含まれているため、ELFノートをデコードするよりも簡単です。

+0

感謝。 – e271p314

2

基本的に、これは私の質問に与えられた答えに基づいて書いたコードです。コードをコンパイルするために私はいくつかの変更を加えなければならず、できるだけ多くの種類のプラットフォームで動作することを願っています。ただし、1台のビルドマシンでのみテストされました。私が使用した仮定の1つは、プログラムが実行されるマシン上にプログラムが構築されているため、プログラムとマシンの間のエンディアンの互換性をチェックすることができませんでした。答えるため

[email protected]:~/$ uname -s -r -m -o 
Linux 3.2.0-45-generic x86_64 GNU/Linux 
[email protected]:~/$ g++ test.cpp -o test 
[email protected]:~/$ readelf -n test | grep Build 
    Build ID: dc5c4682e0282e2bd8bc2d3b61cfe35826aa34fc 
[email protected]:~/$ ./test 
    Build ID: dc5c4682e0282e2bd8bc2d3b61cfe35826aa34fc 
#include <elf.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/mman.h> 
#include <sys/stat.h> 

#if __x86_64__ 
# define ElfW(type) Elf64_##type 
#else 
# define ElfW(type) Elf32_##type 
#endif 

/* 
detecting build id of a program from its note section 
http://stackoverflow.com/questions/17637745/can-a-program-read-its-own-elf-section 
http://www.scs.stanford.edu/histar/src/pkg/uclibc/utils/readelf.c 
http://www.sco.com/developers/gabi/2000-07-17/ch5.pheader.html#note_section 
*/ 

int main (int argc, char* argv[]) 
{ 
    char *thefilename = argv[0]; 
    FILE *thefile; 
    struct stat statbuf; 
    ElfW(Ehdr) *ehdr = 0; 
    ElfW(Phdr) *phdr = 0; 
    ElfW(Nhdr) *nhdr = 0; 
    if (!(thefile = fopen(thefilename, "r"))) { 
    perror(thefilename); 
    exit(EXIT_FAILURE); 
    } 
    if (fstat(fileno(thefile), &statbuf) < 0) { 
    perror(thefilename); 
    exit(EXIT_FAILURE); 
    } 
    ehdr = (ElfW(Ehdr) *)mmap(0, statbuf.st_size, 
    PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(thefile), 0); 
    phdr = (ElfW(Phdr) *)(ehdr->e_phoff + (size_t)ehdr); 
    while (phdr->p_type != PT_NOTE) 
    { 
    ++phdr; 
    } 
    nhdr = (ElfW(Nhdr) *)(phdr->p_offset + (size_t)ehdr); 
    while (nhdr->n_type != NT_GNU_BUILD_ID) 
    { 
    nhdr = (ElfW(Nhdr) *)((size_t)nhdr + sizeof(ElfW(Nhdr)) + nhdr->n_namesz + nhdr->n_descsz); 
    } 
    unsigned char * build_id = (unsigned char *)malloc(nhdr->n_descsz); 
    memcpy(build_id, (void *)((size_t)nhdr + sizeof(ElfW(Nhdr)) + nhdr->n_namesz), nhdr->n_descsz); 
    printf(" Build ID: "); 
    for (int i = 0 ; i < nhdr->n_descsz ; ++i) 
    { 
    printf("%02x",build_id[i]); 
    } 
    free(build_id); 
    printf("\n"); 
    return 0; 
} 
関連する問題