このセクションでは、/usr/lib/librtld_db.so.1 監査ライブラリによってエクスポートされるさまざまなインタフェースについて説明します。機能グループごとに分けて説明します。
この関数は、「rtld-デバッガ」バージョン要件を確立します。ベースとなるバージョンは、RD_VERSION1 として定義されています。現在の「バージョン」は常に RD_VERSION で定義されます。
rd_err_e rd_init(int version);
Solaris 8 10/00 リリースで追加されたバージョン RD_VERSION2 は、rd_loadobj_t 構造体を拡張するものです。詳細は、読み込み可能オブジェクトの走査の rl_flags、rl_bend、および rl_dynamic フィールドを参照してください。
Solaris 8 01/01 リリースで追加されたバージョン RD_VERSION3 は、rd_plt_info_t 構造体を拡張するものです。詳細は、プロシージャーのリンクテーブルのスキップの pi_baddr および pi_flags フィールドを参照してください。
制御プロセスのバージョン要件が使用可能な「rtld-デバッガ」インタフェースよりも大きい場合は、RD_NOCAPAB が返されます。
この関数は、新しいエクスポートのインタフェースエージェントを作成します。
rd_agent_t *rd_new(struct ps_prochandle *php);
php は、制御プロセスによってターゲットプロセスを特定するために作成された cookie です。この cookie は、制御プロセスによってコンテキストを維持するために提供されるインポートされたインタフェースで使用されるものであり、「rtld-デバッガ」インタフェースに対して不透明です。
この関数は、rd_new() に指定された同じ ps_prochandle 構造に基づくエージェント内の情報をリセットします。
rd_err_e rd_reset(struct rd_agent *rdap);
この関数は、エージェントを削除し、それに関連するすべての状態を解放します。
void rd_delete(struct rd_agent *rdap);
次のエラー状態は、「rtld-デバッガ」インタフェース (rtld_db.h に定義) によって返されます。
typedef enum { RD_ERR, RD_OK, RD_NOCAPAB, RD_DBERR, RD_NOBASE, RD_NODYNAM, RD_NOMAPS } rd_err_e;
次のインタフェースは、エラー情報を収集するために使用できます。
この関数は、エラーコード rderr を記述する記述エラー文字列を返します。
char *rd_errstr(rd_err_e rderr);
この関数は、ログ記録をオン (1) またはオフ (0) にします。
void rd_log(const int onoff);
ログ記録がオンの場合、制御プロセスによって提供されるインポートインタフェース関数 ps_plog() は、さらに詳しい診断情報によって呼び出されます。
実行時リンカーのリンクマップで維持される各オブジェクト情報の取得は、rtld_db.h に定義された次の構造を使用して実現されます。
typedef struct rd_loadobj { psaddr_t rl_nameaddr; unsigned rl_flags; psaddr_t rl_base; psaddr_t rl_data_base; unsigned rl_lmident; psaddr_t rl_refnameaddr; psaddr_t rl_plt_base; unsigned rl_plt_size; psaddr_t rl_bend; psaddr_t rl_padstart; psaddr_t rl_padend; psaddt_t rl_dynamic; unsigned long rl_tlsmodid; } rd_loadobj_t;
文字列ポインタを含めて、この構造で指定されるアドレスはすべてターゲットプロセス内のアドレスであり、制御プロセス自体のアドレス空間のアドレスでないことに注意してください。
動的オブジェクトの名前を含む文字列へのポインタ。
リビジョン RD_VERSION2 では、動的に読み込まれる再配置可能オブジェクトは RD_FLG_MEM_OBJECT で識別されます。
動的オブジェクトのベースアドレス。
動的オブジェクトのデータセグメントのベースアドレス。
リンクマップ識別子 (名前空間の確立を参照)。
動的オブジェクトが標準フィルタの場合は、「フィルティー」の名前を指定します。
これらの要素は、下方互換性のために存在するものであり、現在は使用されていません。
オブジェクトのエンドアドレス (text + data + bss)。リビジョン RD_VERSION2 では、動的に読み込まれる再配置可能オブジェクトの場合、この要素は作成されたオブジェクトの最後を指します。このオブジェクトには、自身のセクションヘッダーが含まれています。
動的オブジェクト前のパッドのベースアドレス (動的オブジェクトのパッドを参照)。
動的オブジェクト後のパッドのベースアドレス (動的オブジェクトのパッドを参照)。
このフィールドは RD_VERSION2 に追加されたもので、DT_CHECKSUM (Table 13–8 を参照) のエントリへの参照を可能にするオブジェクトの動的セクションのベースアドレスを提供します。
このフィールドは、RD_VERSION4 に追加されたもので、スレッド固有ストレージ (TLS) 参照のモジュール識別子を提供します。このモジュール識別子は、オブジェクトに固有の短い整数です。この識別子は、問題となるオブジェクトのスレッドの TLS ブロックの基底アドレスを取得するために、libc_db の関数 td_thr_tlsbase() に渡すことができます。td_thr_tlsbase(3C_DB) を参照してください。
rd_loadobj_iter() ルーチンは、このオブジェクトデータ構造を使用して実行時リンカーのリンクマップリストの情報にアクセスします。
この関数は、ターゲットプロセスに現在読み込まれている動的オブジェクトすべてを反復します。
typedef int rl_iter_f(const rd_loadobj_t *, void *); rd_err_e rd_loadobj_iter(rd_agent_t *rap, rl_iter_f *cb, void *clnt_data);
各反復時に、cb によって指定されたインポート関数が呼び出されます。clnt_data は、cb 呼び出しにデータを渡すために使用できます。各オブジェクトに関する情報は、スタックが割り当てられた volatile rd_loadobj_t 構造へのポインタによって返されます。
cb ルーチンからの戻りコードは、rd_loadobj_iter() によってテストされ、次の意味を持ちます。
1 – リンクマップの処理を継続する。
0 – リンクマップの処理を停止して、制御プロセスに制御を返す。
rd_loadobj_iter() は、正常だと RD_OK を返します。RD_NOMAPS が返される場合、実行時リンカーは、まだ初期リンクマップを読み込みません。
制御プロセスは、実行時リンカーの適用範囲内で発生する特定のイベントを追跡できます。これらのイベントは次のとおりです。
実行時リンカーは、すべての動的オブジェクトを読み込んで再配置し、読み込まれた各オブジェクトの .init セクションの呼び出しを開始します。
実行時リンカーは、すべての .init セクションの呼び出しを終了して、基本実行可能プログラムに制御を渡します。
実行時リンカーは、動的オブジェクトを読み込みまたは読み込み解除のために呼び出されます。
これらのイベントは、次のインタフェース (sys/link.h と rtld_db.h に定義) を使用してモニターできます。
typedef enum { RD_NONE = 0, RD_PREINIT, RD_POSTINIT, RD_DLACTIVITY } rd_event_e; /* * Ways that the event notification can take place: */ typedef enum { RD_NOTIFY_BPT, RD_NOTIFY_AUTOBPT, RD_NOTIFY_SYSCALL } rd_notify_e; /* * Information on ways that the event notification can take place: */ typedef struct rd_notify { rd_notify_e type; union { psaddr_t bptaddr; long syscallno; } u; } rd_notify_t;
イベントを追跡する関数を次に示します。
この関数は、イベントモニタリングを有効 (1) または無効 (0) にします。
rd_err_e rd_event_enable(struct rd_agent *rdap, int onoff);
この関数は、制御プログラムへの指定イベントの通知方法を指定します。
rd_err_e rd_event_addr(rd_agent_t *rdap, rd_event_e event, rd_notify_t *notify);
イベントの種類によっては、制御プロセスの通知は、notify->u.syscallno で特定される害のない簡単なシステム呼び出しの呼び出しや、notify->u.bptaddr で指定されるアドレスでのブレークポイントの実行で行われます。システム呼び出しの追跡または実際のブレークポイントの設定は、制御プロセスが行う必要があります。
イベントが発生した場合は、rtld_db.h に定義された次のインタフェースによって追加情報を取得できます。
typedef enum { RD_NOSTATE = 0, RD_CONSISTENT, RD_ADD, RD_DELETE } rd_state_e; typedef struct rd_event_msg { rd_event_e type; union { rd_state_e state; } u; } rd_event_msg_t;
rd_state_e の値を次に示します。
使用可能な追加状態情報はありません。
リンクマップは安定した状態にあってテスト可能です。
動的オブジェクトは削除処理中であり、リンクマップは安定した状態ではありません。リンクマップは、RD_CONSISTANT 状態に達するまでテストできません。
動的オブジェクトは削除処理中であり、リンクマップは安定した状態ではありません。リンクマップは、RD_CONSISTANT 状態に達するまでテストできません。
rd_event_getmsg() 関数を使用して、このイベント状態情報を取得します。
rd_err_e rd_event_getmsg(struct rd_agent *rdap, rd_event_msg_t *msg);
次の表は、異なる各イベントタイプで可能な状態を示しています。
|
「rtld-デバッガ」インタフェースは、制御プロセスが、プロシージャーのリンクのテーブルエントリをスキップオーバーする機能を提供します。デバッガなどの制御プロセスが、関数に介入するようにとの要求をはじめて受けると、プロシージャーのリンクテーブル処理は、制御を実行時リンカーに渡して関数定義を検索します。
次のインタフェースを使用すると、制御プロセスで実行時リンカーのプロシージャーのリンクテーブル処理にステップオーバーできます。制御プロセスは、ELF ファイルで提供される外部情報に基づいて、プロシージャーのリンクのテーブルエントリに遭遇する時期を判定できます。
ターゲットプロセスは、プロシージャーのリンクのテーブルエントリに介入すると、rd_plt_resolution() インタフェースを呼び出します。
この関数は、現在のプロシージャーのリンクテーブルエントリの解決状態と、それをスキップする方法に関する情報を返します。
rd_err_e rd_plt_resolution(rd_agent_t *rdap, paddr_t pc, lwpid_t lwpid, paddr_t plt_base, rd_plt_info_t *rpi);
pc は、プロシージャーのリンクテーブルエントリの最初の命令を表します。lwpid は lwp 識別子を提供し、plt_base はプロシージャーのリンクテーブルのベースアドレスを提供します。これらの 3 つの変数は、各種のアーキテクチャーがプロシージャーのリンクテーブルを処理するため十分な情報を提供します。
rpi は、rtld_db.h 内の次のデータ構造に定義された、プロシージャーのリンクのテーブルエントリに関する詳しい情報を提供します。
typedef enum { RD_RESOLVE_NONE, RD_RESOLVE_STEP, RD_RESOLVE_TARGET, RD_RESOLVE_TARGET_STEP } rd_skip_e; typedef struct rd_plt_info { rd_skip_e pi_skip_method; long pi_nstep; psaddr_t pi_target; psaddr_t pi_baddr; unsigned int pi_flags; } rd_plt_info_t; #define RD_FLG_PI_PLTBOUND 0x0001
rd_plt_info_t 構造体の要素を次に示します。
プロシージャーのリンクテーブルエントリがどのように扱われるかを示します。rd_skip_e 値内の 1 つに設定されます。
RD_RESOLVE_STEP または RD_RESOLVE_TARGET_STEP が返された時にステップオーバーする命令がいくつあるかを示します。
RD_RESOLVE_TARGET_STEP または RD_RESOLVE_TARGET が返された時にブレークポイントを設定するアドレス指定します。
RD_VERSION3 で追加された、プロシージャーのリンクテーブルの宛先アドレス。pi_flags フィールドの RD_FLG_PI_PLTBOUND フラグが設定されると、この要素は解決された (結合された) 宛先アドレスを示します。
RD_VERSION3 で追加されたフラグフィールド。フラグ RD_FLG_PI_PLTBOUND は、pi_baddr フィールドで取得できる宛先アドレスへ解決された (結合された) プロシージャーのリンクエントリを示します。
次のシナリオは rd_plt_info_t 戻り値から考えられます。
このプロシージャーのリンクテーブルによる最初の呼び出しは、実行時リンカーによって解決する必要があります。この場合、rd_plt_info_t には次のものが含まれます。
{RD_RESOLVE_TARGET_STEP, M, <BREAK>, 0, 0}
制御プロセスは、BREAK にブレークポイントを設定し、ターゲットプロセスを続けます。ブレークポイントに達すると、プロシージャーのリンクのテーブルエントリ処理は終了します。制御プロセスは M 命令を宛先関数にステップできます。これはプロシージャーのリンクテーブルエントリで最初の呼び出しであるため、結合アドレス (pi_baddr) が設定されていないことに注意してください。
このプロシージャーのリンクテーブル全体で Nth 番目。rd_plt_info_t には、次のものが含まれます。
{RD_RESOLVE_STEP, M, 0, <BoundAddr>, RD_FLG_PI_PLTBOUND}
プロシージャーのリンクのテーブルエントリはすでに解決されていて、制御プロセスは M 命令を宛先関数にステップできます。プロシージャーのリンクのテーブルエントリと結合しているアドレスは、<BoundAddr> で、RD_FLG_PI_PLTBOUND ビットはフラグフィールドに設定されています。
実行時リンカーのデフォルト動作は、オペレーティングシステムに依存して、もっとも効率的に参照できる場所に動的オブジェクトを読み込みます。制御プロセスの中には、ターゲットプロセスのメモリーに読み込まれたオブジェクトの周りにパッドがあることによって、利益を受けるものがあります。このインタフェースを使用すると、制御プロセスは、このパッドを要求できます。
この関数は、ターゲットプロセスによって続けて読み込まれたオブジェクトのパッドを有効または無効にします。パッドは読み込まれたオブジェクトの両側で行われます。
rd_err_e rd_objpad_enable(struct rd_agent *rdap, size_t padsize);
padsize メモリーにロードされたオブジェクトの前後両方で維持されるパッドのサイズをバイト数で指定します。このパッドは、mmapobj(2) 要求からのメモリー割り当てとして予約されています。実際には、ターゲットプロセスの仮想アドレス空間の、読み込み済みオブジェクトに隣接する領域が予約されます。これらの領域は、制御プロセスによってあとで使用できます。
padsize を 0 にすると、後のオブジェクトに対するオブジェクトパッドは無効になります。