近況報告

1ヶ月ぶりの更新ですね。長い間放置してごめんなさい。

しばらく放置していたので、さぞかしページビューは落ちてるだろうと思っていたのですが、セッション数が 1〜2 割程度減ったくらいで、まだまだ結構な方々が見に来てくださっていることに驚きました。なにも変化が無くて申し訳ないです。また、せっかくいただいたコメントにも返事ができず、申し訳ありませんでした。

ここ1ヶ月はちょっと色々ありまして、仕事が忙しかったり、環境が変わったりと zaurus に触れられる時間があまりとれなかったのです。また、もうしばらく時間がとれない状態が続く可能性が高いです。

えー、ネタ的にこのブログに書く内容でもないんですが、ただいま転職活動まっ最中です。
不況の波がうちの会社にも襲ってきまして、首が回らなくなってしまったというか。

今の会社は、私の理想に近くとても気に入っていたので、苦しいながらも何とか最後まで頑張ってきたのですが、それも限界に達してしまい、転職を余儀なくされてしまいました。

私は仕事でも組み込みLinuxをやっていたのですが、やはり IT業界や組み込み業界の転職は厳しいですね。以前でも組み込みLinuxはそれほど多くなかったのでなおさらです。まだ退職していないので仕事しながら探すとなると更に大変で・・・。

と、まぁ、そんな感じでして、しばらく zaurus を触る余裕がなさそうですので、期待されている方々には申し訳ないですが、落ち着くまで zaurus 関係の更新はできないと思います。ごめんなさい。

qgmap 0.1.8 リリース

かなり間が空いてしまいましたが、qgmap の 0.1.8 をリリースします。→ダウンロードページ

今回は期間が空いているにも関わらず、バグフィックス+α 程度の更新しかありません・・・。ごめんなさい。

今回の修正は以下のとおりです。

  • GPS使用時にズーム操作をすると、中心地がおかしくなるバグを修正
  • rootユーザにパスワード設定をしている場合、自動マウントできない問題の対処
  • 2GBを超えた ISO イメージのマウント対応

1つめは、 bxk07344 さん、sugarware さんからご報告いただいたバグの修正です。
GPSを追従モードで使用中にズームを行うと GPS モードに入った位置に飛ばされてしまうというバグを修正しました。

2つめは、sugarware さんのご要望の機能で、root ユーザにパスワードを設定している場合の対策を行いました。

rootにパスワードを設定している方は、「root権限で実行する」にチェックを入れると自動マウントができるようになります。

ただし、qgmap の様な一般アプリは、本来は root 権限で動かすべきではありません。qgmap が root 権限で動作することになるので、バグなどでシステムファイルを壊したりしてしまう可能性も否定できません。自己責任でご指定ください

また、同様の理由で root にパスワードを設定していると PHS による位置取得もできなかったようで、これも直しました。sugarware さんがPHS位置取得ができないとコメントされていたのは、これが原因だったのかもしれません。

3つめは 「2GB を超えた ISO イメージのマウント対応」と、大げさに表現してますが、ただ単に 2GB超のファイルもファイルダイアログで表示できるようにしただけです ^^;
もともと 2GB 超のファイルもマウント可能だったようです。

いろいろ試してみたところ、Qtのライブラリを使ってファイル一覧を取得すると、なぜか 2GB 以上のファイルは一覧に含まれないようです。そのため、Zaurus純正の「ファイル」タブでも、別のアプリでもファイルの存在が見えません。

ですが、コマンドラインから mount してみると、問題なくマウントできてしまいました。

そこでファイル一覧の取得に Qt のライブラリではなく、一般的な glib の関数を使うことで2GB超のファイルも見えるようにしました。これで違和感なく 2GB 超のイメージを指定できるはずです。

また、ついでに .rom と .iso 以外は見えないようにしてあります。

軽くしか試してないので、2GB以上の地図ファイルをお持ちの方はぜひ試してみてください。

WPA Settings 新版リリース

WPA Settings の問題を修正した新版をリリースします。→ダウンロードページ

以下の修正を行っています。wpa_supplicant 本体や接続スクリプトには変更は入っていません。WPA Settings アプリのみです。

  • 「ネットワーク設定」で接続先を削除すると、WPAの設定と食い違いが発生する問題を修正。
  • SSIDを変更できるようにした。 (スペース入りSSIDを設定可)
  • ステルスSSIDの設定を追加

1つ目はらーまるさんから報告頂いた WPA Settings の問題の修正です。

WPAの設定を行った接続先を「ネットワーク設定」から削除すると、純正システムの接続先設定は消えるのに、WPA Settings で行った設定が残ってしまうという問題がありました。

そのため、次に新しい接続先を作成すると、残っていたWPAの設定が悪さをして接続できなかったり、設定できなかったりといった問題が発生していました。

ただ、「ネットワーク設定」での接続先の削除と連動してWPAの設定を削除するということは出来ない(トリガがない)ため、WPA Settings アプリ起動時に接続先の SSID と WPA設定のSSID が食い違っていたら、WPA設定を削除する処理を追加しました。

2つ目は、WPA Settings アプリから SSID を変更する機能です。「ネットワーク設定」からはスペース入りSSIDの設定ができないため、今までは設定ファイルを直接編集することで対応していました。この機能により、GUI でスペース入りSSID に変更が可能になります。

設定ダイアログ
設定画面

3つ目は、ステルス SSID の対応です。/etc/wpa_supplicant/*.conf を直接編集してステルス SSID の設定が可能でしたが、GUI から設定できるようになりました。

これで設定ファイルを編集すること無く、GUI から全て設定できる様になったと思います。

DebugHacks ネタ – メモリリーク退治

前回のエントリで Debug Hacks Conference 2009 の参加報告 (?) を書きましたが、会場で著者のよしおかさんが「参加した人はブログ等で自分のDebugネタを書いてみんなで共有しよう」とおっしゃっていたので、私のDebugネタをちょっと書いてみます。

以前、ダウンが許されないサーバプログラムで数日間稼働させていると、僅かずつながらもメモリがリークしていくという現象があり非常に困りました。その時のHackです。

Hackその1  mallocカウンタを用意

malloc, free をマクロ定義して独自のmalloc, free で置き換えます。その独自 malloc, free でカウンタの増減を行います。そのカウンタは共有メモリ上に置いておくことでプログラム外から参照できるようにしていました。(コードは雰囲気で、未検証です)

/* 全てのソースがincludeしているヘッダに以下を記述 */
#define malloc(size) __my_malloc(size)
#define free(ptr) __my_free(ptr)
/* 置き換えられるmalloc */
#undef malloc
#undef free
void *__my_malloc(size_t size)
{
void *ptr;
ptr = malloc(size);
if(ptr)
_malloc_count++;
return ptr;
}

void __my_free(void *ptr)
{
free(ptr);
_malloc_count--;
}

これで malloc カウンタを見るとリークが発生しているかどうかが分かります。

ただし、ソフトウェアに定常状態があって、定常状態は常に同じmalloc数の場合でしか使えません。状況に応じてメモリ確保の状況が変わるとダメですね。あと、ライブラリ内でmallocしているようなものはカウントできない欠点もあります。

この方法は、リークの事実は分かっても特定するだけの情報がないので、「リークがない」という事実を確認するには使えますが、リークを潰す目的には使えません。

Hackその2  malloc領域にデバッグ情報を埋め込む

これは比較的メモリに余裕があるときにしか使えないのですが、Hackその1に関連して、mallocをフックした時に実際に要求された領域より+α を余分にmallocしておき、余剰部分にメモリ確保時の状況を書き込んでおくことで、後でリークを検出した時にトレース出来るようにしました。(以下未検証コード)

/* 全てのソースがincludeしているヘッダに以下を記述 */
#define malloc(size) __my_malloc(size, __func__, __LINE__)
#define free(ptr) __my_free(ptr, __func__, __LINE__)
struct malloc_debug_header {
int magic;
const char *func;
int line;
int size;
void *caller;
};
/* 置き換えられるmalloc */
#undef malloc
#undef free
void *__my_malloc(size_t size, const char *func, int line)
{
void *ptr;
struct malloc_debug_header *hdr;
ptr = malloc(size + sizeof(struct malloc_debug_header)); /* 余分にmalloc */
if(!ptr)
return ptr;
_malloc_count++;

hdr = ptr;
hdr->magic = 0xbf8129de; /* magic バイナリに出てこなそうな数値を指定 */
hdr->func = func;
hdr->line = line;
hdr->size = size;
hdr->caller = __builtin_return_address(1);
return ptr + sizeof(struct malloc_debug_header); /* offset を足してreturn */
}

void __my_free(void *ptr)
{
free(ptr - sizeof(struct malloc_debug_header)); /* offset を引いて free */
_malloc_count--;
}

これで各malloc領域にデバッグ情報は埋め込めたけど、じゃぁどうやってそれを読み出すんだよ!と思われるかもしれませんが、それは力技で。

  1. coreダンプさせて、coreファイルからmagicを検索して特定する方法
  2. attatchして、/proc/<PID>/mem をmmapして、そこからmagicを検索する方法

1つ目は、リーク発生後、kill -ABRT <PID> でcoreダンプさせてしまい、coreファイルからmagicナンバーを検索する方法です。

coreファイルはメモリイメージをベタに書き出しているので、gdb で core を開かずとも、バイナリファイルとして magic ナンバーを検索してしまえば、malloc された領域を特定できます。そこからデバッグ情報が書かれているので、line番号やサイズを取得します。

関数名についてはポインタなので、ポインタ値をメモっておいて、gdb でターゲットプログラムを開いて、そのポインタを表示させれば取得できます。

2つ目は、別途プログラムを作る必要がありますが、gdbのようにプロセスにattachして、そのプロセスの /proc/<PID>/mem を mmap することで、ターゲットプログラムのメモリ空間から直接magicナンバーを検索して解析する方法です。この方法では、detach 後、SIGCONTを発行すれば再開するので、プロセスが死なずにすみます。

caller も保存してあるので、おおよそどのルートでmallocされたメモリなのかが分かり、リーク退治に非常に便利でした。

 

今までの私が行ったデバッグの中で一番派手なのが上記の例ですね。後は泥まみれのデバッグばかりです。

私のデバッグスタイルとしては、使えるものを探し(時には作り)、使えるものは全て使ってバグ退治をするという感じですかね。バグを退治するのが目的なので、手段は選びません。

最近は printf デバッグ=悪といった風潮もありますが、printf デバッグも有効な手段である場面も多いと私は思います。私自身結構使いますし、必ずしも悪とは思ってません。その時の状況に応じて使えるものは全て使います。バグ退治に有効ならば。

私の場合、組み込み系の仕事がメインなのですが、i386以外のアーキテクチャではgdbが当てにならない場合が結構あります。マルチスレッドプログラムがgdb上ではうまく動かなかったり、Linuxカーネル起動後はICEなしで開発になったりと、デバッガがまともに使えないケースも結構あるので、デバッガは使えればラッキーくらいな感覚ですね。

なので、あまり手段を選んでられないのです。組み込み系でもスタイリッシュにグラフィカルなデバッガでスイスイデバッグができると楽なんですけどねぇ。組み込み系のようなプアな環境でのデバッグは十数年前からあまり変わってないのかもしれません。

DEBUG HACKS Conference 2009 に参加しました

久しぶりのブログです。今回は zaurus とは関係ないですが。。。

昨日開催された Debug Hacks の発売記念イベント Debug Hacks Conference 2009 に参加してきました。

参加前は本を買うかどうかは立ち読みしてから決めようかと思っていたんですが(^^;)、会場の即売所で買ってしまいました。

オライリーの紙袋 Debug Hacks Tシャツ

会場で本を買ったら DEBUG HACKS Tシャツがもらえました。ネタ以外では着れないですが・・・。
本を入れてくれたオライリーの紙袋がCoolです。

Conference の内容は詳細に書かれている方々がいらっしゃると思うし、動画がいずれニコニコ動画等にアップされると思うので、個人的にためになった部分を。

GDBでリスト表示

まず、gdb のユーザ定義コマンドによるリストの表示。構造体内のnext を辿って最後まで表示してくれるというもの。ユーザ定義コマンド自体は知ってたけど、面倒そうで使ったことなかったんですが、 こういう使い方が出きるなら便利ですね。

コードはメモってないので書けませんが、ユーザ定義コマンド(仮に list_print とする)で1つの構造体を表示するようなコマンドを作っておき、別のユーザ定義コマンドで next を辿って list_print を呼び出すというもの。(説明が下手ですな)

たしかに、ユーザ定義コマンドを作るのに手間がかかりますが、何度も何度もリストを見なければいけない場合には使えそうです。

今までは、

(gdb) p *list_head->next->next->next->next->next->next->next

とか普通に打ってました (汗)

Yuguiさんの発表

私は Ruby は触ったことがないこともあり、失礼ながら Yugui さんを始めて知りました。

まず、プレゼンうまいなーと。スライドの作りも個性的で、話の流れもわかりやすく、ユーモアもあり、とても印象に残りました。

印象に残ったのは、Ruby や Rails ではデバッグであまり苦労していないということ。言語設計やソフト設計が厄介なバグを混入しにくくしているんだなと感心しました。

DbC (Design by Contruct) や BDD (Behavior Driven Development) といった、軽微なバグを初期段階で検出できて、バグを混入しにくい作り方が、地味そうに思えるも非常に有効だと分かりました。

体験談として、DbC を適用して assert 入れまくったらバグがボロボロ出てきて、全て退治したらバグが1つしか残らなかったとおっしゃってました。1つのスキームで数百、数千単位のバグを1つにまで減らせたというのは驚きです。

こういう理論って確かにそうだけど、実際開発には適用が難しくない?とか、本当に手間に対する効果があるの?みたいなことを考えてしまうのですが、バリバリ開発しているハッカーに言われると非常に説得力があります。

いま仕事で開発してるソフトに DbC に倣って assert 入れまくってみようかな。結果がちょっと怖いですが (^^;

サインもらいました

最後に著者の方々にサインをもらってきました。

まだ本は読んでないですが、なかなか勉強になる Conference でした。