<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CUAER348eSp7ImA9WhRbGEQ.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977</id><updated>2012-02-11T01:08:26.071+08:00</updated><category term="arm" /><category term="flash" /><category term="solr" /><category term="south" /><category term="micro blog" /><category term="web" /><category term="C" /><category term="open source" /><category term="chrome" /><category term="dirty work" /><category term="software development" /><category term="firefox" /><category term="css" /><category term="git" /><category term="rails" /><category term="strace" /><category term="natural language processing" /><category term="ltrace" /><category term="unicode" /><category term="eclipse" /><category term="vim" /><category term="hg" /><category term="raid" /><category term="system management" /><category term="virtualbox" /><category term="java" /><category term="mysql" /><category term="os" /><category term="security" /><category term="memory" /><category term="bit operation" /><category term="algorithm" /><category term="django" /><category term="bash" /><category term="networking" /><category term="gui" /><category term="build" /><category term="review board" /><category term="redmine" /><category term="testing" /><category term="automation" /><category term="C99" /><category term="cpython" /><category term="vcs" /><category term="json" /><category term="compiler" /><category term="google" /><category term="svn" /><category term="ruby" /><category term="mail" /><category term="linker" /><category term="wiki" /><category term="javascript" /><category term="perl" /><category term="gc" /><category term="ipad" /><category term="x86" /><category term="benchmark" /><category term="signal" /><category term="http" /><category term="common lisp" /><category term="C++" /><category term="webkit" /><category term="python" /><category term="browser" /><category term="wsgi" /><category term="llvm" /><category term="windows" /><category term="virtual machine" /><category term="programming language" /><category term="code" /><category term="virtualenv" /><category term="usability" /><category term="thinking" /><category term="apache" /><category term="linux" /><category term="screen" /><category term="gdb" /><category term="english" /><category term="linux programming" /><category term="tool" /><category term="php" /><category term="python3" /><category term="document" /><category term="sqlite" /><category term="tracing code" /><category term="ssh" /><category term="oop" /><category term="blog" /><category term="tip" /><category term="pdb" /><category term="functional programming" /><category term="vpn" /><category term="machine learning" /><category term="cpp" /><category term="mercurial" /><category term="profiling" /><category term="Google Apps" /><title>fcamel 技術隨手記</title><subtitle type="html">Work is not my life, but coding is!</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://fcamel-life.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>306</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/blogspot/fcamel" /><feedburner:info uri="blogspot/fcamel" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CUAER3k_eCp7ImA9WhRbGEQ.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-5787853904195437750</id><published>2012-02-11T01:08:00.001+08:00</published><updated>2012-02-11T01:08:26.740+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-11T01:08:26.740+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="hg" /><title>使用 hg-svn</title><content type="html">&lt;p&gt;參照&lt;a href="http://mercurial.selenic.com/wiki/WorkingWithSubversion"&gt;《WorkingWithSubversion - Mercurial》&lt;/a&gt;, 前置動作是要裝 python-subversion。用了一陣子覺得滿順的。不過得等 hg rebase &lt;span class="escaped"&gt;-&lt;/span&gt;-svn 出現 conflict, 看看有沒有無縫銜接 kdiff3 + resolve conflict, 才可以更放心使用。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-5787853904195437750?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/Y3l5O3YPTrE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/5787853904195437750/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/hg-svn.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/5787853904195437750?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/5787853904195437750?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/Y3l5O3YPTrE/hg-svn.html" title="使用 hg-svn" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/02/hg-svn.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8DSXwzeSp7ImA9WhRbFk8.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-3738557579285501263</id><published>2012-02-07T23:34:00.001+08:00</published><updated>2012-02-07T23:34:38.281+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-07T23:34:38.281+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mysql" /><title>盡量避免使用 BLOB 和 TEXT</title><content type="html">&lt;p&gt;剛好看到朋友在討論, 順便記一下舊心得。
&lt;/p&gt;&lt;p&gt;
初學 mysql 時容易犯的一個錯誤就是亂用 data type, 明明沒有需要很大的空間, 只是方便就選最大的那個。一但選用 BLOB 或 TEXT 後, mysql 許多執行 SQL 的策略會不同:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; &lt;a href="http://fcamel-life.blogspot.com/2010/12/varchar-text-order-by.html"&gt;mysql 不會選用 modified filesort&lt;/a&gt;, 速度有可能會慢很多。注意: group by 也會用到 sort。&lt;/li&gt;
&lt;li&gt; mysql 不會做 query cache。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
別小看 query cache, 它是 mysql 有高效能表現的原因之一。想像完全不懂 database 也沒建 index 的開發者, 若網站大部份需求是讀資料, 只要開夠大的 query cache, 事先用程式掃一掃網站 warm up 一下, 之後 99% 使用者連到網站時, 網頁所用的 SQL 都會從 query cache 裡拿, 連 SQL parsing 都不用, 等同於將 mysql 當作 in-memory key/value store (key = sql), 亂用都還有不錯的效能。
&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-3738557579285501263?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/voT4ExLVtfs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/3738557579285501263/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/blob-text.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/3738557579285501263?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/3738557579285501263?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/voT4ExLVtfs/blob-text.html" title="盡量避免使用 BLOB 和 TEXT" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/02/blob-text.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQCSH8_eyp7ImA9WhRbFk8.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-6210749835505765976</id><published>2012-02-07T21:46:00.001+08:00</published><updated>2012-02-07T21:46:09.143+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-07T21:46:09.143+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vim" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><title>在 gvim 內顯示中文</title><content type="html">&lt;p&gt;若你像我一樣習慣看英文名稱的選單, 想說也可以順便練英文, 因此裝了 win7 64bit 英文版, 才會有這需求。
&lt;/p&gt;&lt;p&gt;
除了本來就該做的:&lt;/p&gt;&lt;pre class="prettyprint"&gt;set encoding=utf-8
set fileencoding=utf-8
&lt;/pre&gt;&lt;p&gt;
之外, 還要設 guifont:&lt;/p&gt;&lt;pre class="prettyprint"&gt;if has("gui_running")
    set guifont=MingLiU:h14
endif
&lt;/pre&gt;&lt;p&gt;
要怎麼知道 guifont 的值呢? 只要按 Edit -&amp;gt; Select Font ..., 選好字型後再打 :set guifont, 就會看到設好的字型, 將它寫入 $HOME/_vimrc 下即可。
&lt;/p&gt;&lt;p&gt;
特別的是, 在 win32 下和 win64 的設法有點不同, 不能直接照著選完字型的值打, 得去掉最後的 :cCHINESEBIG5。在 vim 內輸入 help guifont 會看到完整說明, 不過好像沒看到 win64 的說明。
&lt;/p&gt;

&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-6210749835505765976?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/8P8PopT0Djg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/6210749835505765976/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/gvim.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/6210749835505765976?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/6210749835505765976?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/8P8PopT0Djg/gvim.html" title="在 gvim 內顯示中文" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/02/gvim.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak4DR304eip7ImA9WhRbEkU.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-1938601999356261461</id><published>2012-02-04T00:53:00.001+08:00</published><updated>2012-02-04T01:09:36.332+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-04T01:09:36.332+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Google Apps" /><title>善用 Google Form 和 Google Apps Script 製作問卷</title><content type="html">&lt;p&gt;之前收過幾個朋友用 Google Form 寫的「婚禮報名表」, 知道可以用 Google Docs 做問卷收集資訊, 到是沒有自己實際操作一次。
&lt;/p&gt;&lt;p&gt;
查了一下才知道, 以前這功能寫在 Google Spreadsheet 裡, 有個 Form 的功能, 但現在已獨立成新的檔案類型 &lt;a href="http://support.google.com/docs/bin/answer.py?hl=en&amp;amp;answer=87809&amp;amp;topic=1360904&amp;amp;ctx=topic"&gt;Google Form&lt;/a&gt;。
&lt;/p&gt;&lt;p&gt;
試用後覺得功能相當陽春, 而且最後沒有個「確認頁」讓使用者觀看之前回答的答案。又再研究了一下, 發現原來可以&lt;a href="http://alamoxie.com/blog/tech-tips/sending-confirmation-emails-google-docs-form/"&gt;寫程式產生確認信&lt;/a&gt;, 真是太 geek 了 (這是稱讚), 不給你陽春的基本功能, 只給你全套工具箱, 就自己想辦法吧。
&lt;/p&gt;&lt;p&gt;
摘要作法如下:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; 在 Google Form 的原始檔 (spreadsheet 檔) 點「Tools」-&amp;gt;「Script Editor」開啟編輯器&lt;/li&gt;
&lt;li&gt; 寫個 javascript 函式作些事&lt;/li&gt;
&lt;li&gt; 在編輯頁點「Triggers」-&amp;gt;「Current script's triggers ...」, 然後新增 trigger, 選剛寫的函式並在第三個下拉式選單選「On form submit」。按「Save」後會跳出確認視窗, 點「Authorize」&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
至於 javascript 函式裡能做什麼事呢, 得翻翻 &lt;a href="http://code.google.com/googleapps/appsscript/guide.html"&gt;Google Apps Script&lt;/a&gt; 才知道。一直覺得 Google 提供了一堆 API 可以做很多事, 不過沒什麼動力仔細研究, 希望之後有多些需求, 再來投入時間研究。&lt;a href="http://code.google.com/googleapps/appsscript/guide_events.html"&gt;在官方 events 的文件裡&lt;/a&gt;, 搜 "on form submit" 會看到簡單的範例。&lt;a href="http://alamoxie.com/blog/tech-tips/sending-confirmation-emails-google-docs-form/"&gt;這篇&lt;/a&gt;有提供完整的範例寄出使用者填的內容到使用者信箱, 兩者講得是同件事, 挑自己順眼的讀。
&lt;/p&gt;&lt;p&gt;
不過世界也不是如此美好, 目前 &lt;a href="http://support.google.com/docs/bin/answer.py?hl=en&amp;amp;answer=87809&amp;amp;topic=1360904&amp;amp;ctx=topic"&gt;Google Form&lt;/a&gt; 有幾個很明顯的問題, 搜一下會在 Google 討論區看到許多抱怨, 結論是目前無解:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; 除了 Form 的開頭和最後的訊息, 中間的問題欄都不能用 html 語法, 我想要 link 啊。&lt;/li&gt;
&lt;li&gt; Form 的開頭會自動將 URL 轉成網址, 但不能用 html 語法, 只能貼很醜的長網址。&lt;/li&gt;
&lt;li&gt; Form 的欄位順序很死, 在程式讀取的順序和 spreadsheet 裡填的順序一樣, 都是照「問題產生的順序」定的, 不是它在 Form 裡的順序, 也就是說, 最後產生出來的問題, 即使移到第一題, 在 spreadsheet 裡仍放在最後一欄。&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-1938601999356261461?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/8aHRW2fKF-c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/1938601999356261461/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/google-form-google-apps-script.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/1938601999356261461?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/1938601999356261461?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/8aHRW2fKF-c/google-form-google-apps-script.html" title="善用 Google Form 和 Google Apps Script 製作問卷" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/02/google-form-google-apps-script.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C04ASHY9eCp7ImA9WhRbFk8.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-3081267499558022905</id><published>2012-02-01T21:53:00.001+08:00</published><updated>2012-02-07T21:39:09.860+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-07T21:39:09.860+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="gdb" /><title>產生 core dump 的方法</title><content type="html">&lt;p&gt;這篇是 "Learning core dump from the hard way", 寫下幾個注意事項, 後來才發現 man core 就可以看到全部東西:&lt;/p&gt;&lt;h4&gt;測試&lt;/h4&gt;&lt;p&gt;若執行的程式有讀 terminal input, 可直接輸入 ctrl + \ 送出 SIGQUIT。或用指令 kill -QUIT PID 或 kill -ABRT PID, 要求程式產生 core dump, 藉此測試目前的設定是否 ok。
&lt;/p&gt;&lt;p&gt;
參考&lt;a href="http://fcamel-life.blogspot.com/2012/02/procpidstatus-signal.html"&gt;《從 /proc/PID/status 了解執行中程式處理 signal 的方式》&lt;/a&gt;, 先確認 signal handler 沒有被覆蓋掉, 才可放心測試。
&lt;/p&gt;&lt;h4&gt;ulimit / setrlimit(RLIMIT_CORE, ...)&lt;/h4&gt;&lt;p&gt;Ubuntu 預設為 ulimit -c 0, 表示不產生 core dump, 所以要先執行 ulimit -c unlimited 允許產生 core dump。可以將這行寫到 &lt;span class="escaped"&gt;~&lt;/span&gt;/.bashrc 裡, 以後就預設會產生 core dump。或在程式裡呼叫 setrlimit(RLIMIT_CORE, &amp;amp;limit) 也可以。
&lt;/p&gt;&lt;h4&gt;/proc/sys/kernel/core_pattern&lt;/h4&gt;&lt;p&gt;預設 core dump 的檔名可能不合使用, 參考&lt;a href="http://www.linuxhowtos.org/Tips%20and%20Tricks/coredump.htm"&gt;《setting the core dump name schema》&lt;/a&gt;, 可用&lt;/p&gt;&lt;pre class="prettyprint"&gt;$ echo "core.%e.%p.%t" | sudo tee /proc/sys/kernel/core_pattern
&lt;/pre&gt;&lt;p&gt;改變 core dump 的檔名, 這樣檔名會記錄是程式名稱、PID、發生的時間。在 multi-process 或 multi-thread 時特別有用。若希望每次開機都會生效, 則要在 /etc/sysctl.conf 加入 kernel.core_pattern = core.%e.%p.%t。
&lt;/p&gt;&lt;p&gt;
core pattern 可以是 "|PROGRAM", 這樣會將 core dump 導到 PROGRAM 的標準輸入, 可以自己寫 PROGRAM 做控制。像是 core dump 太頻繁時, 取樣留下幾個就好, 以免一下就塞爆硬碟。同樣的, %e 那些參數也可以接在 PROGRAM 後當參數用, 像是 "|PROGRAM core.%e.%p.%t", 自己的 PROGRAM 就能從 argv[1] 裡取得適合的檔名。需要特別注意的是, | 和 PROGRAM 之間不可以有空白。
&lt;/p&gt;&lt;h4&gt;setuid / setgid&lt;/h4&gt;&lt;p&gt;若確認 ulimit -c 有設好, core_pattern 沒寫到奇怪的地方 (像是 /dev/null),  硬碟也仍有空間, 卻仍無法產生 core dump, 可能是用到 setuid。用 ls -l 檢查一下, 或用 strace -esetuid 檢查。&lt;a href="http://stackoverflow.com/questions/2827520/i-dont-get-coredump-with-all-process"&gt;Linux 為了安全考量, 在使用 setuid/setgid 後, 會自動禁用 core dump。&lt;/a&gt;
&lt;/p&gt;&lt;p&gt;
若確實有觸發 setuid 的話, 在 setuid 後執行:&lt;/p&gt;&lt;pre class="prettyprint"&gt;prctl(PR_SET_DUMPABLE, 1);
&lt;/pre&gt;&lt;p&gt;
重新允許產生 core dump, 應該就 ok 了。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-3081267499558022905?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/Z7bABbgl49U" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/3081267499558022905/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/core-dump.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/3081267499558022905?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/3081267499558022905?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/Z7bABbgl49U/core-dump.html" title="產生 core dump 的方法" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/02/core-dump.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkQAQXkyeyp7ImA9WhRbEUw.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-2073715499464074039</id><published>2012-02-01T21:33:00.001+08:00</published><updated>2012-02-02T01:45:40.793+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-02T01:45:40.793+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="signal" /><title>從 /proc/PID/status 了解執行中程式處理 signal 的方式</title><content type="html">&lt;p&gt;man proc 可得知在 /proc/PID/status 裡有給人讀的 process 資訊, 其中 SigXXX 是關於 signal 的處理方式, 比方 SigIgn 表示忽略該 signal; SigCgt 表示有註冊自己的 signal handler。
&lt;/p&gt;&lt;p&gt;
比較需要花點心思的地方, 在於怎麼讀 signal mask。&lt;a href="http://forum.soft32.com/linux2/Signal-information-proc-status-ftopict13924.html"&gt;這裡&lt;/a&gt;有提到解碼方式, 每個數字用四個 bit 表示四個號碼, 從最右側開始遞增。
&lt;/p&gt;&lt;p&gt;
以這個程式為例:&lt;/p&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;signal.h&amp;gt;

void handler(int signum) {
}

int main(void) {
    signal(SIGQUIT, SIG_IGN);
    signal(SIGHUP, handler);
    signal(SIGPIPE, handler);
    while (1) ;
    return 0;
}
&lt;/pre&gt;&lt;p&gt;
它的 /proc/PID/status 如下:&lt;/p&gt;&lt;pre class="prettyprint"&gt;SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000004
SigCgt: 0000000000001001
&lt;/pre&gt;&lt;p&gt;
表示 3 號 signal (SIGQUIT) 設為 ignore (1, 2, 4 -&amp;gt; 4 表示第三個號碼), 1 號和 13 號 (SIGHUP 和 SIGPIPE) 有註冊 handler。signal 的號碼可從 man 7 signal 得知, 或在 include signal.h 後, 用 &lt;tt&gt;gcc -E -dD&lt;/tt&gt; 展開看也可以。
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;2012-02-02 更新&lt;/b&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://scottt.tw"&gt;Scott&lt;/a&gt; 在留言提供正式的解釋, 附註在此:
&lt;blockquote&gt;這是用 16 進位顯示一個 64 bit 的 bitmask，每個 bit 對應到一個 signal。 bits 從 0 開始編號而 Linux signals 從 1 開始編號，故 bit 0 代表 1 號 signal (SIGHUP)， bit 1 代表 2 號 signal (SIGINT)。
&lt;/blockquote&gt;&lt;/p&gt;
&lt;p&gt;
原本寫的時候想不起來正式的說法, 想說就隨手寫個「白話版」吧。原本的「白話版」也留著, 有不同描述方式, 應該多少會有幫助吧。
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-2073715499464074039?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/7DTshlSgkuY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/2073715499464074039/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/procpidstatus-signal.html#comment-form" title="4 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/2073715499464074039?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/2073715499464074039?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/7DTshlSgkuY/procpidstatus-signal.html" title="從 /proc/PID/status 了解執行中程式處理 signal 的方式" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>4</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/02/procpidstatus-signal.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQFR3w-eCp7ImA9WhRbEE8.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-5492177002672805163</id><published>2012-02-01T00:10:00.001+08:00</published><updated>2012-02-01T00:11:56.250+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-01T00:11:56.250+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gdb" /><title>查詢 gdb 的新功能</title><content type="html">&lt;p&gt;最近聽 &lt;a href="http://scottt.tw/"&gt;Scott&lt;/a&gt; 講到一些 gdb 的好功能, 發現為啥我這裡都沒有, 才發覺原來用的 gdb 版本不同。
&lt;/p&gt;&lt;p&gt;
要看 gdb 各版的 release note, 得下載 gdb 該版的 tarball, 解開後在 gdb/NEWS 裡有寫詳細的新功能。列一下最近聊到幾個我想用但在 7.2 卻沒有的新功能:
&lt;/p&gt;&lt;p&gt;
7.3 版: 加速 executable 載入時間的 gdb index:&lt;/p&gt;&lt;blockquote&gt;* GDB now has support for reading and writing a new .gdb_index
section. This section holds a fast index of DWARF debugging
information and can be used to greatly speed up GDB startup and
operation. See the documentation for `save gdb-index' for details.
&lt;/blockquote&gt;&lt;p&gt;
7.4 版: 不要在離開 scope 時刪掉 watch 的目標變數:&lt;/p&gt;&lt;blockquote&gt;* The "watch" command now accepts an optional "-location" argument.
When used, this causes GDB to watch the memory referred to by the
exblockquotession. Such a watchpoint is never deleted due to it going out
of scope.
&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-5492177002672805163?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/sKNYq0V5WPw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/5492177002672805163/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/gdb.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/5492177002672805163?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/5492177002672805163?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/sKNYq0V5WPw/gdb.html" title="查詢 gdb 的新功能" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/02/gdb.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cNRXwzfCp7ImA9WhRbE0o.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-8582024020423390235</id><published>2012-01-31T00:25:00.001+08:00</published><updated>2012-02-05T01:04:54.284+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-05T01:04:54.284+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gdb" /><title>gdb: 維持永久的 watchpoint</title><content type="html">&lt;p&gt;若想觀察特定變數的變化, &lt;a href="http://sourceware.org/gdb/current/onlinedocs/gdb/Set-Watchpoints.html#Set-Watchpoints"&gt;watchpoint&lt;/a&gt; 比 breakpoint 易於使用。但 &lt;a href="http://sourceware.org/gdb/current/onlinedocs/gdb/Set-Watchpoints.html#Set-Watchpoints"&gt;watchpoint&lt;/a&gt; 有個小問題, 一但離開 scope 後, gdb 會自動刪掉 &lt;a href="http://sourceware.org/gdb/current/onlinedocs/gdb/Set-Watchpoints.html#Set-Watchpoints"&gt;watchpoint&lt;/a&gt;。
&lt;/p&gt;&lt;p&gt;
若該變數是 member field, 就無法持續追踪不同 method 怎麼讀取或寫入它的值。&lt;a href="http://stackoverflow.com/a/7269569"&gt;這篇&lt;/a&gt;提供一個小技巧, 取用目標變數的指標, 再觀察指標取值的變數, 藉此讓 gdb 認定它不是區域變數, 借用該文的例子如下:&lt;/p&gt;&lt;pre class="prettyprint"&gt;(gdb) p &amp;amp;var1
$1 = (int *) 0x41523c0
(gdb) watch *(int *)0x41523c0
Hardware watchpoint 1: *(int *)0x41523c0
&lt;/pre&gt;&lt;p&gt;
若真的是區域變數的話, 可用 &lt;a href="http://sourceware.org/gdb/current/onlinedocs/gdb/Break-Commands.html#Break-Commands"&gt;commands&lt;/a&gt; 定義簡短的指令, &lt;a href="http://stackoverflow.com/a/1354742"&gt;之後進入函式時, 自動加回 watchpoint&lt;/a&gt;,  借用該文提供的例子:&lt;/p&gt;&lt;pre class="prettyprint"&gt;(gdb) break func
(gdb) commands
&amp;gt;   watch var
&amp;gt;   continue
&amp;gt; end
&lt;/pre&gt;
&lt;p&gt;
&lt;a href="http://sourceware.org/gdb/current/onlinedocs/gdb/Break-Commands.html#Break-Commands"&gt;commands&lt;/a&gt; 看來很方便, 還有許多適合應用的情境, 像是追踪網路連線輸出關鍵資訊, 可避免手動操作太久造成 timeout。&lt;/p&gt;
&lt;p&gt;
另外要注意, 若 gdb 用的是 software watchpoints, 它只會追踪單一 thread; 反之, hardware watchpoints 可以追踪全部 threads。
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;2012-02-04 更新&lt;/b&gt;
&lt;/p&gt;
&lt;p&gt;
gdb 7.4+ 支援 watch -l, 就不用自己取位置再設 watchpoint 解套。在 7.4 之前想用這功能, 可使用 &lt;a href="http://scottt.tw"&gt;Scott&lt;/a&gt; 寫的 &lt;a href="https://github.com/scottt/scottt-gdb/blob/master/gdb-watch-location.py"&gt;gdb-watch-location.py&lt;/a&gt;。用法是
&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
$ wget https://raw.github.com/scottt/scottt-gdb/master/gdb-watch-location.py
$ gdb -x gdb-watch-location.py PROG
&lt;/pre&gt;
&lt;p&gt;
在 gdb 裡會新增幾個指令: watch-l、rwatch-l、awatch-l 對應到 watch -l、rwatch -l、awatch -l。
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-8582024020423390235?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/MMmeqTENBMg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/8582024020423390235/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/gdb-keep-out-of-scope-watchpoint.html#comment-form" title="3 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/8582024020423390235?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/8582024020423390235?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/MMmeqTENBMg/gdb-keep-out-of-scope-watchpoint.html" title="gdb: 維持永久的 watchpoint" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/gdb-keep-out-of-scope-watchpoint.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUARncycCp7ImA9WhRbEU0.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-9039322422663061535</id><published>2012-01-29T16:04:00.001+08:00</published><updated>2012-02-01T21:17:27.998+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-01T21:17:27.998+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux programming" /><title>讀懂函式庫的 man page</title><content type="html">&lt;p&gt;初學 Linux 時, 覺得 man page 真不是寫給一般人看的, 到像是寫給已經懂的人備忘用的。即使現在已比較習慣讀 man page 了, 還是這麼覺得。
&lt;/p&gt;&lt;p&gt;
以前只知道 man function 看要引入什麼 header, 了解函式的參數、傳回值。最近才明白裡面的其它資訊。
&lt;/p&gt;&lt;p&gt;
背景知識可以&lt;a href="http://www.google.com.tw/search?ie=UTF-8&amp;amp;q=how+to+read+man+page"&gt;搜尋 "how to read man page"&lt;/a&gt; 或看 &lt;a href="http://en.wikipedia.org/wiki/Man_page"&gt;Wikipedia 介紹&lt;/a&gt;得知。這裡只針對使用函式庫講基礎知識。另外&lt;a href="https://github.com/fcamel/configs/blob/master/.bashrc_public#L52"&gt;這裡有顯示彩色 man page 的設定&lt;/a&gt;。
&lt;/p&gt;&lt;p&gt;
以 &lt;tt&gt;man 3 sqrt&lt;/tt&gt; 為例:&lt;/p&gt;&lt;pre class="prettyprint"&gt;SQRT(3)                                          Linux Programmer's Manual                                         SQRT(3)

NAME
       sqrt, sqrtf, sqrtl - square root function

SYNOPSIS
       #include &amp;lt;math.h&amp;gt;

       double sqrt(double x);
       float sqrtf(float x);
       long double sqrtl(long double x);

       Link with -lm.

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       sqrtf(), sqrtl():
           _BSD_SOURCE || _SVID_SOURCE || _XOPEN_SOURCE &amp;gt;= 600 || _ISOC99_SOURCE || _POSIX_C_SOURCE &amp;gt;= 200112L;
           or cc -std=c99
&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt; &lt;tt&gt;#include&lt;/tt&gt; 表示需要的 header&lt;/li&gt;
&lt;li&gt; 下面有函式的 signature&lt;/li&gt;
&lt;li&gt; &lt;tt&gt;Link with -lm&lt;/tt&gt; 表示使用 gcc 編譯時要加 &lt;tt&gt;-lm&lt;/tt&gt;, ld 才會找到 libm.so。詳細的運作過程見&lt;a href="http://fcamel-life.blogspot.com/2012/01/ld-ldso-ldconfig.html?showComment=1327793779646#comment-c109241311192708541"&gt;《ld, ld.so 和 ldconfig 的行為》&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;tt&gt;Feature Test Macro&lt;/tt&gt; 是 UNIX 跨平台用的一套規範, 見 &lt;tt&gt;man feature_test_macros&lt;/tt&gt; 了解 feature test macro 的作用, 以及 glibc 認得的類型。feature test macro 要定義在檔案的一開頭才行, 或用 &lt;tt&gt;gcc -D&lt;/tt&gt; 定義。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
關於 feature test macro, 這裡指出要定義 &lt;tt&gt;_BSD_SOURCE&lt;/tt&gt;、...、&lt;tt&gt;_XOPEN_SOURCE &lt;/tt&gt; 等, 才能使用 sqrtf() 和 sqrtl() (&lt;tt&gt;math.h&lt;/tt&gt; 才會引入它們的宣告}}}。反之, sqrt() 有跨所有平台, 可直接使用。
&lt;/p&gt;&lt;p&gt;
&lt;a href="http://stackoverflow.com/questions/575350/why-cant-gcc-find-the-random-interface-when-std-c99-is-set"&gt;這裡&lt;/a&gt;和&lt;a href="http://stackoverflow.com/questions/3355298/unistd-h-and-c99-on-linux"&gt;這裡&lt;/a&gt;有相關說明, 解釋 &lt;tt&gt;-std=c99&lt;/tt&gt;、&lt;tt&gt;-std=gnu99&lt;/tt&gt; 的效果, 會定義不同的 feature test macro。若沒有考慮可攜性的話, 用 c99 編不過時改用 gnu99 可編過, 不用擔心會有什麼副作用。
&lt;/p&gt;&lt;p&gt;
所以, 要使用特定函式時, 要先看 man FUNCTION 了解需要定義的 feature test macro, 讓 compiler 可以編過。再來從 man FUNCTION 得知 static linking 需要的參數。
&lt;/p&gt;
&lt;p&gt;
要檢查目前程式定義了那些 feature test macro, 可以用:
&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
gcc -E -dD MYPROG.c
&lt;/pre&gt;
&lt;p&gt;
除查看 feature test macro 外, 用來查引入的常數也很方便, 比方說忘了 stdin 的 file number 的常數, 引入 unistd.h 後, 用 gcc 展開看一看, 就會找到&lt;tt&gt;#define STDIN_FILENO 0&lt;/tt&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-9039322422663061535?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/3kySlbRAkIs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/9039322422663061535/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/man-page.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/9039322422663061535?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/9039322422663061535?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/3kySlbRAkIs/man-page.html" title="讀懂函式庫的 man page" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/man-page.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAER387fSp7ImA9WhRUGUk.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-2441114110197660950</id><published>2012-01-29T14:36:00.001+08:00</published><updated>2012-01-31T02:05:06.105+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-31T02:05:06.105+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="linker" /><title>使用 RTLD_NEXT 實作 wrapper</title><content type="html">&lt;p&gt;先貼程式:&lt;/p&gt;&lt;pre class="prettyprint"&gt;// RLTD_NEXT is only supported in _GNU_SOURCE.
#define _GNU_SOURCE

#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;dlfcn.h&amp;gt;

void *malloc(size_t size) {
    void* (*m)(size_t);
    // 「標準」取得 function pointer 的寫法. 見 TLPI 42.1.2 p863 的說明
    *(void**)(&amp;amp;m) = dlsym(RTLD_NEXT, "malloc");
    printf("local malloc\n");
    return m(size);
}

int main(void) {
    int *t = malloc(sizeof(int));
    *t = 3;
    printf("%d\n", *t);
    return 0;
}
&lt;/pre&gt;&lt;p&gt;
編譯和執行結果:&lt;/p&gt;&lt;pre class="prettyprint"&gt;$ gcc m.c -ldl -o m
$ nm m | grep malloc
0000000000400604 T malloc
$ ./m
local malloc
3
&lt;/pre&gt;&lt;p&gt;
若去掉 malloc(), 加上 #include stdlib.h, 用 nm 看則是:&lt;/p&gt;&lt;pre class="prettyprint"&gt;$ nm m | grep malloc
                 U malloc@@GLIBC_2.2.5
&lt;/pre&gt;&lt;p&gt;
表示在 m 裡面沒有定義 malloc, 它存在 glibc 裡。malloc 後面的 "@@GLIBC_2.2.5" 是 &lt;a href="http://www.akkadia.org/drepper/symbol-versioning"&gt;version tag&lt;/a&gt;。當 shared library 裡有多個版本 malloc 時, 可用 &lt;a href="http://www.akkadia.org/drepper/symbol-versioning"&gt;version tag&lt;/a&gt; 來區別要用的是那一個 malloc, 詳情見 &lt;a href="http://man7.org/tlpi/"&gt;TLPI&lt;/a&gt; 42.3.2。
&lt;/p&gt;&lt;p&gt;
這裡的關鍵是 glibc 定義了擴充功能 — 假的 library handle: RTLD_DEFAULT 和 RTLD_NEXT。用前者取函式 (變數) 就和原本 ld.so 找 symbol 的方式一樣; 而後者則會找「下一個」, 這是針對實作 wrapper 的需求而定的。
&lt;/p&gt;&lt;p&gt;
由於是 glibc 的擴充, 編譯時要在開頭加上 &lt;tt&gt;#define _GNU_SOURCE&lt;/tt&gt; 或在命令列加 &lt;tt&gt;-D_GNU_SOURCE&lt;/tt&gt;, dlfcn.h 才會載入 RTLD_NEXT。關於 &lt;tt&gt;_GNU_SOURCE&lt;/tt&gt; 的說明, 見&lt;a href="http://fcamel-life.blogspot.com/2012/01/man-page.html"&gt;《讀懂函式庫的 man page》&lt;/a&gt;。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-2441114110197660950?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/n7PpXnoBoBY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/2441114110197660950/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/rtldnext-wrapper.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/2441114110197660950?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/2441114110197660950?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/n7PpXnoBoBY/rtldnext-wrapper.html" title="使用 RTLD_NEXT 實作 wrapper" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/rtldnext-wrapper.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UDQH84fyp7ImA9WhRUGUk.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-2772075017056666916</id><published>2012-01-29T01:16:00.001+08:00</published><updated>2012-01-31T01:41:11.137+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-31T01:41:11.137+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="strace" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="linker" /><title>ld, ld.so 和 ldconfig 的行為</title><content type="html">&lt;p&gt;&lt;a href="http://man7.org/tlpi/"&gt;TLPI&lt;/a&gt; ch41 相當值得一看, 從開發者使用 library 的角度說明 library 的生成、靜態連結、動態連結 (載入) 的行為, 內容不多不少, 正好就是我想知道的, 省了看 &lt;a href="http://linker.iecc.com/"&gt;linker、loader &lt;/a&gt;的時間。
&lt;/p&gt;&lt;h4&gt;shared library 的名詞介紹&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; soname: 記錄在 shared library header 裡的名稱, 格式為 libX.so.MAJOR。要有同名檔案, 供之後程式載入 shared library 時使用&lt;/li&gt;
&lt;li&gt; real name: shared library 的檔名, 格式為 libX.so.MAJOR.MINOR.NUMBER&lt;/li&gt;
&lt;li&gt; linker name: 對 library X 來說, 就是 libX.so, 一般會是 symbolic link 指向最新的 major shared library&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
以 libjpeg 為例, 對應如下:&lt;/p&gt;&lt;pre class="prettyprint"&gt;libjpeg.so -&amp;gt; libjpeg.so.62.0.0     # linker name
libjpeg.so.62 -&amp;gt; libjpeg.so.62.0.0  # soname
libjpeg.so.62.0.0                   # real name
&lt;/pre&gt;&lt;p&gt;
這是我在 Ubuntu 裝好 package 後的樣子, 照理說 libjpeg.so 指向 libjpeg.so.62 應該會更彈性。
&lt;/p&gt;&lt;p&gt;
讀出 soname:&lt;/p&gt;&lt;pre class="prettyprint"&gt;$ readelf -d libjpeg.so | grep SONAME
 0x000000000000000e (SONAME)             Library soname: [libjpeg.so.62]
&lt;/pre&gt;&lt;h4&gt;static 和 dynamic linker&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; ld (ld.bfd) 是 static linker。Google 開發的 &lt;a href="http://google-opensource.blogspot.com/2008/04/gold-google-releases-new-and-improved.html"&gt;gold&lt;/a&gt; 是取代 ld.bfs 的 static linker。用 gcc 連結 shared library 或 executable 時就是呼叫 ld, 並將需要的參數傳給它。不論連結的是 static library 或 shared library, 都是 static linking。&lt;/li&gt;
&lt;li&gt; ld 在連結 shared library 或 executable 時, 會將需要的 shared library 的 soname 寫入結果檔裡。注意, 只有 soname 而已, 沒有完整路徑。&lt;/li&gt;
&lt;li&gt; ld-VERSION.so 是 dynamic (runtime) linker, 執行程式時, 由 runtime linker 載入 executable 開始。若 OS 用的 glibc 版本為 2.13, 就叫 ld-2.13.so。用 ldd 看所有執行檔, 都會找到它 (某個 symbolic link 連到 ld-2.13.so)。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
以連結 libm.so 為例, 執行 &lt;tt&gt;gcc -lm prog.c -o prog&lt;/tt&gt; 中間的部份行為如下:&lt;/p&gt;&lt;ol&gt;
&lt;li&gt; gcc 透過 -lm 的指示告知 ld 要連結 libm.so&lt;/li&gt;
&lt;li&gt; ld 會找到某處的 libm.so 指向 /lib/x86_64-linux-gnu/libm.so.6, 確認要用到的 symbol 都有, 沒有 link error&lt;/li&gt;
&lt;li&gt; ld 從 libm.so.6 的 header 讀出 soname "libm.so.6", 寫入 "libm.so.6" 到 prog 的 header。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;
執行 prog 時, ld-2.13.so 會從 prog 讀出 "libm.so.6", 再到預設的路徑上找檔名 "libm.so.6"。注意, static linking 時需要 libm.so, 但之後執行 prog 時用不到它, 因為記錄的 soname 為 "libm.so.6"。
&lt;/p&gt;&lt;p&gt;
關於 static linking 找檔名的順序, 可用 strace 觀察:&lt;/p&gt;&lt;pre class="prettyprint"&gt;$ strace -e open,execve -f -o gcc.trace gcc -lm prog.c -o prog
&lt;/pre&gt;&lt;p&gt;
在 gcc.trace 裡可看出一二。
&lt;/p&gt;&lt;p&gt;
ps.&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; 使用 execve 的目的是知道 child process 是那一個程式, 目標是看 ld 開敋的檔案&lt;/li&gt;
&lt;li&gt; 可由 man 2 exec&amp;lt;TAB&amp;gt; 得知 system call 使用的 exec 函式為 execve。&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;ldconfig&lt;/h4&gt;&lt;p&gt;執行 ldconfig 後, 它做的事如下:&lt;/p&gt;&lt;ol&gt;
&lt;li&gt; 讀出 /lib, /usr/lib, /etc/ld.so.conf 內的路徑之下的 shared library (ldconfig 會略過 symbolic link), 將結果寫入 /etc/ld.so.cache。之後 ld-2.13.so 會用 ld.so.cache 的記錄來找 shared library。&lt;/li&gt;
&lt;li&gt; ldconfig 會&lt;strong&gt;自動產生 symbolic link "libX.so.MAJOR" 指向最新版本的 shared library&lt;/strong&gt;。例如 /lib/libfoo.so.2.0.1 的 soname 是 libbar.so.2, 執行 ldconfig 後, 它會產生 /lib/libbar.so.2 指向 /lib/libfoo.so.2.0.1。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;
之前困擾我許久的事就是第二步, 而 &lt;tt&gt;man ldconfig&lt;/tt&gt; 裡沒提到這點。
&lt;/p&gt;&lt;p&gt;
結論是別隨便手動更新 soname 的檔案, 執行 ldconfig 後可能會出問題。裝套件後, 系統工具會自動跑 ldconfig 更新目錄, 可能會蓋掉自己手動更新的同檔名檔案。另外 ldconfig 沒有管 linker name, 若是自己編的 shared library, 要自己產生。
&lt;/p&gt;&lt;h4&gt;其它&lt;/h4&gt;&lt;p&gt;若想連到舊的 major 版本 shared library, 得在 gcc 參數指定舊版檔名。還有可用 rpath 的參數寫入搜尋 shared library 的路徑到 shared library 或 executable 裡。關於這些細節, 還有 static linker 以及 dynamic linker 尋找 shared library 的完整順序, &lt;a href="http://man7.org/tlpi/"&gt;TLPI&lt;/a&gt; ch41 講得相當清楚。ch42 描述 dlopen, 之後再來翻翻。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-2772075017056666916?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/U3D7VAfjzko" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/2772075017056666916/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/ld-ldso-ldconfig.html#comment-form" title="1 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/2772075017056666916?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/2772075017056666916?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/U3D7VAfjzko/ld-ldso-ldconfig.html" title="ld, ld.so 和 ldconfig 的行為" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/ld-ldso-ldconfig.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A04ARX4-eyp7ImA9WhRUFk4.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-5614875832261287140</id><published>2012-01-27T12:51:00.001+08:00</published><updated>2012-01-27T12:52:24.053+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-27T12:52:24.053+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="C" /><category scheme="http://www.blogger.com/atom/ns#" term="C99" /><title>C99 好用的語法</title><content type="html">&lt;p&gt;之前只有用到 &lt;a href="http://en.wikipedia.org/wiki/C99"&gt;C99&lt;/a&gt; 的 loop initial declarations (在 for 的初始化部份宣告變數), 看 &lt;a href="http://scottt.tw"&gt;Scott&lt;/a&gt; 提到才知道有其它好東西, 順便來掃一下 &lt;a href="http://en.wikipedia.org/wiki/C99#Design"&gt;C99 的功能&lt;/a&gt;
&lt;/p&gt;&lt;h4&gt;stdbool.h&lt;/h4&gt;&lt;p&gt;定義 bool、true、false, 實際上是將 bool 對應到 C99 定義 _Bool 
&lt;/p&gt;&lt;h4&gt;stdint.h&lt;/h4&gt;&lt;p&gt;定義了整數範圍、int16_t、int32_t、int64_t 等型別, 再也不用查 short/int/long 等在 32/64 bit OS 上的大小為多少。
&lt;/p&gt;&lt;h4&gt;designated initializers&lt;/h4&gt;&lt;p&gt;可攜又易讀的初始化 (&lt;a href="http://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html"&gt;ref.&lt;/a&gt;)&lt;/p&gt;&lt;pre class="prettyprint"&gt;// array
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
// struct
struct point { int x, y; };
struct point p = { .y = yvalue, .x = xvalue };
&lt;/pre&gt;&lt;p&gt;
像要用建表實作 isspace() 的話, 這樣寫超清楚的:&lt;/p&gt;&lt;pre class="prettyprint"&gt;bool myisspace(int ch) {
    static bool whitespace[256] = {
        [' '] = true, ['\t'] = true, ['\f'] = true,
        ['\n'] = true, ['\r'] = true
    };

    if (ch &amp;lt; 0 || ch &amp;gt;= 256)
        return false;
    return whitespace[ch];
}
&lt;/pre&gt;&lt;h4&gt;其它&lt;/h4&gt;&lt;p&gt;像 snprintf、inline、variable-length array (例如 int array[n]) 也很實用。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-5614875832261287140?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/oajdRCKeoq8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/5614875832261287140/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/c99.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/5614875832261287140?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/5614875832261287140?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/oajdRCKeoq8/c99.html" title="C99 好用的語法" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/c99.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcDSXwyeSp7ImA9WhRUFk0.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-5953180622012475138</id><published>2012-01-27T03:40:00.001+08:00</published><updated>2012-01-27T03:44:38.291+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-27T03:44:38.291+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux programming" /><title>signal 小知識</title><content type="html">&lt;p&gt;看 &lt;a href="http://man7.org/tlpi/"&gt;TLPI&lt;/a&gt; 長知識。
&lt;/p&gt;&lt;h4&gt;先送 SIGTERM 再送 SIGKILL 砍程式&lt;/h4&gt;&lt;p&gt;若程式有照標準寫, 可能會有 SIGTERM 的 handler, 在收到這 signal 時做些清理動作 (砍暫存檔、釋放資源等), 再自我了結。而 SIGKILL 就直接掛了。所以, 先給人家一個機會掛得優雅一些, 若對方拒絕的話, 再狠一點直接掛了它。
&lt;/p&gt;
&lt;p&gt;
附帶一提, ctrl + c 是送出 SIGINT。
&lt;/p&gt;
&lt;h4&gt;SIGHUP 的行為&lt;/h4&gt;&lt;p&gt;terminal 斷線 (hangup) 時, terminal 的主控 process 會收到 SIGHUP。而它的預設行為是終結程式, 所以關掉 terminal 時, 裡面的程式會直接結束。
&lt;/p&gt;&lt;p&gt;
bash 和 ksh 在結束的時候會送 SIGHUP 給背景程式, 若背景程式也沒寫 SIGHUP handler, 那它們也會一起結束。這是關掉 terminal, 全部程式會一起結束的原因。
&lt;/p&gt;&lt;p&gt;
要避免這個行為, 可用 nohup 執行程式, 它會做 I/O 重導、執行 &lt;tt&gt;signal (SIGHUP, SIG_IGN)&lt;/tt&gt;, 然後執行目標程式。或是用 bash 的 disown -h, 再放到背景跑, 或&lt;a href="http://blog.vgod.tw/2006/06/21/gdb%E7%9A%84%E5%A6%99%E7%94%A8/"&gt;用 gdb attach process, 再輸入 handle SIGHUP nopass&lt;/a&gt;。
&lt;/p&gt;&lt;h4&gt;用 SIGQUIT 產生 core dump&lt;/h4&gt;&lt;p&gt;在 terminal 按 ctrl + \ 時會送出 SIGQUIT 給前景程式, 這個 signal 的作用是要就該程式自我了結並產生 core dump。當然, &lt;a href="http://fcamel-life.blogspot.com/2011/12/core-dump-cgdb.html"&gt;一些設定要先設好, 才會有 core dump&lt;/a&gt;。
&lt;/p&gt;&lt;p&gt;
這有許多好處:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; 程式進無窮迴圈時按 ctrl + \, 再用 gdb 列 backtrace 看卡在那。雖說直接 用 gdb attach 也 ok。若高中練 ACM 知道這個方法, 可省下一些除錯時間 (遠目)。&lt;/li&gt;
&lt;li&gt; 方便&lt;a href="http://fcamel-life.blogspot.com/2011/12/core-dump-cgdb.html"&gt;測試 core dump 設定&lt;/a&gt;, 不用另寫個小程式故意寫入不合法的位置。&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-5953180622012475138?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/hoBgJ9gouuI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/5953180622012475138/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/signal.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/5953180622012475138?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/5953180622012475138?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/hoBgJ9gouuI/signal.html" title="signal 小知識" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/signal.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08DSHk-eCp7ImA9WhRUE0w.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-6970270955976433226</id><published>2012-01-23T19:57:00.001+08:00</published><updated>2012-01-23T19:57:59.750+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-23T19:57:59.750+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux programming" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><title>Linux 的 capability</title><content type="html">&lt;p&gt;昨天看 &lt;a href="http://man7.org/tlpi/"&gt;TLPI&lt;/a&gt; ch39 才知道 Linux 有 capability 可依項目授權, 不用像以前那樣, 使用 &lt;a href="http://en.wikipedia.org/wiki/Setuid"&gt;setuid&lt;/a&gt; 一次大放送。像 passwd 就是 &lt;a href="http://en.wikipedia.org/wiki/Setuid"&gt;setuid&lt;/a&gt; 的典型使用情境, 要讓所有使用者能改自己的密碼, 所以他們要有權限存取密碼檔, 但又不能讓使用者做超出他們該做的事。於是, 使用 &lt;a href="http://en.wikipedia.org/wiki/Setuid"&gt;setuid&lt;/a&gt; 的程式需要很小心地設計, 避免給太多權限, 或是被 cracker 攻破取得 root 權限。
&lt;/p&gt;&lt;p&gt;
看到 capability 如此地威, 不禁納悶有多少程式有使用 capability, &lt;a href="http://scottt.tw"&gt;Scott&lt;/a&gt; 提供&lt;a href="https://plus.google.com/111353793049965752735/posts/XuFMkJfwSEf"&gt;一個不錯的找法&lt;/a&gt;: 用 package 管理套件找出有那些程式依賴 capability 的套件, 就知道了。Ubuntu 對應的指令是 &lt;tt&gt;apt-rdepends -r libcap2&lt;/tt&gt;, 也不算少, 有 100 多個套件用到 libcap2。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-6970270955976433226?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/2-p55vaQ3HI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/6970270955976433226/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/linux-capability.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/6970270955976433226?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/6970270955976433226?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/2-p55vaQ3HI/linux-capability.html" title="Linux 的 capability" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/linux-capability.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYGSX4-eyp7ImA9WhRUE0w.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-4968166977281787068</id><published>2012-01-23T13:59:00.001+08:00</published><updated>2012-01-23T18:55:28.053+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-23T18:55:28.053+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tracing code" /><category scheme="http://www.blogger.com/atom/ns#" term="strace" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><title>用 strace 找出 Ubuntu 如何提示未安裝的指令</title><content type="html">&lt;p&gt;在 Ubuntu 下執行指令後, 若沒有安裝指令的話, 會出現提示:&lt;/p&gt;&lt;pre class="prettyprint"&gt;$ apt-rdepends
The program 'apt-rdepends' is currently not installed.  You can install it by typing:
sudo apt-get install apt-rdepends
&lt;/pre&gt;&lt;p&gt;
但若直接用 bash 執行, 卻不會有這效果:&lt;/p&gt;&lt;pre class="prettyprint"&gt;$ bash -c apt-rdepends
bash: apt-rdepends: command not found
&lt;/pre&gt;&lt;p&gt;
以前覺得很好奇, Ubuntu 怎麼做到這件事的, 知道 strace 以後, 追這類原因簡單許多, 只要有輸入和輸出訊息, 就可夾擊出一些線索。
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; 在 terminal 1 輸入 &lt;tt&gt;echo $$&lt;/tt&gt; 取得該 bash 的 PID&lt;/li&gt;
&lt;li&gt; 在 terminal 2 輸入 &lt;tt&gt;sudo strace -obash.trace -f -s512 -p PID&lt;/tt&gt;&lt;ul&gt;
&lt;li&gt; -obash.trace 表示將輸出存到 bash.trace, 訊息很多, 通常都會寫到檔案裡&lt;/li&gt;
&lt;li&gt; -s512 表示輸出訊息最多到 512, 預設行寬有點短, 之後不方便找輸出的訊息&lt;/li&gt;
&lt;li&gt; -f 表示一起追蹤 child process, 這點很重要, 沒加 -f 就追不到 bash 使用的其它子程序, 而關鍵就在 bash 叫起的子程序&lt;/li&gt;
&lt;li&gt; -p PID 表示追踪其它 process, 照理說同一個使用者不用 root 權限應該也能看, 不知為啥不通&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt; 在 terminal 1 輸入 apt-rdepends, 因為 strace 有用 "-f", 速度會慢很多。等待指令完成&lt;/li&gt;
&lt;li&gt; 在 terminal 2 按 Ctrl+C 中斷 strace, 觀察 bash.trace&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
搜一下 "apt-rdepends" 會看到 bash 在嘗試各種 path 後都找不到檔案:&lt;/p&gt;&lt;pre class="prettyprint"&gt;16520 stat("/home/fcamel/bin/apt-rdepends", 0x...) = -1 ENOENT...
16520 stat("/usr/local/sbin/apt-rdepends", 0x...) = -1 ENOENT...
16520 stat("/usr/local/bin/apt-rdepends", 0x...) = -1 ENOENT...
16520 stat("/usr/sbin/apt-rdepends", 0x...) = -1 ENOENT...
16520 stat("/usr/bin/apt-rdepends", 0x...) = -1 ENOENT...
16520 stat("/sbin/apt-rdepends", 0x...) = -1 ENOENT...
16520 stat("/bin/apt-rdepends", 0x...) = -1 ENOENT...
16520 stat("/usr/games/apt-rdepends", 0x...) = -1 ENOENT...
16520 stat("/home/fcamel/bin/apt-rdepends", 0x...) = -1 ENOENT...
16520 stat("/home/fcamel/bin/apt-rdepends", 0x...) = -1 ENOENT...
&lt;/pre&gt;&lt;p&gt;
之後在別的 child process 呼叫外部程式執行 /usr/lib/command-not-found:&lt;/p&gt;&lt;pre class="prettyprint"&gt;16877 execve("/usr/bin/python", ["/usr/bin/python", "/usr/lib/command-not-found", "--", "apt-rdepends"], [/* 38 vars */]) = 0
&lt;/pre&gt;&lt;p&gt;
若想研究怎麼找出該裝的套件, 可以研究 "/usr/lib/command-not-found"。若想研究 bash 如何判斷在有 terminal 的情況下要多找安裝的指令, 可以自己&lt;a href="http://fcamel-life.blogspot.com/2012/01/debug-symbol-package.html"&gt;編含 debug symbol 的 bash&lt;/a&gt;, 再用 gdb 找出相關位置, 再讀附近的原始碼。這樣一來, 至少知道需要追的時候該如何進行, 剩下就是增加經驗提昇追程式的速度了。&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;2012-01-23 更新&lt;/b&gt;
&lt;/p&gt;
&lt;p&gt;
經 &lt;a href="https://plus.google.com/115208016645517532827/posts"&gt;wens&lt;/a&gt; 提醒, 原來是用 bash 的 hook 做的, 見 /etc/bash.bashrc 了解設定, man bash 在 COMMAND EXECUTION 那節有說明。
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-4968166977281787068?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/TN9KwzrJxRk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/4968166977281787068/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/strace-ubuntu.html#comment-form" title="2 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/4968166977281787068?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/4968166977281787068?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/TN9KwzrJxRk/strace-ubuntu.html" title="用 strace 找出 Ubuntu 如何提示未安裝的指令" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/strace-ubuntu.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQFRX84eCp7ImA9WhRUEk8.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-1155693733044829006</id><published>2012-01-22T16:41:00.001+08:00</published><updated>2012-01-22T17:25:14.130+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-22T17:25:14.130+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="gdb" /><title>gdb 如何找到 debug symbol</title><content type="html">&lt;p&gt;先前在&lt;a href="http://fcamel-life.blogspot.com/2012/01/glibc.html"&gt;《追踪 glibc 裡的程式》&lt;/a&gt;提到自己如何亂試, 試出讓 gdb 讀到 debug symbol。昨天聽 &lt;a href="http://scottt.tw/"&gt;Scott&lt;/a&gt; 說明, 才知道背後是怎麼一回事。
&lt;/p&gt;&lt;p&gt;
在 Ubuntu 下以 libm 為例, 在 /lib/x86_64-linux-gnu/libm-2.13.so 裡面, 先看一些相關的 section header:&lt;/p&gt;&lt;pre class="brush: bash"&gt;$ objdump -h /lib/x86_64-linux-gnu/libm-2.13.so | grep gnu
/lib/x86_64-linux-gnu/libm-2.13.so:     file format elf64-x86-64
  0 .note.gnu.build-id 00000024  0000000000000238  0000000000000238  00000238  2**2
  2 .gnu.hash     00000fa4  0000000000000280  0000000000000280  00000280  2**3
  5 .gnu.version  00000298  00000000000038da  00000000000038da  000038da  2**1
  6 .gnu.version_d 0000005c  0000000000003b78  0000000000003b78  00003b78  2**3
  7 .gnu.version_r 00000030  0000000000003bd8  0000000000003bd8  00003bd8  2**3
 27 .gnu_debuglink 00000014  0000000000000000  0000000000000000  000840e4  2**0
&lt;/pre&gt;&lt;p&gt;
幾個重點&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; .note.gnu.build-id 表示 binary id, 之後用來比對 debug symbol 是否出自 shared lib。看起來 Fedora 在找 debug symbol 時, 有用到 binary id; 而 Ubuntu 沒有的樣子, 我用 hexedit 亂改這個 section 的值, 仍能找到 debug symbol&lt;/li&gt;
&lt;li&gt; .gnu_debuglink 指向包含 debug symbol 的檔案, 若用 hexedit 改掉它的值, 執行 &lt;tt&gt;gdb /lib/x86_64-linux-gnu/libm-2.13.so&lt;/tt&gt;, gdb 會表示找不到 libm 的 debug symbol&lt;/li&gt;
&lt;li&gt; 可用 &lt;tt&gt;objdump -s -j .gnu_debuglink /lib/x86_64-linux-gnu/libm-2.13.so&lt;/tt&gt; 顯示 section 內容&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
若用 &lt;tt&gt;LD_PRELOAD=/usr/lib/debug/lib/x86_64-linux-gnu/libm-2.13.so ANY_PROGRAM&lt;/tt&gt; 執行程式, 結果會 segmentation fault, 所以我推測 Ubuntu 下 X-dbg 裡包的檔案, 可能和 Fedora 一樣, 只有 debug symbol 而不是完整 strip 前的函式庫。不知要如何確認該檔案裡只有 debug symbol 沒有實際的 object code。
&lt;/p&gt;&lt;p&gt;
至於確認原本的 binary (object file / shared lib / executable) 是否有編入 debug symbol, 除了用 objdump -S 再找看看有沒有出現程式碼外, 更簡單的作法是用 objdump -h | grep debug:&lt;/p&gt;&lt;pre class="brush: bash"&gt;$ objdump -h /usr/lib/debug/lib/x86_64-linux-gnu/libm-2.13.so | grep debug
/usr/lib/debug/lib/x86_64-linux-gnu/libm-2.13.so:     file format elf64-x86-64
 28 .debug_aranges 00004770  0000000000000000  0000000000000000  000002b0  2**4
 29 .debug_pubnames 00002e44  0000000000000000  0000000000000000  00004a20  2**0
 30 .debug_info   000318ee  0000000000000000  0000000000000000  00007864  2**0
 31 .debug_abbrev 00010fc3  0000000000000000  0000000000000000  00039152  2**0
 32 .debug_line   00018c20  0000000000000000  0000000000000000  0004a115  2**0
 33 .debug_str    000041bc  0000000000000000  0000000000000000  00062d35  2**0
 34 .debug_loc    00062bc5  0000000000000000  0000000000000000  00066ef1  2**0
 35 .debug_pubtypes 00003a11  0000000000000000  0000000000000000  000c9ab6  2**0
 36 .debug_ranges 00003e30  0000000000000000  0000000000000000  000cd4c7  2**0
&lt;/pre&gt;
&lt;p&gt;
有上述 section 的話, 表示有含 debug symbols。
&lt;/p&gt;
&lt;h4&gt;備註&lt;/h4&gt;&lt;p&gt;1. hexedit 基本指令&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; F1: 等同於 man hexedit&lt;/li&gt;
&lt;li&gt; F4: 跳到 offset, 對照 &lt;tt&gt;objdump -h X&lt;/tt&gt; 看倒數第二欄使用&lt;/li&gt;
&lt;li&gt; TAB: 切換 hexadecimal 或 ascii 區, 之後取代內容或搜尋, 和這有關&lt;/li&gt;
&lt;li&gt; 直接在 byte 上打字取代 &lt;/li&gt;
&lt;li&gt; /: 找字串&lt;/li&gt;
&lt;li&gt; ctrl+c / ctrl+x: 離開 / 存檔離開&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
2. 見&lt;a href="http://dwarfstd.org/"&gt;《The DWARF Debugging Standard》&lt;/a&gt;了解 debug 資訊如何存在檔案, 只是留著備忘, 目前應該沒必要去讀。
&lt;/p&gt;&lt;p&gt;
3. 若是&lt;a href="http://fcamel-life.blogspot.com/2012/01/debug-symbol-package.html"&gt;自己編含 debug symbol 的函式庫&lt;/a&gt;, 就不是上述那一回事了, 而是直接編進目前的函式庫裡。&lt;/p&gt;
&lt;p&gt;
4. &lt;a href="http://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html"&gt;《Separate Debug Files - Debugging with GDB》&lt;/a&gt;說明 gdb 如何支援分離 debug symbol 到另一個檔案, 另外 man strip 或 man objcopy, 可在 "--only-keep-debug" 的部份看到相關說明。看來要知道到底各個 distribution 怎麼做這事, 去看該 distribution 官方的說明會比較確實。之後再看看吧。
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-1155693733044829006?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/LIwp02Vez_w" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/1155693733044829006/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/gdb-debug-symbol.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/1155693733044829006?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/1155693733044829006?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/LIwp02Vez_w/gdb-debug-symbol.html" title="gdb 如何找到 debug symbol" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/gdb-debug-symbol.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcBQXk5fip7ImA9WhRVGUU.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-5608313714274149817</id><published>2012-01-19T22:07:00.001+08:00</published><updated>2012-01-19T22:07:30.726+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-19T22:07:30.726+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ipad" /><title>iPad 升級到 iOS 5</title><content type="html">&lt;p&gt;不知是否因為和 &lt;a href="https://plus.google.com/102249536116095884743/posts"&gt;command&lt;/a&gt; 一樣人品不好, 用 Apple 的產品總遇到一堆鳥事, 讓我對 Apple 產品難以建立好感。
&lt;/p&gt;&lt;p&gt;
照官網和 google 大部份人的說法來看, 就 iTunes 升到 10.5, 將 iPad 接上去, 在 iTunes 裡按 check for update 即可。但 iTunes 回報 &lt;a href="https://discussions.apple.com/thread/2777777?start=0&amp;amp;tstart=0"&gt;This version of the iPad software (4.2) is the current version&lt;/a&gt;。
&lt;/p&gt;&lt;p&gt;
有人提到可嘗試&lt;a href="http://osxdaily.com/2011/10/12/ios-5-download-available"&gt;手動升級&lt;/a&gt;, 下載好 firmware 檔後, 照著指示手動選檔案 restore, 結果出現 "this device isn't eligible for the requested build"。google 看到有許多人提到類似問題, 但有些是 jail break 造成的, 提到的解法看來也不適用於我的情況, 況且我用的 iPad 應該沒 JB。
&lt;/p&gt;&lt;p&gt;
最後在 restore mode 下, 成功地升到 iOS 5.x 了, 太感謝這個影片, 操作方式講解得非常清楚: &lt;a href="http://www.youtube.com/watch?v=dJkf8O8wOoU"&gt;《How to Enter DFU Mode | Restore Mode - Get Out of DFU Mode | Restore Mode - Fast, Safe &amp;amp; Easy - YouTube》&lt;/a&gt;。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-5608313714274149817?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/SVP8fVooumU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/5608313714274149817/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/ipad-ios-5.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/5608313714274149817?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/5608313714274149817?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/SVP8fVooumU/ipad-ios-5.html" title="iPad 升級到 iOS 5" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/ipad-ios-5.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQHRHc7cCp7ImA9WhRVGU0.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-3236618177313310722</id><published>2012-01-18T22:37:00.004+08:00</published><updated>2012-01-18T23:58:55.908+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-18T23:58:55.908+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="build" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="gdb" /><title>自行編譯含 debug symbol 的套件 (package)</title><content type="html">&lt;p&gt;對函式庫 X 來說&lt;/p&gt;&lt;ul&gt;&lt;li&gt; X-dev 表示讓開發者用的, 有裝 header、文件之類的&lt;/li&gt;
&lt;li&gt; X-dbg 內容類似 X, 不過有留 debug symbol&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;比方說 libjpeg, 三種的描述如下:&lt;/p&gt;&lt;ul&gt;&lt;li&gt; libjpeg62 - The Independent JPEG Group's JPEG runtime library&lt;/li&gt;
&lt;li&gt; libjpeg62-dbg - Development files for the IJG JPEG library&lt;/li&gt;
&lt;li&gt; libjpeg62-dev - Development files for the IJG JPEG library&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;裝了 X-dbg 後什麼事也不用做, &lt;a href="http://fcamel-life.blogspot.com/2012/01/glibc.html"&gt;gdb 自己會優先用含 debug symbol 的版本&lt;/a&gt;。不過若官方沒提供供 X-dbg 的話, 就得自己編。參考官方文件&lt;a href="http://wiki.debian.org/HowToGetABacktrace"&gt;《HowToGetABacktrace - Debian Wiki》&lt;/a&gt;, 做法如下:&lt;/p&gt;&lt;ul&gt;&lt;li&gt; $ apt-get install build-essential fakeroot gdb&lt;/li&gt;
&lt;li&gt; $ apt-get build-dep X&lt;/li&gt;
&lt;li&gt; $ DEB_BUILD_OPTIONS="nostrip noopt" fakeroot apt-get -b source X&lt;/li&gt;
&lt;li&gt; $ dpkg -i X.deb&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;針對上述指令, 補充幾點&lt;/p&gt;&lt;ul&gt;&lt;li&gt; 編好套件後, 可用 dpkg -c X.deb 先看裡面裝了什麼&lt;/li&gt;
&lt;li&gt; 用 objdump &lt;span class="escaped"&gt;-&lt;/span&gt;-source FILE 查看裡面有沒有含程式碼, 有的話才表示確實有含 debug symbol。這個作法比用 file FILE 看是否有 strip 更確實。二進位檔有可能沒含 debug symbol 也沒 strip。&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-3236618177313310722?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/1NOBukmyBvQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/3236618177313310722/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/debug-symbol-package.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/3236618177313310722?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/3236618177313310722?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/1NOBukmyBvQ/debug-symbol-package.html" title="自行編譯含 debug symbol 的套件 (package)" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/debug-symbol-package.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU4CRXg7fSp7ImA9WhRVF08.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-2729632316090860461</id><published>2012-01-16T22:20:00.002+08:00</published><updated>2012-01-16T22:26:04.605+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-16T22:26:04.605+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>Python debug 的方法</title><content type="html">&lt;p&gt;有別於 C/C++, Python 通常會有原始碼, 除非套件提供者無腦地用 egg 包裝, 不然應該滿好改程式碼的 (我討厭 egg!! 其實這有雙關, 不過 ...)。再加上使用 &lt;a href="http://pypi.python.org/pypi/virtualenv"&gt;virtualenv&lt;/a&gt; 擁有自己安裝的函式庫, 這樣和別人共用 server 時, 不用擔心改函式庫的程式會影響到別人, 相當方便。&lt;/p&gt;&lt;p&gt;在這樣方便改程式的情況下, 通常我會採下列三種方法之一來觀察程式 (或除錯):&lt;br /&gt;
&lt;/p&gt;&lt;h4&gt;使用 IPython&lt;/h4&gt;&lt;p&gt;在要觀察程式的地方寫入&lt;br /&gt;
&lt;pre class=prettyprint&gt;import IPython
IPython.Shell.IPShellEmbed()()
&lt;/pre&gt;我甚至寫了個 &lt;a href="https://github.com/fcamel/configs/blob/master/.vim/plugin/python/python_setting.vim#L28"&gt;vim 巨集&lt;/a&gt;展開這段。&lt;br /&gt;
&lt;/p&gt;&lt;h4&gt;使用 &lt;a href="http://docs.python.org/library/pdb.html"&gt;pdb&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;&lt;pre class=prettyprint&gt;import pdb; pdb.set_trace()
&lt;/pre&gt;效果類以上一個, 不過應該是 ipython 更易操作。或許也可考慮用 &lt;a href="http://pypi.python.org/pypi/ipdb"&gt;IPython pdb&lt;/a&gt;。&lt;br /&gt;
&lt;/p&gt;&lt;h4&gt;使用 logger&lt;/h4&gt;&lt;p&gt;配合 decorator 的語法, python 要觀察特定函式容易許多, 如&lt;a href="http://blog.roodo.com/descriptor/archives/9206319.html"&gt;這篇&lt;/a&gt;提到的做法, 寫個 decorator "log", 配合 lazy initialization 的方式&lt;a href="http://docs.python.org/library/logging.html#logging.basicConfig"&gt;設定 logging&lt;/a&gt;。之後只要在有興趣的幾個函式上加個 @log 即可。&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;這個作法應用的範圍更大, 像在 &lt;a href="http://en.wikipedia.org/wiki/Web_Server_Gateway_Interface"&gt;WSGI&lt;/a&gt; 沒 console 可用, 也不能輸出到 STDOUT, 用這招就沒問題。還有, 這個作法也可在 production 環境記錄關鍵函式的執行速度, 協助 profiling。&lt;br /&gt;
&lt;/p&gt;&lt;h4&gt;題外話&lt;/h4&gt;&lt;p&gt;若是要除錯的話, 視情況用 unit test 會更好, 原因見&lt;a href="http://fcamel-fc.blogspot.com/2009/06/unit-test.html"&gt;《為什麼要寫 unit test？為什麼要先寫測試？》&lt;/a&gt;。在見識過 C/C++ 的困難處後, 覺得在 Python 的環境裡寫 test 實在是太輕鬆寫意了, 雖說寫 test 確實還是有它的難處, 不過該寫的東西之前寫得差不多了, 有興趣的人請翻翻舊文。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-2729632316090860461?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/VfzYhfR-INs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/2729632316090860461/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/python-debug.html#comment-form" title="1 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/2729632316090860461?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/2729632316090860461?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/VfzYhfR-INs/python-debug.html" title="Python debug 的方法" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/python-debug.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEEEQX46cSp7ImA9WhRVFkk.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-4922212675976315988</id><published>2012-01-16T00:34:00.003+08:00</published><updated>2012-01-16T00:56:40.019+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-16T00:56:40.019+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="virtualbox" /><title>VirtualBox 改變 vdi 的大小</title><content type="html">&lt;p&gt;花了一整個晚上的血淚談。 &lt;/p&gt;&lt;h4&gt;注意事項&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; 目前 (4.x) 只支援在沒有 snapshots 的情況下改變 vdi 大小&lt;/li&gt;
&lt;li&gt; 若目前有用 snapshot, &lt;a href="http://www.virtualbox.org/manual/ch08.html"&gt;VBoxManage&lt;/a&gt; 也不會阻止你改變大小, 只是改完就沒救了, 會無法刪掉最早的 snapshot, 推測是因為硬碟上的 vdi 檔案資訊和 snapshot 內的 vdi 不合。可以刪除中間的 snapshot, 因為那沒有涉及硬碟上的 vdi 檔&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;擴大 vdi&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; 關掉 guest OS&lt;/li&gt;
&lt;li&gt; 砍掉所有 snapshot, 只剩 current state: 在命令列下使用 VBoxManage modifyhd &lt;span class="escaped"&gt;-&lt;/span&gt;-resize NUM_MB /path/to/vdi&lt;/li&gt;
&lt;li&gt; 用 Ubuntu CD 開機 (現在已沒有 "live CD" 的名稱了, Ubuntu 安裝光碟本身就可當 "live CD"), 使用 gparted 調整硬碟大小&lt;/li&gt;
&lt;li&gt; 重開 guest OS, 可用 &lt;tt&gt;df -h&lt;/tt&gt; 確認實際大小確實有改變 (或用 &lt;tt&gt;sudo fdisk -l /dev/sda&lt;/tt&gt; 看 partition 資訊)。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;若不幸在砍 snapshot 前先用 &lt;a href="http://www.virtualbox.org/manual/ch08.html"&gt;VBoxManage&lt;/a&gt; 改了大小, 就無解了。目前只有看到一位仁兄用 Mac 的 Time Machine 還原到他做蠢事前的狀態, 解決這個砍不掉的問題 ... 。&lt;/p&gt;&lt;p&gt;我用另一台電腦的 VirtualBox 實驗以上步驟沒有問題, 確認問題出在我先改了 vdi 大小。&lt;br /&gt;
&lt;/p&gt;&lt;h4&gt;縮小 vdi&lt;/h4&gt;&lt;p&gt;我沒試過這個, 順便筆記一下&lt;/p&gt;&lt;ul&gt;&lt;li&gt; VBoxManage &lt;span class="escaped"&gt;-&lt;/span&gt;-resize 只支援擴大, 要縮小的話要換指令&lt;/li&gt;
&lt;li&gt; 先在 guest OS 針對要縮小的 partitoin, 用對應的工具重整 partition (zerofree on Linux)&lt;/li&gt;
&lt;li&gt; 使用指令 VboxManage modifyhd &lt;span class="escaped"&gt;-&lt;/span&gt;-compact /path/to/vdi&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;參考資料&lt;/h4&gt;&lt;p&gt;下次用這類 VM 的指令, 一定要熟讀手冊再下手啊 ... &lt;/p&gt;&lt;ul&gt;&lt;li&gt; &lt;a href="http://www.virtualbox.org/manual/ch08.html#vboxmanage-modifyvdi"&gt;《VBoxManage modifyhd》&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;a href="http://trivialproof.blogspot.com/2011/01/resizing-virtualbox-virtual-hard-disk.html"&gt;《Trivial Proof: Resizing a VirtualBox Virtual Hard Disk》&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;a href="https://forums.virtualbox.org/viewtopic.php?f=8&amp;amp;t=44510"&gt;《virtualbox.org: Can't delete top snapshot or expand HD size in VB 4.0.12》&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-4922212675976315988?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/ohLTJlum1Hk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/4922212675976315988/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/virtualbox-vdi-resize.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/4922212675976315988?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/4922212675976315988?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/ohLTJlum1Hk/virtualbox-vdi-resize.html" title="VirtualBox 改變 vdi 的大小" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/virtualbox-vdi-resize.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MEQ389fyp7ImA9WhRVGU0.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-4544045553874419591</id><published>2012-01-12T21:57:00.010+08:00</published><updated>2012-01-18T23:43:22.167+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-18T23:43:22.167+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tracing code" /><category scheme="http://www.blogger.com/atom/ns#" term="gdb" /><title>gdb 初步心得</title><content type="html">&lt;p&gt;對初學者來說, 最好有個針對常用情境的簡單指南, 之後有閒再看落落長的教學。這裡列一下最近常用的功能, 之後再慢慢更新。&lt;br /&gt;
&lt;/p&gt;&lt;h4&gt;前置動作&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; gcc/g++ 編譯時要加 -g&lt;/li&gt;
&lt;li&gt; 要觀察用到的函式庫, 則要裝 x-dbg 版 (如 libjpeg62 -&amp;gt; libjpeg62-dbg), gdb 會優先載入 debug 版函式庫。並且需要用 directory 載入原始碼, 見&lt;a href="http://fcamel-life.blogspot.com/2012/01/glibc.html"&gt;這裡&lt;/a&gt;的介紹。&lt;/li&gt;
&lt;li&gt; 可用 &lt;tt&gt;objdump --source FILE&lt;/tt&gt; 確認是否真的有編到 -g。有的話可以在輸出裡看到程式碼。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;雖說通篇我都寫 gdb, 但是 &lt;a href="http://cgdb.sourceforge.net/"&gt;cgdb&lt;/a&gt; 好用許多, 推薦使用。聽 &lt;a href="https://plus.google.com/102249536116095884743/posts"&gt;command&lt;/a&gt; 說 vimgdb 更好用, 不過要 patch vim 後才能用, 就 ... 先備忘吧。&lt;br /&gt;
&lt;/p&gt;&lt;h4&gt;執行方式&lt;/h4&gt;&lt;p&gt;從頭執行&lt;/p&gt;&lt;ul&gt;&lt;li&gt; bash&amp;gt; gdb &lt;span class="escaped"&gt;-&lt;/span&gt;-args PROGRAM PROGRAM-ARG1 ...&lt;/li&gt;
&lt;li&gt; gdb&amp;gt; start  # 進入 main 後停下來&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;檢查掛點原因 (參考&lt;a href="http://fcamel-life.blogspot.com/2011/12/core-dump-cgdb.html"&gt;這篇&lt;/a&gt;的設定)&lt;/p&gt;&lt;ul&gt;&lt;li&gt; bash&amp;gt; gdb PROGRAM CORE&lt;/li&gt;
&lt;li&gt; gdb&amp;gt; bt 20  # 看掛掉的 call stack 最底層 20 個 function call&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;通常載入 PROGRAM 讀 debug symbol 較花時間, 我習慣用 gdb PROGRAM 進 gdb 後, 再用 core CORE 指令看不同的 core dump。&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;若希望從頭重來, 有設好中斷點就用 r, 沒有則繼續用 start, 不用離開 gdb, 可簡省載入  PROG 的時間。&lt;br /&gt;
&lt;/p&gt;&lt;h4&gt;設中斷點&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; b LOC # 設中斷點, 或用 cgdb 直接在程式視窗按空白鍵&lt;/li&gt;
&lt;li&gt; i b # 列出全部中斷點&lt;/li&gt;
&lt;li&gt; d NUM # 移除編號 NUM 的中斷點&lt;/li&gt;
&lt;li&gt; save breakpoints FILE # 存下目前設的中斷點到檔案 FILE&lt;/li&gt;
&lt;li&gt; so FILE # 載入之前設的中斷點&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;關於 LOC: 見&lt;a href="http://sourceware.org/gdb/current/onlinedocs/gdb/Specify-Location.html"&gt;《Specify Location - Debugging with GDB》&lt;/a&gt;。我比較常用 filename:linenum、linenum 或 +N。因為不易對到 C++ 的函式名稱, 所以我都用行號。&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;我還沒有適當情境試 &lt;a href="http://sourceware.org/gdb/current/onlinedocs/gdb/Conditions.html#Conditions"&gt;conditional break&lt;/a&gt;, 但應該很有用, 備忘。&lt;br /&gt;
&lt;/p&gt;&lt;h4&gt;移動&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; n # 跳下行&lt;/li&gt;
&lt;li&gt; s # 若有函式, 跳進去; 反之則同 n&lt;/li&gt;
&lt;li&gt; until LOC # 執行到 LOC 再停, 我以前都傻傻的先設中斷再按 c ...&lt;/li&gt;
&lt;li&gt; c # 執行到下個中斷點&lt;/li&gt;
&lt;li&gt; 跳過下一行程式 (&lt;a href="http://www.toptip.ca/2010/06/gdb-skip-instructions-or-lines-while.html"&gt;ref.&lt;/a&gt;), 記得要設中斷點才行&lt;br /&gt;
&lt;ul&gt;&lt;li&gt; b +1&lt;/li&gt;
&lt;li&gt; j +1&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt; ps. 按 Enter 可重覆上個指令, 在移動指令時和切 stack frame (後述) 時特別好用&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;在 call stack 之間移動&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; up  # 往上移一個&lt;/li&gt;
&lt;li&gt; do  # 往下移一個&lt;/li&gt;
&lt;li&gt; f N # 跳到 stack frame N&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;觀察值&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; p EXPRESSION  # 印出 EXPRESSION 的值, 可是變數、函式等&lt;/li&gt;
&lt;li&gt; 印出 smart pointer 的值 (&lt;a href="http://www.nsnam.org/wiki/index.php/HOWTO_debug_smart_pointer"&gt;ref.&lt;/a&gt;): 得先取出裡面的 pointer 再取出它的 member function / field&lt;/li&gt;
&lt;li&gt; whatis VAR # 看型別&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;其它&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; set var X = ... # 執行期間改變變數 X, 以在執行期驗證小修改是否有效, 簡省編譯時間&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;參考資料&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; &lt;a href="http://sourceware.org/gdb/current/onlinedocs/gdb/"&gt;《Debugging with GDB》&lt;/a&gt;: 待用一陣子後再來掃一遍, 挑出有用的東西&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-4544045553874419591?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/n2V0iL3LddE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/4544045553874419591/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/gdb.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/4544045553874419591?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/4544045553874419591?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/n2V0iL3LddE/gdb.html" title="gdb 初步心得" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/gdb.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcBRnY7fyp7ImA9WhRUEk8.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-4955636459658394209</id><published>2012-01-09T23:44:00.004+08:00</published><updated>2012-01-22T16:47:37.807+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-22T16:47:37.807+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="C" /><category scheme="http://www.blogger.com/atom/ns#" term="tracing code" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="gdb" /><title>追踪 glibc 裡的程式</title><content type="html">&lt;p&gt;這篇是一堆試誤心得的中間記錄, 使用的版本是 Ubuntu 11.04。 &lt;/p&gt;&lt;h4&gt;失敗的作法&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; 在 link 時, 用 -L/usr/lib/debug/lib/x86_64-linux-gnu/ 改變 link 到的 libc.so, 但沒有效果。用 &lt;tt&gt;strace -e open&lt;/tt&gt; 觀察 gcc 做的事, 發現是因為 /usr/lib/debug/lib/x86_64-linux-gnu/ 下沒有 libc.so, 而是 libc-2.13.so。之前沒學清楚 -L 和 -l 的細節, 耍笨。&lt;/li&gt;
&lt;li&gt; 由 &lt;tt&gt;man ld.so&lt;/tt&gt; 得知可用 LD_LIBRARY_PATH 或 LD_PRELOAD 在執行期換掉 libc.so, 但是也沒有效果。用 LD_PRELOAD 換成 debug 版 libc.so 時, 跑 gdb 會 segmentation fault&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;成功的作法&lt;/h4&gt;&lt;p&gt;前置作業&lt;/p&gt;&lt;ul&gt;&lt;li&gt; &lt;tt&gt;$ sudo aptitude install libc6-dbg&lt;/tt&gt; # 取得有 debug symbol 的 libc.so&lt;/li&gt;
&lt;li&gt; &lt;tt&gt;$ apt-get source libc6-dev&lt;/tt&gt;  # 取得原始碼目錄 eglibc-2.13&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;執行&lt;/p&gt;&lt;ol&gt;&lt;li&gt; $ gcc myprog.c -g -o myprog&lt;/li&gt;
&lt;li&gt; $ gdb myprog&lt;/li&gt;
&lt;li&gt; $ directory /path/to/eglibc-2.13/stdio-common/&lt;/li&gt;
&lt;li&gt; $ start  # 跑到 main 就停下來&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;然後 gdb 會神奇地去找含 debug symbol 的 libc, 後面就可以用 step 進入 glibc 的函式。不知這個行為寫在那裡, 或許可以從 gdb 原始碼找出來吧。&lt;/p&gt;&lt;p&gt;若有進入但說找不到原始碼, 表示沒有告知 gdb 正確的原始碼位置, 到 eglibc-2.13 下找一找, 再回來用 directory 設位置。 &lt;/p&gt;&lt;p&gt;另外在用到 sqrt()、log() 時也是如此, 照一樣的編法 &lt;tt&gt;gcc myprog.c -g -lm -o myprog&lt;/tt&gt;, 然後在 start 後, gdb 會去找 debug 版的 libm.so。不過要記得多執行 &lt;tt&gt;directory /path/to/eglibc-2.13/math&lt;/tt&gt; 載入 math 的原始碼, gdb 才能列出原本的程式。用 ldd 觀察 myprog 也驗證原本的執行檔將 libc 和 libm 連到沒有 debug symbol 的版本。 &lt;/p&gt;&lt;p&gt;另外試了直接和 debug 版的 libc.so 或 libm.so 編在一起 (&lt;tt&gt;gcc myprog.c -g /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.13.so&lt;/tt&gt;), 但是一跑就會 segmentation fault。&lt;/p&gt;&lt;p&gt;另外有些函式好像是用組語寫的, 看不懂它們的行為, step into sqrt 沒有效果。 &lt;/p&gt;&lt;h4&gt;結論&lt;/h4&gt;&lt;p&gt;要觀察 glibc 的行為, 要做以下的事:&lt;/p&gt;&lt;ul&gt;&lt;li&gt; 裝 libc6-dbg, 取得含 debug symbol 的 shared lib&lt;/li&gt;
&lt;li&gt; 用 apt-get source libc6-dev 取得原始碼。由於 glibc 裡有多個 shared lib, 要先 grep 找看看想觀察的程式放在那個目錄下, 跑 gdb 時再用 directory 載入該目錄, 相對路徑才會對。&lt;/li&gt;
&lt;/ul&gt;&lt;h4&gt;2012-01-10 更新: 補充觀察 gdb 找 debug lib 的行為 &lt;/h4&gt;&lt;p&gt;一樣可以用老招 &lt;tt&gt;strace -e open&lt;/tt&gt; 跑 gdb 看出背後發生的事, 以下是沒有裝 libc6-dbg 跑出的訊息: &lt;pre class="prettyprint"&gt;$ strace -e open -o gdb.trace gdb myprog
&lt;/pre&gt;然後執行 &lt;tt&gt;tail -f gdb.trace | grep libc&lt;/tt&gt; 觀察行為。&lt;/p&gt;&lt;p&gt;以下是執行 start 以前的訊息: &lt;pre class="brush: c"&gt;open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY) = 3
open("/lib/libcrypto.so.0.9.8", O_RDONLY) = 3
open("/usr/share/locale/en_US.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_US.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_US.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;以下是執行 start 以後的訊息: &lt;pre class="brush: c"&gt;open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY) = 6
open("/lib/x86_64-linux-gnu/libc-2.13.so", O_RDONLY) = 7
open("/lib/x86_64-linux-gnu/.debug/libc-2.13.so", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/debug//lib/x86_64-linux-gnu/libc-2.13.so", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/debug/lib/x86_64-linux-gnu/libc-2.13.so", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc-2.13.so-gdb.py", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/debug/lib/x86_64-linux-gnu/libc-2.13.so-gdb.py", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/gdb/auto-load/lib/x86_64-linux-gnu/libc-2.13.so-gdb.py", O_RDONLY) = -1 ENOENT (No such file or directory)
&lt;/pre&gt;可以看出 gdb 不論如何, 都會試著載入 debug 版的函式庫, 來執行目標程式。找不到的時候, 自然就是用沒有 debug symbol 的函式庫。 &lt;/p&gt;
&lt;p&gt;
&lt;b&gt;2012-01-22 更新&lt;/b&gt;
&lt;/p&gt;
在&lt;a href="http://fcamel-life.blogspot.com/2012/01/gdb-debug-symbol.html"&gt;《gdb 如何找到 debug symbol》&lt;/a&gt;有進一步說明。
&lt;p&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-4955636459658394209?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/niWTUyH7H1s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/4955636459658394209/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/glibc.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/4955636459658394209?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/4955636459658394209?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/niWTUyH7H1s/glibc.html" title="追踪 glibc 裡的程式" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/glibc.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cGR3c4cCp7ImA9WhRWGEo.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-6233480177012859657</id><published>2012-01-07T01:28:00.001+08:00</published><updated>2012-01-07T01:30:26.938+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-07T01:30:26.938+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="blog" /><title>寫 blog 的目的</title><content type="html">&lt;p&gt;一開始寫這個 blog, 是為了備忘以及分享一些小心得。一兩個月才寫個一篇&lt;a href="http://fcamel-fc.blogspot.com"&gt;主站&lt;/a&gt;的文章, 很多小東西就這樣流失了, 有點可惜。
&lt;/p&gt;&lt;p&gt;
昨天和 &lt;a href="http://scottt.tw"&gt;Scott&lt;/a&gt; 在&lt;a href="https://plus.google.com/111353793049965752735/posts/U1Bg7zybEzo"&gt;這裡&lt;/a&gt;聊到寫這 blog 的目的, 順手貼過來:&lt;/p&gt;&lt;blockquote&gt;我寫 blog 除備忘外, 主要是想記錄「思考解決問題」的路徑。比方說「了解背後運作原理」、「用什麼工具觀察出背後運作機制」、「從什麼角度思考可能的原因並做驗證」。有時是缺少背景知識、有時是缺少關鍵工具, 以致於無法完成一個看似困難實則簡單的事。&lt;br /&gt;
&lt;br /&gt;
以前很想知道某些問題怎麼解, 但是太拉里拉雜, 很難問, 問了別人, 別人只會說答案, 也不太知道怎麼說明背後的思路, 已成為他們的習慣了。
&lt;/blockquote&gt;&lt;p&gt;
沒想到這樣隨手&lt;a href="http://fcamel-life.blogspot.com/2010/01/blog.html"&gt;寫了兩年&lt;/a&gt;, 意外地寫出新的心得, 才發覺我想寫的東西為何。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-6233480177012859657?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/UTS1TU1bEeE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/6233480177012859657/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/blog.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/6233480177012859657?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/6233480177012859657?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/UTS1TU1bEeE/blog.html" title="寫 blog 的目的" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/blog.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4GR3w9eip7ImA9WhRWF0o.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-8898908195038858488</id><published>2012-01-05T23:38:00.001+08:00</published><updated>2012-01-05T23:38:46.262+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-05T23:38:46.262+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><title>一秒設好慣用的環境</title><content type="html">&lt;blockquote&gt;sudo apt-get install git-core &amp;amp;&amp;amp; git clone git://github.com/fcamel/configs.git &amp;amp;&amp;amp; cd configs &amp;amp;&amp;amp; ./install.sh
&lt;/blockquote&gt;&lt;p&gt;
不是想發一行文, 而是想強調 open repository 真方便。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-8898908195038858488?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/1FJNxWRmCVM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/8898908195038858488/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/blog-post_05.html#comment-form" title="3 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/8898908195038858488?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/8898908195038858488?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/1FJNxWRmCVM/blog-post_05.html" title="一秒設好慣用的環境" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/blog-post_05.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU8FSH09eip7ImA9WhRWF0o.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-3249016241528471847</id><published>2012-01-05T23:36:00.001+08:00</published><updated>2012-01-05T23:36:59.362+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-05T23:36:59.362+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><title>熟悉系統工具好處多多</title><content type="html">&lt;p&gt;記一下以前很困擾, 現在秒殺的小事。
&lt;/p&gt;&lt;p&gt;
更新&lt;a href="http://fcamel-life.blogspot.com/2011/12/undefined-symbol-reference.html"&gt;這篇&lt;/a&gt;的時候, 忘了函式庫用的 man page 裝在那個 package。以前就會想辦法 google, 運氣好一下會找到, 運氣不好會多找一會兒。
&lt;/p&gt;&lt;p&gt;
這回我想到新作法:&lt;/p&gt;&lt;pre class="prettyprint"&gt;$ strace -e open man 3 printf &amp;gt; /dev/null
# 發現是讀 /usr/share/man/man3/printf.3.gz

$ dpkg --search /usr/share/man/man3/printf.3.gz
# 找到套件名稱 manpages-dev

$ aptitude show manpages-dev
# 確認描述符合, 收工
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-3249016241528471847?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/jWBzpV_VsZs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/3249016241528471847/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/01/blog-post.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/3249016241528471847?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/3249016241528471847?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/jWBzpV_VsZs/blog-post.html" title="熟悉系統工具好處多多" /><author><name>fcamel</name><uri>http://www.blogger.com/profile/04792244455260595133</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://fcamel-life.blogspot.com/2012/01/blog-post.html</feedburner:origLink></entry></feed>

