By utahta, on 10月 27th, 2009%
core ファイルを解析するメモ。
下準備
まず意図的に SEGV させるコードを書く。
#include <stdio.h>
class CPrint
{
private:
int m_number;
char *m_str;
public:
CPrint() : m_number(10), m_str(NULL) {}
~CPrint() {}
void print(){
// ここで SEGV る予定
printf( "%d, %c\n", m_number, m_str[0] );
}
};
int main()
{
CPrint p;
p.print();
return 0;
}
続けて core を出力させる設定。環境は Linux CentOS 5。
core dumped
下準備で作成したソースコードをコンパイル。-g を忘れずに。
実行する。当然 SEGV る。
$ ./a.out
セグメンテーション違反です (core dumped)
core ファイルが吐かれていることを確認。
$ ls
a.cpp a.out core.1613
core 解析
gdb を立ち上げる。gdb 実行バイナリ coreファイル
$ gdb a.out core.1613
...
Program terminated with signal 11, Segmentation fault.
#0 0x08048568 in CPrint::print (this=0xbfe45794) at a.cpp:15
15 printf( "%d, %c\n", m_number, m_str[0] );
(gdb)
呼び出された順番で関数を表示する。
(gdb) where
#0 0x08048568 in CPrint::print (this=0xbfe45794) at a.cpp:15
#1 0x080484fd in main () at a.cpp:22
(gdb)
ソースコードを表示する。
(gdb) list
10 CPrint() : m_number(10), m_str(NULL) {}
11 ~CPrint() {}
12
13 void print(){
14 // ここで SEGV る予定
15 printf( "%d, %c\n", m_number, m_str[0] );
16 }
17 };
18
19 int main()
(gdb)
変数の値を確認する。
クラスのメンバ変数もアドレスさえ分かれば確認できる。
(gdb) p ((class CPrint *) 0xbfe45794)->m_number
$2 = 10
(gdb)
いちいち ((class CPrint *) 0xbfe45794) とうつのが面倒な場合は、変数に代入する。
(gdb) set $c = ((class CPrint *) 0xbfe45794)
(gdb) p $c->m_number
$3 = 10
(gdb) p $c->m_str
$4 = 0x0
By utahta, on 10月 27th, 2009%
自宅サーバのネットワークが突如不安定になる問題の解決メモ。
samba 経由で 10GB 程度のファイルをダウンロードしていると、サーバと通信が途切れてその後まともに通信出来なくなるという現象。
上記なことをしなければまったく問題なかったので、解決まで時間がかかったかかった。
いろいろ無駄な作業もしたけど、忘れがたい経験になったのでまとめメモ。
* 自宅サーバは CentOS 5.4 を使用しています。
* ディストリビューションによっては、そのまま従って解決というわけにいかないかもしれません。
原因追及
とりあえず情報収集。
手始めに /var/log/message を眺める。
いろいろあやしげな文字列がある中、ひときわ目立ってたのが次の1文。
$ vi /var/log/message
...
NETDEV WATCHDOG: eth0: transmit timed out
...
このメッセージが出た直後から、まともに ssh すらできない状態に陥るもよう。
最初はクライアント側の Mac のせいかと思って、Windows から同じことを試したりしたけど、状況は変わらず
いま思ってみれば、サーバにエラー的なメッセージが出ている時点でほぼ原因はサーバと断定して良かったかもしれない。
とにかく原因はサーバ側にあるらしいとこまで絞り込めた。
けど、具体的な症状はこの時点で当然ながらさっぱりだったので、引き続き情報収集。
# ifconfig
eth0 Link encap:Ethernet HWaddr 00:1C:C0:B4:F6:4A
inet addr:192.168.11.30 Bcast:192.168.11.255 Mask:255.255.255.0
...
# ethtool eth0
Settings for eth0:
...
Advertised auto-negotiation: Yes
Speed: 1000Mb/s
Duplex: Full
...
# lspci -v
...
01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B PCI Express Gigabit Ethernet controller (rev 02)
Subsystem: Intel Corporation Unknown device 0001
...
いろいろコマンドの使い方は分かったものの、原因はさっぱり。
調べた情報を元に google 先生と協力しながら、
ethtool で speed を 1000 から 100 にしてみたり。
# ethtool -s eth0 speed 100
TCP Segmentation Offload をオフにしてみたり。(後でもともとオフだったことに気づいたり)
# ethtool -K eth0 tso off
けれど、解決には至らず。
検索語を変えながらさらに調べていくと、
「NIC のドライバのバージョンが違うとネットワークが不安定になるよ」という情報を発見。
どうも NIC とドライバのバージョン関係に原因がありそうということが分かった。
解決編
先人の知恵をもとに NIC のバージョンとドライバを確認。
# lspci | grep Ether
01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B PCI Express Gigabit Ethernet controller (rev 02)
# lsmod | grep r81
... r8169 ですよ的な表示 ...
バージョンは、RTL8111/8168B。
インストールされているドライバは、r8169。
!!
RTL8111/8168B には、r8168 がインストールされていないとだめとのこと。
ここまで来れば解決したも同然!
さっそくドライバを再インストール。
ssh 経由 だとサーバから切断されて作業が中断されること請け合いなので、直接キーボードを繋いでの作業がオススメ。
事前に ドライバ をダウンロードしてサーバに置いておく。
作業時は r8168-8.014.00.tar.bz2 を /usr/local/src に置いた。
$ su -
# cd /usr/local/src
# rmmod r8169
# vi /etc/modprobe.conf
r8169 を r8168 に置換
...
# tar jxvf r8168-8.014.00.tar.bz2
# cd r8168-8.014.00
# vi readme
... すべき作業が書いてある...
# make clean modules
# make install
# man depmod
# depmod -a
# modprobe r8168
# lsmod | grep r8168
# reboot
以上のコマンドを叩いた結果、無事に samba 経由で 10GB 程度のファイルをダウンロードすることが出来るようになった。
まさかのドライバ違いに思わぬ時間を取られてしまったけど、いい経験になったかも。
参考
CentOSにNICを手動インストールした人は、正しいドライバが入っているかチェックしたほうがよさげ