善用 strace、debugger 從執行期間找出問題根源

最近被迫在短時間內學會 strace、gdb 這些之前一直用不到的重兵器, 都還不熟練就是了。剛好使用 hgsubversion 時有些困擾, 雖說它和 svn 整合得很好, 無縫接好 pull / push, 但它不會顯示 mercurial 對應到的 svn 版本, 平時看其它和 svn 整合的工具 (如 issue tracking) 會很困擾, 用得都是 svn 版號。

剛剛想到可以學 Strace -- The Sysadmin's Microscope 的做法, 用 strace 找出關聯的程式, 再來看怎麼修正它。

我推測 hg 一定有記錄 svn 相關版本的方式, 不然無法和 svn server 同步資料。於是挑個會讀到 svn 資料的指令來試:

strace -o trace.log -s 512 -e read,open hg svn info

用顯示的 svn 版號 123 來翻 trace.log, 發現這兩行:

open("/path/to/project/.hg/svn/lastpulled", O_RDONLY) = 3
read(3, "123\n", 4096)                 = 5

於是找到 meta data 存在 .hg/svn/ 下。 到該目錄下找到 .hg/svn/rev_map 這個檔案, 裡面存 hg 和 svn 的版號對應表。至少這樣就有足夠的材料寫個 script 來轉換 hg、svn 的版號。

不過若能直接加到 hg 裡, 應該會更方便也較可攜。要做這點相對容易, 可以到 hgsubversion 原始碼目錄下用 ack 找相關程式。

先用 ack rev_map 找到存 meta data 的物件 revmap, 再用 ack revmap 找到 wrappers.py 是換掉 hg 指令的程式。

再來用 pdb 觀察 revmap 如何被使用。先在 wrappers.py 裡設中斷點, 然後執行 pdb /usr/local/bin/hg parents --svn 找出 meta data 如何被讀出來。於是明白可在函式 parents 的部份塞入幾行顯示 svn 版本:

--- a/hgsubversion/wrappers.py        2011-12-25 00:34:39.170606104 +0800
+++ b/hgsubversion/wrappers.py        2011-12-25 00:33:04.161800527 +0800
@@ -57,6 +57,9 @@
         raise hgutil.Abort('No parent svn revision!')
     displayer = cmdutil.show_changeset(ui, repo, opts, buffered=False)
     displayer.show(ha)
+    # patch svn revision
+    print '\033[1;32msvn revision: %d\033[0m' % hashes[ha.node()][0]
+    print
     return 0

這樣打 hg parents --svn 就會多輸出一行 svn 的版號。雖說顯示在 hg log 會更方便, 不過 wrappers.py 裡沒有 log, 之後有再找時間看看怎麼加。

附帶一提, 剛用 pdb 時還不太習慣, 忘了 python 是執行期載入程式, 不能像 gdb 那樣在執行前就指定檔名指定行數設中斷點。而是要在 script 裡直接塞

import pdb; pdb.set_trace()

2011-12-25 更新

如留言裡的討論, 上述的修正沒有實質幫助, 就當作練 debugger 吧。最後覺得另外寫個 shell script 最省事效果也最好, 寫好的東西放在這裡

留言

  1. Hey學長,我最近也打算架設一個紀錄學習心得的blog,能否請教你我該怎麼把code/command貼上來(syntax highlighter?)

    回覆刪除
  2. @Heron 你是打算用blogger, wordpress or 自己架設?
    不然google search code highlight or syntax highlight.
    ex:
    http://heisencoder.net/2009/01/adding-syntax-highlighting-to-blogger.html

    回覆刪除
  3. 工具用的好。strace 最好用的功能之一就是『程式到底在讀哪個檔案』,而只 trace syscall 剛好能看到此重點。你這樣短時間內改別人程式的能力應感覺到有提昇?

    你的 use case 我有點疑惑:
    打 "hg svn info" 看 SVN revision 跟打 "hg parents --svn" 不是差不多? 若是看 "hg log" 時需要 SVN rev 我還能理解.

    gdb 下也可像 "pdb.set_trace()" 一樣在 source 中插入中斷: https://github.com/scottt/debugbreak
    gdb 除錯的對象有用 shared library 時,往往也是『執行期載入程式』。pdb 不能用檔名、行數預設 breakpoint 可算是缺功能。我自己最常用的其實是將 ipython 類似 "pdb.set_trace()"來用:
    import IPython; IPython.embed()

    (ipython 0.10 後的 API)


    另外也鼓勵你對 hgsubversion 從 bitbucket.org 回報 bug 、 merge request。

    我有寫過一個小程式,像是一個特殊功能的 debugger 是當 debug 的 target 發出 syscall (用 PTRACE_SYSCALL) 時就印出 stack trace (用 libunwind)。我整理一下,下次見面時跟你分享。

    回覆刪除
  4. @Heron: 在這頁 view-source,然後找 Google Code Prettify.類似的程式不少

    回覆刪除
  5. 恩,我弄好了,本來想使用新版Blogger的動態檢視,卻發現他限制更改html。接下我也要來好好學習寫好的Blog了。
    http://heron-note.blogspot.com/

    回覆刪除
  6. @Heron 順便廣告一下不直接相關的事, 我都是用自己寫的工具發文 http://fcamel-fc.blogspot.com/2011/06/ego-post-wsyiwyg-wiki.html

    這東西可以直接改成 Chrome Web App, 這樣別人要用按個安裝就結束了。不過目前自己用得好好的, 暫時也沒時間移過去, 所以就一直拖著 ...

    回覆刪除
  7. @Scott 這個 use case 的確有問題, 應該要直接改 log 才對。我原本是看到 parents 有 --svn 的功能, 至少可克難的用 hg parents -r REV --svn 查對應, 不過目前的程式這部份並沒有用, 所以就是.....還沒達到目的, 接下來有空會再看怎麼改到 log 裡, 然後問看看該社群有沒有興趣接收。

    目前想到兩個用法:
    1. 加個新指令 hg svn lookup 查 svn -> hg 的對應, 改起來簡單, 用法也不會令人困惑

    2. 加上 hg log --svn, 首先得先定義這個 --svn 的行為為何, 還有顯示的方式。定規格部份就滿麻煩的, 也得另外定顯示方式

    所以應該會先試 1 吧

    回覆刪除
  8. 目前覺得進步滿多的, 不過離能應付實戰還有段距離。待能順手應付實戰後, 應該會成長不少吧 XD

    下個目標是加強使用 gdb 的能力, 再來則是補充 linux system programming 的常識

    回覆刪除
  9. svn2hg line 40 指定 hg_revision 中,grep 前面多了反斜線? 類似 svn2hg 這種 script,需要 option parsing 時我後來都用 Python 寫。

    回覆刪除
  10. 也是, 我想說只有一個參數就將就一下, 再多一點用 python 比較方便。

    那個反斜線表示不要用 alias 展開的結果, 就叫 shell 執行 "grep"。我平時有設 alias grep='grep --color=auto'

    回覆刪除
  11. @fcamel: Re: svn2hg alias
    I see. 但讓 grep alias 展開應該無妨?

    回覆刪除
  12. 以前踩過雷, 有時寫 shell script 就會順手加。經你這樣一提, 才想起來了, 是 ls 有影響, grep 到是沒差。

    我的 ls 是 alias ls='ls -F --color', 配合 for loop 取檔名時會變成拿到錯誤的檔名

    回覆刪除
  13. ls --color=auto 就會在只有 isatty(stdout) 時才輸出控制碼

    回覆刪除
  14. 但是 pipe 後也會消失, 有時會 ls | less, 希望保有顏色, 還有我習慣加 -F。所以就變成 alias ls 設成那樣, 寫 shell script 時記得寫 \ls 了

    回覆刪除
  15. Re: ls --color:
    這樣有一天別人的 shell script 只有在你的系統上有問題的時候你要記得檢查 ls 部份啊 ... ;)

    回覆刪除

張貼留言

這個網誌中的熱門文章

(C/C++ ) 如何在 Linux 上使用自行編譯的第三方函式庫

熟悉系統工具好處多多

virtualbox 使用 USB 裝置