<?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;DkIAQnY7cSp7ImA9WhVTEUU.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977</id><updated>2012-02-25T23:42:23.809+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="vcs" /><category term="cpython" /><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="wsgi" /><category term="browser" /><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="tlpi" /><category term="blog" /><category term="tip" /><category term="apache2" /><category term="pdb" /><category term="functional programming" /><category term="gtk+" /><category term="mobile web" /><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>312</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;DkIAQnY6fyp7ImA9WhVTEUU.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-8207849880181281795</id><published>2012-02-25T23:42:00.001+08:00</published><updated>2012-02-25T23:42:23.817+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-25T23:42:23.817+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gtk+" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><title>Gtk+ 入門</title><content type="html">&lt;p&gt;之前看過 &lt;a href="http://blog.linux.org.tw/~jserv/"&gt;jserv&lt;/a&gt; 的 &lt;a href="http://people.debian.org.tw/~jserv/gtk-training/"&gt;Gtk+ 程式設計初體驗&lt;/a&gt;, 玩了一下範例程式, 對 Gtk+ 的 OO 表達方式和處理事件的架構有概念。再來看&lt;a href="http://caterpillar.onlyfun.net/Gossip/GTKGossip/GTKGossip.html"&gt;《GTK 學習筆記》&lt;/a&gt;的前幾篇, 試一下範例, 知道怎麼重頭編寫。後來看到&lt;a href="http://caterpillar.onlyfun.net/Gossip/GTKGossip/GtkReference.html"&gt;其中一篇提到 gtk-demo&lt;/a&gt;, 接下來就簡單許多。看一下範例, 挑自己要的出來改, 配合官方文件查幾個 API 用法, 就搞定要做的小東西了, 整個過程還算順利。
&lt;/p&gt;
&lt;p&gt;
備忘:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; 安裝: $ sudo apt-get install libgtk2.0-dev gtk2.0-examples&lt;/li&gt;
&lt;li&gt; 編譯: $ gcc prog.c -o prog `pkg-config &lt;span class="escaped"&gt;-&lt;/span&gt;-cflags &lt;span class="escaped"&gt;-&lt;/span&gt;-libs gtk+-2.0`&lt;/li&gt;
&lt;li&gt; 查範例程式: $ gtk-demo ( 點左側選單兩下會執行程式, 右側有程式碼)。若有需要, 也可用 apt-get source gtk-demo 取得原始碼, 更方便。&lt;/li&gt;
&lt;li&gt; &lt;a href="http://scottt.tw/"&gt;Scott&lt;/a&gt; 提到&lt;a href="https://github.com/blog/306-parasite-firebug-for-gtk"&gt;《Parasite: Firebug for GTK+》&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-8207849880181281795?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/2uFWNq0FLF0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/8207849880181281795/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/gtk.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/8207849880181281795?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/8207849880181281795?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/2uFWNq0FLF0/gtk.html" title="Gtk+ 入門" /><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/gtk.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMBQ3o9fCp7ImA9WhRaGE4.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-1442389939389949462</id><published>2012-02-21T22:06:00.001+08:00</published><updated>2012-02-21T22:10:52.464+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-21T22:10:52.464+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mobile web" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><category scheme="http://www.blogger.com/atom/ns#" term="browser" /><title>設定 viewport 的寬度為 device-width 以支援各種 mobile browser</title><content type="html">&lt;p&gt;好歹也是花了一些時間看的東西, 備忘一下。
&lt;/p&gt;&lt;p&gt;
&lt;a href="http://www.quirksmode.org/blog/archives/2010/04/the_orientation.html"&gt;《The orientation media query》&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; orientation (landscape or portrait) 不是重點, 重點是螢幕寬度到底是幾 pixel&lt;/li&gt;
&lt;li&gt; 結論: 用 device-width&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
&lt;a href="http://webdev-il.blogspot.com/2011/04/mobile-web-design-viewport-size-vs.html"&gt;《Mobile web design viewport size vs screen resolution - viewport META tag》&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; 詳述 viewport 為何, 覺得重述一次意思會不對, 還是請大家看原文吧&lt;/li&gt;
&lt;li&gt; mobile device 的 viewport 大小不見得和 screen 大小一樣 (桌機則是一致)&lt;/li&gt;
&lt;li&gt; 有些 mobile browser 藉由讓 html 畫在較寬的 viewport 上, 再將它縮放到符合螢幕寬度, 藉此顯示整個網頁的大概樣子 (有時稱為 overview mode)。也就是說, 網頁會依 viewport 的寬度來 render, 而不是 screen 寬度。對桌機來說兩者寬度一樣, 所以不會混淆&lt;/li&gt;
&lt;li&gt; 各家 mobile browser 預設的 viewport 大小不同, 造成寫網頁的人的困擾&lt;/li&gt;
&lt;li&gt; 可用 &lt;tt&gt;&amp;lt;meta name="viewport"content="width=1100"/&amp;gt;&lt;/tt&gt; 改變預設 viewport 寬度&lt;/li&gt;
&lt;li&gt; 可用 &lt;tt&gt;&amp;lt;meta name="viewport"content="width=device-width"/&amp;gt;&lt;/tt&gt; 將 viewport 設為 device 寬度&lt;/li&gt;
&lt;li&gt; 舊手機不支援上述語法, 該連結有提到其它備案&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
&lt;a href="http://tech.bluesmoon.info/2011/01/device-width-and-how-not-to-hate-your.html"&gt;《device-width and how not to hate your users》&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; 可用 CSS 3 新語法 &lt;a href="http://waterlily-lsl.com/modules/article/view.article.php/236/c2"&gt;media-query&lt;/a&gt; 針對螢幕寬度決定使用的 CSS rules。對於桌機不同的螢幕寬度來說, 這是個好解法, 不用擔心使用者用 24" 寬螢幕還是 19" 一般螢幕。&lt;/li&gt;
&lt;li&gt; mobile device 另有 viewport 大小不同 screen 大小的特色, 所以使用 &lt;a href="http://waterlily-lsl.com/modules/article/view.article.php/236/c2"&gt;media-query&lt;/a&gt; 的話, 要再配合限制 viewport 寬度為 device-width, 才可確保用對 CSS rules&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-1442389939389949462?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/xAibhkUHWQM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/1442389939389949462/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/viewport-device-width-mobile-browser.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/1442389939389949462?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/1442389939389949462?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/xAibhkUHWQM/viewport-device-width-mobile-browser.html" title="設定 viewport 的寬度為 device-width 以支援各種 mobile browser" /><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/viewport-device-width-mobile-browser.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0AMQn49eip7ImA9WhRaFko.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-5312105735297738130</id><published>2012-02-20T02:23:00.001+08:00</published><updated>2012-02-20T02:23:03.062+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-20T02:23:03.062+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="apache2" /><title>在 apache2 內顯示 symbolic link</title><content type="html">&lt;p&gt;要滿足以下三者才可以顯示 symbolic link&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; &amp;lt;Directory /path/to/dir/&amp;gt; 內要有 SymLinksIfOwnerMatch 外 (module userdir 預設就有設)&lt;/li&gt;
&lt;li&gt; soft link 的擁有者要和連到的檔案是同一人, 這樣才安全, 也可避免 /、/home 之類的目錄被使用者亂連出去&lt;/li&gt;
&lt;li&gt; soft link 目錄的整條路徑都要能讓 www daemon 存取, 若有個目錄是 750 之類的就不行&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
有錯時可看 /var/log/apache2/error.log, 若出現「Symbolic link not allowed or link target not accessible」, 大概上述其中一者沒設對。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-5312105735297738130?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/MtaQmEq3KAw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/5312105735297738130/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/apache2-symbolic-link.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/5312105735297738130?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/5312105735297738130?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/MtaQmEq3KAw/apache2-symbolic-link.html" title="在 apache2 內顯示 symbolic link" /><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/apache2-symbolic-link.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkENSX4-cCp7ImA9WhRaFUU.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-7864384352299123891</id><published>2012-02-17T23:32:00.001+08:00</published><updated>2012-02-19T02:11:38.058+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-19T02:11:38.058+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mercurial" /><category scheme="http://www.blogger.com/atom/ns#" term="git" /><title>git staging area 的價值</title><content type="html">&lt;p&gt;之前用 &lt;a href="http://mercurial.selenic.com/"&gt;mercurial&lt;/a&gt; 時一直很納悶, 為啥 git 的愛好者都如此&lt;a href="http://zh-tw.whygitisbetterthanx.com/#the-staging-area"&gt;推崇 staging area&lt;/a&gt;, 但我怎麼看就是看不懂, &lt;a href="http://mercurial.selenic.com/"&gt;mercurial&lt;/a&gt; 沒這東西用起來也沒特別困擾, 反而要和別人解釋 staging area 時還會一直說不清楚 (畢竟自己也沒搞懂它的價值 ...)。
&lt;/p&gt;&lt;p&gt;
看到&lt;a href="http://tomayko.com/writings/the-thing-about-git"&gt;《The Thing About Git》&lt;/a&gt;總算解開我多年來 (遠目...) 的疑惑, 要配合「只想 commit 檔案內部份修改」的情境才會突顯它的價值。
&lt;/p&gt;&lt;p&gt;
該文有範例說明, 有時我們會同時改到不同東西, 好死不死, 兩個東西的修改在同一個檔案裡。這時有幾個選擇:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; 就給它 commit 下去, 在 commit log 裡順帶一提多 commit 的東西&lt;/li&gt;
&lt;li&gt; 兩個功能一起 commit 進去, commit log 寫長一點, commit 內容比較雜&lt;/li&gt;
&lt;li&gt; 回去原本的檔案「取消」不想 commit 的修改, 再回來 commit&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
身為一名良好市民, 大部份時候我是選第三個方案, 但是做得很辛苦。&lt;a href="http://mercurial.selenic.com/"&gt;mercurial&lt;/a&gt; 好像有 extension 可以只 commit 部份內容 (hunk-by-hunk commit), 不過我懶得找。我後來的作法是:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; 用 &lt;a href="https://bitbucket.org/tortoisehg/thg/wiki/Home"&gt;thg&lt;/a&gt; 的 commit&lt;/li&gt;
&lt;li&gt; 在 commit 視窗裡針對目標檔案按 "open shelve tool"&lt;/li&gt;
&lt;li&gt; hunk-by-hunk 地 shelve 不想 commit 的內容&lt;/li&gt;
&lt;li&gt; commit&lt;/li&gt;
&lt;li&gt; unshelve all&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
還過得去就是了。
&lt;/p&gt;&lt;p&gt;
但是有 staging area 的話, 有不同的選擇。先 hunk-by-hunk 地將準備 commit 的內容加到 staging area (git add &lt;span class="escaped"&gt;-&lt;/span&gt;-patch), 接下來比對 repository 和 staging area 確認要 commit 的內容, 同時還可回頭比對 staging area 和 working directory 確定沒有漏東西。和 shelve 的作法相比, 比較直覺一些。&lt;/p&gt;
&lt;h4&gt;2012-02-18 Update&lt;/h4&gt;
&lt;p&gt;
看到&lt;a href="https://plus.google.com/115189691004764071174/posts"&gt;邱&lt;/a&gt;提到&lt;a href="http://stevelosh.com/blog/2010/08/a-git-users-guide-to-mercurial-queues/"&gt;《A Git User&amp;apos;s Guide to Mercurial Queues》&lt;/a&gt; (&lt;a href="https://plus.google.com/111353793049965752735/posts/8ZPnqVQLwph"&gt;ref.&lt;/a&gt;), 裡面有說明用 MQ 做到「多重 staring area」的效果, 看起來挺實用的。更新一個涉及多個模組的功能時, 個人偏向依各模組拆開 commit, 比較易讀。配合 MQ 可以更直覺地折解更新成多個 patch, 並保有隨時更新的彈性, 最後再一起 commit 成多個 changesets。
&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-7864384352299123891?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/Ne64q_aUM9M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/7864384352299123891/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/git-staging-area.html#comment-form" title="0 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/7864384352299123891?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/7864384352299123891?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/Ne64q_aUM9M/git-staging-area.html" title="git staging area 的價值" /><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/git-staging-area.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08BQn44cSp7ImA9WhRaFEw.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-4890420207213602067</id><published>2012-02-16T21:39:00.001+08:00</published><updated>2012-02-17T01:04:13.039+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-17T01:04:13.039+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tracing code" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>配合 c++filt 讀程式</title><content type="html">&lt;p&gt;在用 gdb 追蹤程式前, 得先找到幾個關鍵中斷點, 才能著手進行。若有機會想到不錯的關鍵字的話, 除了用 grep 之類的工具大海撈針外, 有時從 binary 裡下手, 效果也不錯, 有機會減少搜尋範圍。畢竟程式碼中難免有一些平台或參數相關的設定, 讓部份程式碼根本沒有編進 binary。從 binary 回頭找, 可免除這層顧慮。
&lt;/p&gt;&lt;p&gt;
我目前試過的作法有兩種&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; &lt;tt&gt;string PROG | grep KEYWORD&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt; &lt;tt&gt;nm PROG | grep KEYWORD | awk '{print $NF}' | xargs c++filt&lt;/tt&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
第一個作法是配合程式輸出的訊息來找程式。
&lt;/p&gt;&lt;p&gt;
第二個作法則是從 binary 取出可能有關的的 symbol, 再用 c++filt demangle symbol, 找出它的 namespace、signature 等資訊。需要注意的是, 有可能因編譯器最佳化 (如 inline), 實際上沒有呼叫到函式。經 &lt;a href="http://www.plurk.com/qrtt1"&gt;qrtt1&lt;/a&gt; 提醒, 保險起見, 可在編譯時加上 &lt;tt&gt;-O0&lt;/tt&gt; 確保行為符合預期。
&lt;/p&gt;&lt;p&gt;
題外話, C 的 function name 反而無法 demangle 找出 signature(應該沒理解錯吧)。不過相對於 C++ 的複雜度, 讀 C 的程式時, 也許沒那麼需要吧。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4982215793068879977-4890420207213602067?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/6KOG88KZVnE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/4890420207213602067/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/cfilt.html#comment-form" title="3 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/4890420207213602067?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/4890420207213602067?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/6KOG88KZVnE/cfilt.html" title="配合 c++filt 讀程式" /><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/02/cfilt.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEEAR3s-eSp7ImA9WhRaEk4.&quot;"><id>tag:blogger.com,1999:blog-4982215793068879977.post-7574949259445359605</id><published>2012-02-14T22:35:00.001+08:00</published><updated>2012-02-14T23:17:26.551+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-14T23:17:26.551+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tlpi" /><category scheme="http://www.blogger.com/atom/ns#" term="linux programming" /><title>Linux process priorities and scheduling 心得</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;scheduling policy&lt;/h4&gt;&lt;p&gt;POSIX 規定了幾種 scheduling policy, 它們的優先權如下:&lt;/p&gt;&lt;pre class="prettyprint"&gt;SCHED_FIFO = SCHED_RR &amp;gt; SCHED_OTHER ~ SCHED_BATCH &amp;gt; SCHED_IDLE
&lt;/pre&gt;&lt;p&gt;
舉例來說: &lt;tt&gt;SCHED_FIFO&lt;/tt&gt; (99) &amp;gt; &lt;tt&gt;SCHED_FIFO&lt;/tt&gt; (1) &amp;gt; &lt;tt&gt;SCHED_OTHER&lt;/tt&gt; -20 (0) &amp;gt; &lt;tt&gt;SCHED_OTHER&lt;/tt&gt; 19 (0) &amp;gt; &lt;tt&gt;SCHED_IDLE&lt;/tt&gt; (0)
&lt;/p&gt;&lt;p&gt;
括號裡的數字是 process 的 static priority; -20 和 19 是 nice value, 見後文說明。
&lt;/p&gt;&lt;p&gt;
各 policy 的效果為:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; 所有 policy 都是 preemptive, 也就是&lt;strong&gt;高優先權 process 想執行的時候, 會搶走執行中低優先權 process 的 CPU&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt; &lt;tt&gt;SCHED_FIFO&lt;/tt&gt; 和 &lt;tt&gt;SCHED_RR&lt;/tt&gt; 的 static priority 範圍必須落在 1 &lt;span class="escaped"&gt;~&lt;/span&gt; 99, 剩下三個 (&lt;tt&gt;SCHED_OTHER&lt;/tt&gt;、...) 只能設 priority = 0。達到的效果是 &lt;strong&gt;&lt;tt&gt;SCHED_FIFO&lt;/tt&gt; 和 &lt;tt&gt;SCHED_RR&lt;/tt&gt; 永遠會比後幾種 policy 先執行&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt; &lt;tt&gt;SCHED_FIFO&lt;/tt&gt; 和 &lt;tt&gt;SCHED_RR&lt;/tt&gt; 是 real-time scheduling, 不過是 linux kernel 盡可能做到即時, 真的要做 real-time system (如汽車), 得用改過的 linux kernel&lt;/li&gt;
&lt;li&gt; &lt;tt&gt;SCHED_OTHER&lt;/tt&gt; 和 &lt;tt&gt;SCHED_BATCH&lt;/tt&gt; 的 static priority 都為 0, 所以會另外參考 dynamic priority 來決定順序, 這個值主要取決於 nice value (用 nice/renice 設), &lt;strong&gt;只是參考值, 較低的 nice value 不會永遠表示較高的 dynamic priority&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt; 沒做設定的話, 預設 policy 是 &lt;tt&gt;SCHED_OTHER&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt; &lt;tt&gt;SCHED_BATCH&lt;/tt&gt; 用在不需互動的程式, 會減少 wake-up 的頻率&lt;/li&gt;
&lt;li&gt; nice value 對 &lt;tt&gt;SCHED_IDLE&lt;/tt&gt; 無效, 這個 policy 會保證有最低優先權&lt;/li&gt;
&lt;li&gt; 以上所有效果都會繼承到 sub-process&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
所以, 若用 SHCED_OTHER 配上 nice value, 可達到優先效果, 也不會有 process 餓死, 都搶不到 CPU。若用了 &lt;tt&gt;SCHED_FIFO&lt;/tt&gt; 和 &lt;tt&gt;SCHED_RR&lt;/tt&gt;, 要小心搶光 CPU 資源的情況。用 &lt;tt&gt;SCHED_OTHER&lt;/tt&gt; 配上負值 nice value 也要小心。
&lt;/p&gt;&lt;h4&gt;保險機制&lt;/h4&gt;&lt;p&gt;做為保險, 可用 setrlimit(RLIMIT_CPU) 限制執行時間, 超過 soft limit 會收到 SIGXCPU, 預設會掛掉該 process。若沒掛的話, 之後每秒鐘會收到一次 SIGXCPU, 直到超過 hard limit 收到 SIGKILL, 保證掛掉該 process。在這之間就有操作空間來調整自己的優先權。
&lt;/p&gt;&lt;p&gt;
或用 setrlimit(RLIMIT_RTTIME), 來限制在 real-time scheduling policy 下最長執行的時間, 遇到 blocking system call 後會歸零, 可避免失控超時。超時後的行為和 setrlimit(RLIMIT_CPU) 相同。

setrlimit 也和設 scheduling 一樣, 會繼承到 sub-process。
&lt;/p&gt;&lt;h4&gt;Affinity&lt;/h4&gt;&lt;p&gt;Linux 另有特別的 system call &lt;strong&gt;可限制 process 只能跑在那些 CPU&lt;/strong&gt;, 在 man sched_setaffinity 的 CONFORMING TO 該節有註明這是 linux-specific 的功能。
&lt;/p&gt;&lt;p&gt;
透過 set affinity, 可以滿足一些特殊需求:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt; 一台 8 core 的 server, 跑 8 個 process 限制它們各自用同一個 core 來服務大量 client, 讓 context switch 的次數降到最低&lt;/li&gt;
&lt;li&gt; 限制某些類型的 process 只能用部份 CPU, 確保隨時有餘力服務其它 process。比方說留一個 CPU 不跑 real-time process, 至少失控時還能登入使用 shell 處理&lt;/li&gt;
&lt;li&gt; 若 multi-thread 的程式沒寫好容易掛, 限制它們只跑在一個 core, 也許比較不會當 (這是我看 stackoverflow 裡某位路人提到他的用法 ...)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
sched_setaffinity() 可以設在 process 也可設在 thread 上, 用的時候注意一下 man page 針對 pid 的說明。這個值也會繼承到 sub-process&lt;/p&gt;&lt;p&gt;另外, 經 &lt;a href="https://plus.google.com/115208016645517532827/posts"&gt;wens&lt;/a&gt; 提醒, 還有 pthread_setaffinity_np() 可用來設 thread 的 affinity。查了一下 man page, 它是基於 sched_setaffinity() 的實作。待比較熟 multi-thread、pthread 的事情後, 大概會比較清楚為什麼要多包一個 pthread_setaffinity_np() 吧。
&lt;/p&gt;
&lt;h4&gt;參考資料&lt;/h4&gt;&lt;ul&gt;&lt;li&gt; &lt;a href="http://man7.org/tlpi/"&gt;TLPI&lt;/a&gt; ch35&lt;/li&gt;
&lt;li&gt; man sched_setscheduler&lt;/li&gt;
&lt;li&gt; man sched_setaffinity&lt;/li&gt;
&lt;li&gt; man pthread_setaffinity_np&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-7574949259445359605?l=fcamel-life.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/fcamel/~4/T2f4CdCi2HI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fcamel-life.blogspot.com/feeds/7574949259445359605/comments/default" title="張貼意見" /><link rel="replies" type="text/html" href="http://fcamel-life.blogspot.com/2012/02/linux-process-priorities-and-scheduling.html#comment-form" title="2 個意見" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/7574949259445359605?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4982215793068879977/posts/default/7574949259445359605?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/fcamel/~3/T2f4CdCi2HI/linux-process-priorities-and-scheduling.html" title="Linux process priorities and scheduling 心得" /><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/02/linux-process-priorities-and-scheduling.html</feedburner:origLink></entry><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></feed>

