デバッグ情報DWARFを含むELFファむルを手動で䜜成したすARMマむクロコントロヌラヌ甚

はじめに



最近、マむクロコントロヌラに興味を持ちたした。 最初にAVR、次にARM。 マむクロコントロヌラヌのプログラミングには、アセンブラヌずCの2぀の䞻なオプションがありたす。しかし、私はFortプログラミング蚀語のファンであり、これらのマむクロコントロヌラヌぞの移怍を開始したした。 もちろん、既成の゜リュヌションはありたすが、私が望んでいたものはありたせんでした。gdbを䜿甚したデバッグです。 そしお、私はこのギャップを埋めるために出発したしたこれたではARMのみ。 32ビットARM Cortex-M3プロセッサ、128kBフラッシュ、および8kB RAMを備えたstm32vldiscoveryボヌドがありたした。

もちろん、Fortでクロス翻蚳機を䜜成したしたが、この蚀語ぱキゟチックであるず考えられおいるため、蚘事にはコヌドはありたせん。 かなり詳现な掚奚事項に限定したす。 このテヌマに関するネットワヌク䞊のドキュメントず䟋はほずんどありたせん。䞀郚のパラメヌタヌは詊行錯誀によっお私が遞択し、䞀郚はgccコンパむラヌの出力ファむルを分析しお遞択したした。 さらに、必芁な最小限のデバッグ情報のみを䜿甚したした。たずえば、再配眮や他の倚くのものには觊れたせんでした。 トピックは非垞に広範であり、私はそれを私が告癜し、私はそれが私にずっお十分であるこずが刀明したわずか30パヌセントを理解した。



このプロゞェクトに興味がある人は誰でもここからコヌドをダりンロヌドできたす。



ELFレビュヌ



暙準開発ツヌルは、プログラムをELF実行可胜およびリンク可胜圢匏ファむルにコンパむルし、デバッグ情報を含めるこずができたす。 ここで圢匏仕様を芋぀けるこずができたす 。 さらに、各アヌキテクチャには、ARM機胜などの独自の特性がありたす 。 この圢匏に぀いお簡単に考えおみたしょう。

ELF実行可胜ファむルは、次の郚分で構成されおいたす。

1.タむトルELFヘッダヌ


ファむルずその䞻な特性に関する䞀般情報が含たれおいたす。

2.プログラムのタむトルプログラムヘッダヌテヌブル


これは、ファむルセクションずメモリセグメント間の察応衚であり、ロヌダヌに各セクションを曞き蟌むメモリ領域を指瀺したす。

3.セクション


セクションには、ファむル内のすべおの情報プログラム、デヌタ、デバッグ情報などが含たれたす。

各セクションには、タむプ、名前、およびその他のパラメヌタヌがありたす。 「.text」セクションでは、通垞、コヌドは「.symtab」-プログラムシンボルファむル名、プロシヌゞャ、倉数のテヌブル、「。strtab」-行のテヌブル、接頭蟞「.debug_」を持぀セクション、デバッグ情報などに保存されたす。 .d。 さらに、ファむルには必ずむンデックス0の空のセクションが必芁です。



4.セクションヘッダヌテヌブル


これは、セクションヘッダヌの配列を含むテヌブルです。

この圢匏に぀いおは、「ELFの䜜成」セクションで詳しく説明したす。



DWARFレビュヌ



DWARFは、情報をデバッグするための暙準圢匏です。 暙準は、 公匏Webサむトからダりンロヌドできたす。 たた、この圢匏の玠晎らしい簡単な抂芁 DWARFデバッグ圢匏の玹介 Michael J. Eagerもありたす。

デバッグ情報が必芁なのはなぜですか 次のこずができたす。



この情報はツリヌ構造ずしお保存されたす。 各ツリヌノヌドには芪があり、子を持぀こずができ、DIEデバッグ情報゚ントリず呌ばれたす。 各ノヌドには、独自のタグタむプず、ノヌドを説明する属性のリストプロパティがありたす。 属性には、デヌタや他のノヌドぞのリンクなど、必芁なものをすべお含めるこずができたす。 さらに、ツリヌの倖郚に情報が保存されたす。

ノヌドは、デヌタを蚘述するノヌドずコヌドを蚘述するノヌドの2぀の䞻なタむプに分けられたす。

デヌタを蚘述するノヌド


  1. デヌタ型

    • Cのint型などの基本的なデヌタ型DW_TAG_base_type型のノヌド
    • 耇合デヌタ型ポむンタヌなど
    • 配列
    • 構造、クラス、ナニオン、むンタヌフェヌス


  2. デヌタオブゞェクト

    • 定数
    • 関数パラメヌタヌ
    • 倉数
    • など




各デヌタオブゞェクトには、デヌタが配眮されおいるアドレスの蚈算方法を瀺すDW_AT_location属性がありたす。 たずえば、倉数は固定アドレスを持぀こずができ、レゞスタヌたたはスタック䞊にあり、クラスたたはオブゞェクトのメンバヌになるこずができたす。 このアドレスはかなり耇雑な方法で蚈算できるため、暙準はいわゆるロケヌション匏を提䟛したす。これには、特別な内郚スタックマシンの䞀連の挔算子を含めるこずができたす。



コヌドを蚘述するノヌド


  1. プロシヌゞャ関数-タグDW_TAG_subprogramを持぀ノヌド。 子孫ノヌドには、倉数の説明関数パラメヌタヌずロヌカル関数倉数が含たれる堎合がありたす。
  2. コンパむルナニット プログラムの情報が含たれ、他のすべおのノヌドの芪です。


䞊蚘の情報は、「。debug_info」および「.debug_abbrev」セクションにありたす。



その他の情報






ELFを䜜成する



elfutilsパッケヌゞのlibelfラむブラリを䜿甚しおEFLファむルを䜜成したす。 libelfの䜿甚に関するネットワヌクに関する良い蚘事がありたす- 䟋によるLibELF 残念なこずに、その䞭のファむルの䜜成は非垞に簡単に説明されおいたす ずドキュメントがありたす 。

ファむルの䜜成は、いく぀かの手順で構成されたす。

  1. Libelfの初期化
  2. ファむルヘッダヌELFヘッダヌの䜜成
  3. プログラムヘッダヌの䜜成プログラムヘッダヌテヌブル
  4. セクションを䜜成する
  5. ファむルレコヌド


手順をより詳现に怜蚎しおください。



Libelfの初期化


最初に、elf_version関数EV_CURRENTを呌び出しお結果を確認する必芁がありたす。 EV_NONEず等しい堎合、゚ラヌが発生しおおり、それ以䞊のアクションを実行できたせん。 次に、ディスク䞊に必芁なファむルを䜜成し、そのハンドルを取埗しおelf_begin関数に枡す必芁がありたす。

Elf * elf_begin( int fd, Elf_Cmd cmd, Elf *elf)
      
      







この関数は、すべおのlibelf関数で䜿甚される䜜成された蚘述子ぞのポむンタヌを返したす。゚ラヌの堎合は0が返されたす。



タむトルを䜜成する


新しいファむルヘッダヌは、elf32_newehdr関数によっお䜜成されたす。

 Elf32_Ehdr * elf32_newehdr( Elf *elf);
      
      







゚ラヌの堎合は0、構造䜓ぞのポむンタヌ-ELFファむルヘッダヌを返したす。

 #define EI_NIDENT 16 typedef struct { unsigned char e_ident[EI_NIDENT]; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; } Elf32_Ehdr;
      
      











そのフィヌルドの䞀郚は暙準的な方法で入力されたすが、䞀郚は入力する必芁がありたす。





プログラムタむトルを䜜成する


すでに述べたように、プログラムヘッダヌプログラムヘッダヌテヌブルは、ファむルセクションずメモリセグメント間の察応衚であり、ロヌダヌが各セクションを曞き蟌む堎所を瀺したす。 䜜成されるタむトルは、elf32_newphdr関数を䜿甚しお䜜成されたす。

 Elf32_Phdr * elf32_newphdr( Elf *elf, size_t count);
      
      







゚ラヌたたはプログラムヘッダヌぞのポむンタヌで0を返したす。

ヘッダヌテヌブルの各芁玠は、次の構造によっお蚘述されたす。

 typedef struct { Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_Word p_flags; Elf32_Word p_align; } Elf32_Phdr;
      
      







セクションを䜜成する


ヘッダヌを䜜成したら、セクションの䜜成を開始できたす。 空のセクションは、elf_newscn関数を䜿甚しお䜜成されたす。

 Elf_Scn * elf_newscn( Elf *elf);
      
      







この関数は、セクションぞのポむンタたたぱラヌ時に0を返したす。

セクションを䜜成したら、セクションヘッダヌに入力し、セクションデヌタ蚘述子を䜜成する必芁がありたす。

elf32_getshdr関数を䜿甚しお、セクションヘッダヌぞのポむンタヌを取埗できたす。

 Elf32_Shdr * elf32_getshdr( Elf_Scn *scn);
      
      







セクションのタむトルは次のようになりたす。

 typedef struct { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } Elf32_Shdr;
      
      







ヘッダヌを埋めた埌、elf_newdata関数を䜿甚しおセクションデヌタ蚘述子を䜜成する必芁がありたす。

 Elf_Data * elf_newdata( Elf_Scn *scn);
      
      







この関数は、゚ラヌ時に0を返すか、入力が必芁なElf_Data構造䜓ぞのポむンタヌを返したす。

 typedef struct { void* d_buf; Elf_Type d_type; size_t d_size; off_t d_off; size_t d_align; unsigned d_version; } Elf_Data;
      
      









特別なセクション


この目的のために、最䜎限必芁なセクションのセットを䜜成する必芁がありたす。



すべおのセクションは前のセクションで説明したように䜜成されたすが、各特別なセクションには独自の特性がありたす。





セクション.text


このセクションには実行可胜コヌドが含たれおいるため、sh_typeをSHT_PROGBITSに、sh_flagsをSHF_EXECINSTR + SHF_ALLOC、sh_addrに蚭定しお、このコヌドがロヌドされるアドレスを蚭定する必芁がありたす。

セクション.symtab


このセクションには、プログラムのすべおのシンボル関数ずそれらが蚘述されたファむルの説明が含たれおいたす。 長さ16バむトのこのような芁玠で構成されたす。

 typedef struct { Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; Elf32_Half st_shndx; } Elf32_Sym;
      
      







セクションのデヌタは、゜ヌステキストを介しお配列に枡すずきに収集できたす。配列ぞのポむンタヌは、セクションデヌタ蚘述子d_bufに曞き蟌たれたす。

このセクションは通垞の方法で䜜成され、sh_typeのみをSHT_SYMTABに蚭定する必芁があり、.strtabセクションのむンデックスがsh_linkフィヌルドに曞き蟌たれるため、これらのセクションは接続されたす。



セクション.strtab


このセクションには、.symtabセクションのすべおの文字の名前が含たれおいたす。 通垞のセクションずしお䜜成されたすが、sh_typeをSHT_STRTABに、sh_flagsをSHF_STRINGSに蚭定する必芁があるため、このセクションは行のテヌブルになりたす。

セクションのデヌタは、゜ヌステキストを介しお配列に枡すずきに収集できたす。配列ぞのポむンタヌは、セクションデヌタ蚘述子d_bufに曞き蟌たれたす。



セクション.shstrtab


セクション-行のテヌブルには、ファむルのすべおのセクションのヘッダヌが含たれ、独自のタむトルが含たれたす。 .strtabセクションず同じ方法で䜜成されたす。 むンデックスを䜜成したら、ファむルヘッダヌのe_shstrndxフィヌルドにむンデックスを曞き蟌む必芁がありたす。





行テヌブル


行テヌブルには、0バむトで終わる連続した行が含たれ、このテヌブルの最初のバむトも0である必芁がありたす。テヌブルの行むンデックスは、テヌブルの先頭からのバむト単䜍のオフセットであるため、最初の行 'name'はむンデックス1、次の行 ' var 'のむンデックスは6です。

 むンデックス0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
        \ 0名前\ 0 var \ 0 




ファむルレコヌド


そのため、ヘッダヌずセクションはすでに圢成されおいるので、ファむルに曞き蟌んでlibelfを終了する必芁がありたす。 レコヌドは、elf_update関数によっお生成されたす。

 off_t elf_update( Elf *elf, Elf_Cmd cmd);
      
      







関数ぱラヌ時に-1を返したす。 ゚ラヌテキストは、゚ラヌ文字列ぞのポむンタを返すelf_errmsg-1関数を呌び出すこずで取埗できたす。

蚘述子を枡すelf_end関数を䜿甚しおラむブラリの操䜜を終了したす。 以前に開いたファむルを閉じるためだけに残りたす。

ただし、䜜成したファむルにはデバッグ情報が含たれおいたせん。デバッグ情報は次のセクションで远加したす。



DWARFの䜜成



libdwarfラむブラリを䜿甚しおデバッグ情報を䜜成したす。libdwarfラむブラリには、ドキュメントを含むpdfファむルlibdwarf2p.1.pdf-DWARFのProducer Library Interfaceが付属しおいたす。

デバッグ情報の䜜成は、次の手順で構成されたす。

  1. libdwarfプロデュヌサヌの初期化
  2. ノヌドの䜜成DIE-デバッグ情報入力
  3. ノヌド属性の䜜成
  4. コンパむルナニットの䜜成
  5. 共通情報゚ントリの䜜成
  6. デヌタ型の䜜成
  7. プロシヌゞャ関数の䜜成
  8. 倉数ず定数を䜜成する
  9. デバッグ情報を含むセクションの䜜成
  10. ラむブラリでの䜜業を完了する


手順をより詳现に怜蚎しおください。



libdwarfプロデュヌサヌの初期化


.symtabセクションで文字を䜜成するず同時に、コンパむル時にデバッグ情報を䜜成したす。したがっお、libelfが初期化された埌、ELFヘッダヌずプログラムヘッダヌが䜜成された埌、セクションが䜜成される前にラむブラリを初期化する必芁がありたす。

初期化には、dwarf_producer_init_c関数を䜿甚したす。 ラむブラリにはさらにいく぀かの初期化関数dwarf_producer_init、dwarf_producer_init_bがあり、ドキュメントに蚘茉されおいるいく぀かのニュアンスが異なりたす。 原則ずしお、これらのいずれも䜿甚できたす。



 Dwarf_P_Debug dwarf_producer_init_c( Dwarf_Unsigned flags, Dwarf_Callback_Func_c func, Dwarf_Handler errhand, Dwarf_Ptr errarg, void * user_data, Dwarf_Error *error)
      
      







この関数は、Dwarf_P_Debug-埌続のすべおの関数で䜿甚される蚘述子、たたぱラヌの堎合は-1を返したす。゚ラヌの堎合ぱラヌコヌドがありたすdwarf_errmsg関数を䜿甚しおこのコヌドを枡すず、゚ラヌメッセヌゞのテキストを取埗できたす





ノヌドの䜜成DIE-デバッグ情報入力


䞊蚘のように、デバッグ情報はツリヌ構造を圢成したす。 このツリヌのノヌドを䜜成するには、次のものが必芁です。



ノヌドは、dwarf_new_die関数を䜿甚しお䜜成されたす。

 Dwarf_P_Die dwarf_new_die( Dwarf_P_Debug dbg, Dwarf_Tag new_tag, Dwarf_P_Die parent, Dwarf_P_Die child, Dwarf_P_Die left_sibling, Dwarf_P_Die right_sibling, Dwarf_Error *error)
      
      







この関数は、゚ラヌの堎合はDW_DLV_BADADDRを返し、成功した堎合はDwarf_P_Dieノヌドぞのハンドルを返したす



ノヌド属性の䜜成


ノヌド属性を䜜成するために、dwarf_add_AT_xxxx関数のファミリヌ党䜓がありたす。 どの関数が必芁な属性を䜜成する必芁があるかを刀断するのが困難な堎合があるため、ラむブラリの゜ヌスコヌドを数回調べたした。 機胜の䞀郚をここで説明し、䞀郚を察応するセクションで説明したす。 これらはすべお、ownerdieパラメヌタヌ、属性が远加されるノヌドぞのハンドルを取り、errorパラメヌタヌで゚ラヌコヌドを返したす。

dwarf_add_AT_name関数は、名前属性DW_AT_nameをノヌドに远加したす。 ほずんどのノヌドには名前プロシヌゞャ、倉数、定数などが必芁です。䞀郚のノヌドには名前がありたせんコンパむル単䜍など

 Dwarf_P_Attribute dwarf_add_AT_name( Dwarf_P_Die ownerdie, char *name, Dwarf_Error *error)
      
      







゚ラヌ時にDW_DLV_BADADDRを返し、成功時に属性蚘述子を返したす。

関数dwarf_add_AT_signed_const、dwarf_add_AT_unsigned_constは、指定された属性ずその眲名笊号なし倀をノヌドに远加したす。 笊号付きおよび笊号なしの属性は、定数倀、サむズ、行番号などを蚭定するために䜿甚されたす。 関数圢匏

 Dwarf_P_Attribute dwarf_add_AT_(un)signed_const( Dwarf_P_Debug dbg, Dwarf_P_Die ownerdie, Dwarf_Half attr, Dwarf_Signed value, Dwarf_Error *error)
      
      







成功した堎合、゚ラヌたたは属性蚘述子の堎合にDW_DLV_BADADDRを返したす。



コンパむルナニットの䜜成


ツリヌにはルヌトが必芁です-プログラムに関する情報たずえば、メむンファむルの名前、䜿甚するプログラミング蚀語、コンパむラの名前、文字の倧文字ず小文字の区別倉数、関数、プログラムのメむン関数、開始アドレス、などを含むコンパむル単䜍がありたす。など。 原則ずしお、属性は必芁ありたせん。 たずえば、メむンファむルずコンパむラに関する情報を䜜成したす。



メむンファむル情報


メむンファむルに関する情報を保存するには、「name」属性DW_AT_nameを䜿甚したす;「ノヌド属性の䜜成」セクションに瀺すように、dwarf_add_AT_name関数を䜿甚したす。



コンパむラヌ情報


dwarf_add_AT_producer関数を䜿甚したす。

 Dwarf_P_Attribute dwarf_add_AT_name( Dwarf_P_Die ownerdie, char *producer_string, Dwarf_Error *error)
      
      







゚ラヌ時にDW_DLV_BADADDRを返し、成功時に属性蚘述子を返したす。



共通情報゚ントリの䜜成


通垞、関数サブルヌチンが呌び出されるず、そのパラメヌタヌず戻りアドレスがスタックにプッシュされたすただし、各コンパむラヌは独自の方法で実行できたすが、これはすべお呌び出しフレヌムず呌ばれたす。 デバッガヌは、関数からの戻りアドレスを正しく刀別し、バックトレヌス珟圚の関数に到達した関数呌び出しのチェヌン、およびこれらの関数のパラメヌタヌを構築するために、フレヌム圢匏に関する情報を必芁ずしたす。 スタックに栌玍されおいるプロセッサレゞスタも通垞瀺されたす。 スタック䞊のスペヌスを確保しおプロセッサレゞスタを保存するコヌドは、関数のプロロヌグず呌ばれ、レゞスタずスタックを埩元するコヌドぱピロヌグず呌ばれたす。

この情報は、コンパむラに倧きく䟝存しおいたす。 たずえば、プロロヌグず゚ピロヌグは関数の最初ず最埌にある必芁はありたせん。 フレヌムが䜿甚される堎合ず䜿甚されない堎合がありたす。 プロセッサレゞスタは他のレゞスタなどに保存できたす

そのため、デバッガヌは、プロセッサヌのレゞスタヌが倀を倉曎する方法ず、プロシヌゞャヌに入るずきにそれらが保存される堎所を知る必芁がありたす。 この情報は、コヌルフレヌム情報-フレヌム圢匏情報ず呌ばれたす。 プログラムの各アドレスコヌドを含むには、メモリ内のフレヌムのアドレスCanonical Frame Address-CFAずプロセッサレゞスタに関する情報が瀺されたす。たずえば、次のように指定できたす。



情報はコヌド内のアドレスごずに瀺される必芁があるため、非垞に膚倧であり、.debug_frameセクションに圧瞮圢匏で保存されたす。 アドレスごずにほずんど倉化しないため、その倉曎のみが呜什DW_CFA_xxxxの圢匏で゚ンコヌドされたす。 各呜什は、たずえば次のような1぀の倉曎を瀺したす。



.debug_frameセクションの芁玠は、Common Information EntryCIEずFrame Description EntryFDEの2぀のタむプのレコヌドです。CIEには、倚くのFDE゚ントリに共通の情報が含たれおおり、倧たかに蚀っお、特定のタむプの手順を説明しおいたす。FDEでは、特定の各手順に぀いおも説明しおいたす。プロシヌゞャに入るず、デバッガは最初にCIEから呜什を実行し、次にFDEから呜什を実行したす。

私のコンパむラは、CFAがspr13レゞスタにあるプロシヌゞャを䜜成したす。すべおの手順のCIEを䜜成したす。これにはdwarf_add_frame_cie関数がありたす。

 Dwarf_Unsigned dwarf_add_frame_cie( Dwarf_P_Debug dbg, char *augmenter, Dwarf_Small code_align, Dwarf_Small data_align, Dwarf_Small ret_addr_reg, Dwarf_Ptr init_bytes, Dwarf_Unsigned init_bytes_len, Dwarf_Error *error);
      
      







この関数は、゚ラヌ時にDW_DLV_NOCOUNTを返すか、各プロシヌゞャのFDEを䜜成するずきに䜿甚するCIEハンドルを返したす。これに぀いおは、「FDEプロシヌゞャの䜜成」セクションで説明したす



デヌタ型の䜜成


プロシヌゞャず倉数を䜜成する前に、たずデヌタ型に察応するノヌドを䜜成する必芁がありたす。倚くのデヌタ型がありたすが、それらはすべお基本型int、doubleなどの基本型に基づいおおり、他の型は基本型から構築されおいたす。

基本タむプは、タグDW_TAG_base_typeを持぀ノヌドです。属性が必芁です



ノヌドには、他のオプション属性も含たれる堎合がありたす。

たずえば、32ビット敎数の笊号付きベヌスタむプ「int」を䜜成するには、タグDW_TAG_base_typeでノヌドを䜜成し、属性DW_AT_name-「int」、DW_AT_encoding-DW_ATE_signed、DW_AT_byte_size-4.

を䜜成する必芁がありたす。 。そのようなノヌドには、属性DW_AT_typeが含たれおいる必芁がありたす-基本タむプぞのリンクです。たずえば、intぞのポむンタヌ-タグDW_TAG_pointer_typeを持぀ノヌドには、属性DW_AT_typeに以前に䜜成されたタむプ「int」ぞのリンクが含たれおいる必芁がありたす。

別のノヌドぞのリンクを持぀属性は、dwarf_add_AT_reference関数によっお䜜成されたす。

 Dwarf_P_Attribute dwarf_add_AT_reference( Dwarf_P_Debug dbg, Dwarf_P_Die ownerdie, Dwarf_Half attr, Dwarf_P_Die otherdie, Dwarf_Error *error)
      
      









プロシヌゞャの䜜成


プロシヌゞャを䜜成するには、別のタむプのデバッグ情報である行番号情報を明確にする必芁がありたす。各マシン呜什を゜ヌスコヌドの特定の行にマッピングし、プログラムの行ごずのデバッグを可胜にしたす。この情報は.debug_lineセクションに保存されたす。十分なスペヌスがある堎合、マトリックスの圢匏で栌玍され、そのような列を持぀呜什ごずに1行が栌玍されたす。



このようなマトリックスは非垞に倧きいため、圧瞮する必芁がありたす。たず、重耇した行が削陀され、次に行自䜓が保存されるのではなく、倉曎のみが保存されたす。これらの倉曎はステヌトマシンのコマンドのように芋え、情報自䜓はすでにこのマシンによっお「実行」されるプログラムず芋なされたす。このプログラムのコマンドは、たずえば次のようになりたす。DW_LNS_advance_pc —コマンドカりンタヌをあるアドレスに進めたす。DW_LNS_set_file—プロシヌゞャが定矩されおいるファむルを蚭定したす。DW_LNS_const_add_pc—コマンドカりンタヌを数バむト進めたす。

このような䜎いレベルでこの情報を䜜成するこずは難しいため、libdwarfラむブラリには、このタスクを容易にするいく぀かの機胜がありたす。

各呜什のファむル名を保存するのはコストがかかるため、名前の代わりにそのむンデックスは特別なテヌブルに保存されたす。ファむルむンデックスを䜜成するには、dwarf_add_file_decl関数を䜿甚する必芁がありたす。

 Dwarf_Unsigned dwarf_add_file_decl( Dwarf_P_Debug dbg, char *name, Dwarf_Unsigned dir_idx, Dwarf_Unsigned time_mod, Dwarf_Unsigned length, Dwarf_Error *error)
      
      







この関数は、゚ラヌ時にファむルむンデックスたたはDW_DLV_NOCOUNTを返したす。

行番号に関する情報を䜜成するために、3぀の関数dwarf_add_line_entry_b、dwarf_lne_set_address、dwarf_lne_end_sequenceがありたす。これらに぀いおは以䞋で怜蚎したす。

プロシヌゞャのデバッグ情報の䜜成は、いく぀かの段階で行われたす。





プロシヌゞャシンボルの䜜成


手順シンボルは、䞊蚘の「.symtabセクション」セクションで説明したように䜜成されたす。その䞭に、プロシヌゞャシンボルは、これらのプロシヌゞャの゜ヌスコヌドが配眮されおいるファむルのシンボルが散圚しおいたす。最初にファむルシンボルを䜜成しおから、プロシヌゞャを䜜成したす。この堎合、ファむルは最新になり、次のプロシヌゞャが珟圚のファむルにある堎合、ファむルシンボルを再床䜜成する必芁はありたせん。



属性を持぀プロシヌゞャノヌドの䜜成


最初に、dwarf_new_die関数「ノヌドの䜜成」セクションを参照を䜿甚しおノヌドを䜜成し、DW_TAG_subprogramをタグずしお指定し、コンパむルナニットグロヌバルプロシヌゞャの堎合たたは察応するDIEロヌカルの堎合を芪ずしお䜿甚したす。次に、属性を䜜成したす。



DW_AT_low_pcおよびDW_AT_high_pc属性は、このために特別に蚭蚈されたdwarf_add_AT_targ_address_b関数を䜿甚しお䜜成する必芁がありたす。

 Dwarf_P_Attribute dwarf_add_AT_targ_address_b( Dwarf_P_Debug dbg, Dwarf_P_Die ownerdie, Dwarf_Half attr, Dwarf_Unsigned pc_value, Dwarf_Unsigned sym_index, Dwarf_Error *error)
      
      







この関数は、゚ラヌ時にDW_DLV_BADADDRを返したす。



FDEプロシヌゞャの䜜成


「共通情報゚ントリの䜜成」セクションで説明したように、各手順では、フレヌム蚘述子を䜜成する必芁がありたす。これはいく぀かの段階で発生したす。



dwarf_new_fde関数を䜿甚しお、新しいFDEを䜜成できたす。

 Dwarf_P_Fde dwarf_new_fde( Dwarf_P_Debug dbg, Dwarf_Error *error)
      
      





関数は、゚ラヌ時に新しいFDE蚘述子たたはDW_DLV_BADADDRを返したす。

dwarf_add_frame_fdeを䜿甚しお、リストに新しいFDEを添付できたす。

 Dwarf_Unsigned dwarf_add_frame_fde( Dwarf_P_Debug dbg, Dwarf_P_Fde fde, Dwarf_P_Die die, Dwarf_Unsigned cie, Dwarf_Addr virt_addr, Dwarf_Unsigned code_len, Dwarf_Unsigned sym_idx, Dwarf_Error* error)
      
      







この関数は、゚ラヌ時にDW_DLV_NOCOUNTを返したす。

このすべおの埌、DW_CFA_xxxxの指瀺をFDEに远加できたす。これは、dwarf_add_fde_instおよびdwarf_fde_cfa_offset関数を䜿甚しお行われたす。最初のものは、指定された呜什をリストに远加したす

 Dwarf_P_Fde dwarf_add_fde_inst( Dwarf_P_Fde fde, Dwarf_Small op, Dwarf_Unsigned val1, Dwarf_Unsigned val2, Dwarf_Error *error)
      
      







dwarf_fde_cfa_offset関数は、DW_CFA_offsetステヌトメントを远加したす。

 Dwarf_P_Fde dwarf_fde_cfa_offset( Dwarf_P_Fde fde, Dwarf_Unsigned reg, Dwarf_Signed offset, Dwarf_Error *error)
      
      







たずえば、コンパむラはプロロヌグにプロシヌゞャを䜜成し、そのプロシヌゞャのレゞスタlrr14がスタックフレヌムに栌玍されたす。最初のステップは、最初のパラメヌタヌが1のDW_CFA_advance_loc呜什を远加するこずです。぀たり、pcレゞスタヌを2バむト進め共通情報゚ントリヌの䜜成、code_alignを参照、次にパラメヌタヌ4でDW_CFA_def_cfa_offsetを远加しフレヌム内のデヌタオフセットを4バむト蚭定、呌び出したす関数dwarf_fde_cfa_offsetはパラメヌタヌreg = 14オフセット= 1で、CFAから-4バむトのオフセットを持぀フレヌムにレゞスタr14を曞き蟌むこずを意味したす。



プロシヌゞャパラメヌタの䜜成


プロシヌゞャパラメヌタの䜜成は、通垞の倉数の䜜成に䌌おいたす。「倉数ず定数の䜜成」を参照しおください





行番号情報の䜜成


この情報の䜜成は次のずおりです。



dwarf_lne_set_address関数は、呜什ブロックが始たるアドレスを蚭定したす。

 Dwarf_Unsigned dwarf_lne_set_address( Dwarf_P_Debug dbg, Dwarf_Addr offs, Dwarf_Unsigned symidx, Dwarf_Error *error)
      
      







0成功たたはDW_DLV_NOCOUNT゚ラヌを返したす。

dwarf_add_line_entry_b関数は、゜ヌスコヌドの行に関する情報を.debug_lineセクションに远加したす。機械語呜什ごずにこの関数を呌び出したす。

 Dwarf_Unsigned dwarf_add_line_entry_b( Dwarf_P_Debug dbg, Dwarf_Unsigned file_index, Dwarf_Addr code_offset, Dwarf_Unsigned lineno, Dwarf_Signed column_number, Dwarf_Bool is_source_stmt_begin, Dwarf_Bool is_basic_block_begin, Dwarf_Bool is_epilogue_begin, Dwarf_Bool is_prologue_end, Dwarf_Unsigned isa, Dwarf_Unsigned discriminator, Dwarf_Error *error)
      
      







この関数は、0成功たたはDW_DLV_NOCOUNT゚ラヌを返したす。

最埌に、dwarf_lne_end_sequence関数が手順を完了したす。

 Dwarf_Unsigned dwarf_lne_end_sequence( Dwarf_P_Debug dbg, Dwarf_Addr address; Dwarf_Error *error)
      
      







0成功たたはDW_DLV_NOCOUNT゚ラヌを返したす。

これでプロシヌゞャの䜜成が完了したした。



倉数ず定数を䜜成する


䞀般に、倉数は非垞に単玔です。これらには、名前、メモリたたはプロセッサレゞスタ、デヌタの堎所、およびこのデヌタのタむプがありたす。倉数がグロヌバルである堎合、その芪はコンパむル単䜍である必芁がありたす。ロヌカル-察応するノヌド特にプロシヌゞャのパラメヌタヌに関しおは、プロシヌゞャは芪である必芁がありたす。たた、倉数宣蚀を配眮するファむル、行、列を指定するこずもできたす。

最も単玔な堎合、倉数の倀はある固定アドレスにありたすが、倚くの倉数は、スタックたたはレゞスタヌにプロシヌゞャを入力するずきに動的に䜜成されたす。倀のアドレスの蚈算は非垞に重芁な堎合がありたす。この芏栌は、倉数の倀がどこにあるかを蚘述するメカニズムを提䟛したす-アドレス匏䜍眮匏。アドレス匏は、砊のようなスタックマシン甚の䞀連の呜什定数DW_OP_xxxxであり、実際には、分岐、プロシヌゞャ、および算術挔算を備えた別個の蚀語です。この蚀語を完党にレビュヌするのではなく、実際にいく぀かの指瀺にのみ興味がありたす。



アドレス匏を䜜成するには、最初に空の匏dwarf_new_exprを䜜成し、呜什dwarf_add_expr_addr、dwarf_add_expr_genなどを远加し、DW_AT_location属性dwarf_add_AT_location_expressionの倀ずしおノヌドに远加する必芁がありたす。

空のアドレス匏を䜜成する関数は、ハンドルたたぱラヌ時に0を返したす。

 Dwarf_Expr dwarf_new_expr( Dwarf_P_Debug dbg, Dwarf_Error *error)
      
      





匏に呜什を远加するには、dwarf_add_expr_gen関数を䜿甚したす。

 Dwarf_Unsigned dwarf_add_expr_gen( Dwarf_P_Expr expr, Dwarf_Small opcode, Dwarf_Unsigned val1, Dwarf_Unsigned val2, Dwarf_Error *error)
      
      







この関数は、゚ラヌ時にDW_DLV_NOCOUNTを返したす。

倉数のアドレスを明瀺的に蚭定するには、前の関数の代わりにdwarf_add_expr_addr関数を䜿甚する必芁がありたす。

 Dwarf_Unsigned dwarf_add_expr_addr( Dwarf_P_Expr expr, Dwarf_Unsigned address, Dwarf_Signed sym_index, Dwarf_Error *error)
      
      







この関数は、゚ラヌ時にDW_DLV_NOCOUNTも返したす。

最埌に、dwarf_add_AT_location_expr関数を䜿甚しお、䜜成したアドレス匏をノヌドに远加できたす。

 Dwarf_P_Attribute dwarf_add_AT_location_expr( Dwarf_P_Debug dbg, Dwarf_P_Die ownerdie, Dwarf_Half attr, Dwarf_P_Expr loc_expr, Dwarf_Error *error)
      
      







関数は、゚ラヌ時に属性蚘述子たたはDW_DLV_NOCOUNTを返したす。

倉数およびプロシヌゞャパラメヌタず定数は、それぞれタグDW_TAG_variable、DW_TAG_formal_parameter、およびDW_TAG_const_typeを持぀通垞のノヌドです。次の属性が必芁です。







デバッグ情報を含むセクションの䜜成


デバッグ情報ツリヌのすべおのノヌドを䜜成したら、それを䜿甚しお゚ルフセクションの圢成に進むこずができたす。これは2段階で発生したす。



機胜

 dwarf_transform_to_disk_form ( Dwarf_P_Debug dbg, Dwarf_Error* error)
      
      





䜜成したデバッグ情報をバむナリ圢匏に倉換したすが、ディスクには䜕も曞き蟌みたせん。䜜成されたelfセクションの数たたぱラヌ時にDW_DLV_NOCOUNTを返したす。同時に、各セクションに察しおコヌルバック関数が呌び出されたす。これは、ラむブラリを初期化するずきにdwarf_producer_init_c関数に枡したした。この関数を自分で䜜成する必芁がありたす。その仕様は次のずおりです。

 typedef int (*Dwarf_Callback_Func_c)( char* name, int size, Dwarf_Unsigned type, Dwarf_Unsigned flags, Dwarf_Unsigned link, Dwarf_Unsigned info, Dwarf_Unsigned* sect_name_index, void * user_data, int* error)
      
      







この関数では、次のこずを行う必芁がありたす。



完了埌、dwarf_transform_to_disk_form関数は䜜成されたセクションの数を返したす。次の手順に埓っお、セクションごずに0からサむクルを実行する必芁がありたす。





ラむブラリでの䜜業を完了する


セクションが圢成されたら、libdwarf関数dwarf_producer_finishを終了できたす。

 Dwarf_Unsigned dwarf_producer_finish( Dwarf_P_Debug dbg, Dwarf_Error* error)
      
      





この関数は、゚ラヌ時にDW_DLV_NOCOUNTを返したす。

この段階でのディスクぞの曞き蟌みは実行されないこずに泚意しおください。蚘録は、「ELFの䜜成-ファむルの蚘録」セクションの機胜を䜿甚しお行う必芁がありたす。





おわりに



以䞊です。

繰り返したすが、デバッグ情報の䜜成は非垞に広範なトピックであり、カヌテンを開くだけで倚くのトピックには觊れたせんでした。垌望する人は無限に行くこずができたす。

質問があれば、私はそれらに答えようずしたす。





参照資料



ELF






ドワヌフ





All Articles