gdbで絶対秒を日付で表示する
gdbでデバッグ時に、対象のプログラムが内部で持っている絶対秒(Unix時間)を
日付に変換して表示する方法。
バグ等でcoreファイルから原因を調査する際に欲しくなったので作ってみた。
具体的には~/.gdbinitにユーザ定義のコマンドを作って実現する。
#普通にgdbでプログラムを動かしている場合は、glibcの関数等を呼び出して変換できるはず。
目次
coreファイル出力用のソースコード
解析用のソースコードとcoreファイルが必要なので、
グローバル変数に時刻と項番を書き込んだらabort()で自爆する単純なプログラムを作る。
printime.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#define ENTRY_MAX 10
typedef struct {
struct timeval tv;
int entno;
} entry_t;
static entry_t ent[ENTRY_MAX];
int main(int argc, char* argv[])
{
int i = 0;
for(i = 0; i < ENTRY_MAX; i++) {
gettimeofday(&ent[i].tv, NULL);
ent[i].entno = i;
}
abort();
return 0;
}
~/.gdbinitの作成
gdbinitにユーザコマンドを定義する際のフォーマットは次の通り。
define <コマンド名>
#実行したい処理
<処理1>
<処理2>
...
end
↓みたいな秒とマイクロ秒の引数を渡すと日付で表示してくれるコマンドを作る。
(gdb) ShowClock <sec> <usec>
2017/04/14 00:45:12.246025(JST)
実際に作成したgdbinitは下記。
Unix時間から表示する各要素を求めるのがとっても面倒だった。
~/.gdbinit
#
# Convert Unix-Time (tv_sec, tv_usec) to date(yy/mm/dd hh:mm:ss)
#
define ConvertUnixTime2Date
set $__acdays1 = 31
set $__acdays2 = 59
set $__acdays3 = 90
set $__acdays4 = 120
set $__acdays5 = 151
set $__acdays6 = 181
set $__acdays7 = 212
set $__acdays8 = 243
set $__acdays9 = 273
set $__acdays10 = 304
set $__acdays11 = 334
set $__acdays12 = 365
set $__leapdays = ((($__year-1)/4) - (($__year-1)/100) + (($__year-1)/400)) - 477
set $__year = 1970 + (($__daycount - $__leapdays)/365)
set $__restdays = $__daycount - ((($__year - 1970) * 365) + $__leapdays)
if (($__year % 400 == 0) || (($__year % 4 == 0) && ($__year % 100 !=0 )))
set $__acdays2++
set $__acdays3++
set $__acdays4++
set $__acdays5++
set $__acdays6++
set $__acdays7++
set $__acdays8++
set $__acdays9++
set $__acdays10++
set $__acdays11++
set $__acdays12++
end
if ($__restdays <= $__acdays1)
set $__mon = 1
set $__day = $__restdays
end
if ($__acdays1 < $__restdays && $__restdays <= $__acdays2)
set $__mon = 2
set $__day = $__restdays - $__acdays1
end
if ($__acdays2 < $__restdays && $__restdays <= $__acdays3)
set $__mon = 3
set $__day = $__restdays - $__acdays2
end
if ($__acdays3 < $__restdays && $__restdays <= $__acdays4)
set $__mon = 4
set $__day = $__restdays - $__acdays3
end
if ($__acdays4 < $__restdays && $__restdays <= $__acdays5)
set $__mon = 5
set $__day = $__restdays - $__acdays4
end
if ($__acdays5 < $__restdays && $__restdays <= $__acdays6)
set $__mon = 6
set $__day = $__restdays - $__acdays5
end
if ($__acdays6 < $__restdays && $__restdays <= $__acdays7)
set $__mon = 7
set $__day = $__restdays - $__acdays6
end
if ($__acdays7 < $__restdays && $__restdays <= $__acdays8)
set $__mon = 8
set $__day = $__restdays - $__acdays7
end
if ($__acdays8 < $__restdays && $__restdays <= $__acdays9)
set $__mon = 9
set $__day = $__restdays - $__acdays8
end
if ($__acdays9 < $__restdays && $__restdays <= $__acdays10)
set $__mon = 10
set $__day = $__restdays - $__acdays9
end
if ($__acdays10 < $__restdays && $__restdays <= $__acdays11)
set $__mon = 11
set $__day = $__restdays - $__acdays10
end
if ($__acdays11 < $__restdays && $__restdays <= $__acdays12)
set $__mon = 12
set $__day = $__restdays - $__acdays11
end
end
#
# Show clock form Unix-Time
# This command requires 2 arguments (tv_sec, tv_usec)
#
define ShowClock
set $__tv_sec = $arg0
set $__tv_usec = $arg1
# Set Time-Zone(JST)
set $__timezone = 9
set $__tv_sec = $__tv_sec + ($__timezone * 60 * 60)
set $__mon = 0
set $__day = 0
set $__daycount = ($__tv_sec / 86400) + 1
set $__year = (1970 + ($__daycount / 365))
set $__hour = (($__tv_sec % 86400) / 3600)
set $__min = ((($__tv_sec % 86400) / 60) % 60)
set $__sec = (($__tv_sec % 86400) % 60)
ConvertUnixTime2Date
if ($__timezone == 0)
printf "%04d/%02d/%02d %02d:%02d:%02d.%06d(UTC) ", \
$__year, $__mon, $__day, $__hour, $__min, $__sec, $__tv_usec
end
if ($__timezone == 9)
printf "%04d/%02d/%02d %02d:%02d:%02d.%06d(JST) ", \
$__year, $__mon, $__day, $__hour, $__min, $__sec, $__tv_usec
end
end
define ShowEntryDump
set $__index = 0
while ($__index < 10)
set $__ent = &ent[$__index]
ShowClock $__ent->tv.tv_sec $__ent->tv.tv_usec
printf "entno=%d\n", $__ent->entno
set $__index++
end
end
実行結果
$ ulimit -c unlimited
$ ./printime
$ gdb printime corefile
$ (gdb) showentrydump

コメント