__FUNCTION__と__LINE__の文字列化
Linux kernel用に自作の簡易トレーサを使っている。
1つのチェックポイントあたり、16バイトの情報を記録しておいて、あとでダンプするというもの。16バイトというのは、
u32 timestamp; // タイムスタンプ const char *message; // メッセージ u32 param[2]; // データA、データB
という内容で、「いつ」「どこで」「どんなデータを」処理したかを記録できる。
messageは、ここ(数値の文字列化)のように
msg " at " __FUNC__ ":" num_to_str(__LINE__)
連結して、静的に保持したもの。
__FUNC__
と__LINE__
それぞれを記録するより、文字列化しておいて一つのポインタにした方が、トレースデータが節約できる。
なのだが、kosaki氏のエントリのコメント欄で、GCC 3.4以降はこの技が使えないことを教えていただいた。
元々のマクロはこうなっていた。
void tkt_record(const char *message, unsigned int param1, unsigned int param2); #define TKT_RECORD(param1, param2) tkt_record(__FUNCTION__ ":" num_to_str(__LINE__), param1, param2)
どうしようかと思っていたが、その場で構造体を作って、そのポインタを記録するようにすれば同等になるのに気がついた。こんな感じ。
typedef struct { const char *message; const char *function; int line; } TKT_MFL; void tkt_record(const TKT_MFL *mfl, unsigned int param1, unsigned int param2); #define TKT_RECORD_MSG(msg, param1, param2) \ { \ static const TKT_MFL mfl = { msg, __FUNCTION__, __LINE__ }; \ tkt_record(&mfl, (uint32_t)(param1), (uint32_t)(param2)); \ }
記録できる情報が増えるけど、混迷が深まった感じ。
ちなみに静的データのポインタを記録しているので、モジュールがアンロードされてからダンプすると、文字列表示のところでお亡くなりになってしまう。
構造体の先頭にマジックナンバーを埋め込んでおいて、文字列表示の前に、その存在を確認するようにすれば死ななくなるかも、などと、より混迷が深まりそうな今日この頃。