__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)); \
  }

記録できる情報が増えるけど、混迷が深まった感じ。

ちなみに静的データのポインタを記録しているので、モジュールがアンロードされてからダンプすると、文字列表示のところでお亡くなりになってしまう。
構造体の先頭にマジックナンバーを埋め込んでおいて、文字列表示の前に、その存在を確認するようにすれば死ななくなるかも、などと、より混迷が深まりそうな今日この頃。