2011年12月18日 星期日

Turn your Linux computer into a wireless access point using hostapd


話說手持無線裝置越來越多,習慣晚上用我的android手機上網,不過有天竟然把AP帶回老家忘記帶回來,只好拿我的HP Compaq CQ45來充當AP了,網路上已經很多Turn your Linux computer into a wireless access point using hostapd這類的文章了,我就不多加闡述,只是單純的紀錄。
我的CQ45的網卡是Broadcom的Chip,用的Linux kernel是3.0.0,預設的wireless driver是去load wl.ko,產生的interface name是eth1,不過hostap好像不支援,也沒去深究他,索性把他換成舊的b43.ko,然後簡單設定一下hostapd.conf就執行hostapd了。

hostapd.conf
ssid=test
hw_mode=g
channel=1
interface=wlan1
#bridge=br1
driver=nl80211
ignore_broadcast_ssid=0
macaddr_acl=0
wmm_enabled=0

接著還要設定wireless的IP,不過我並沒有啟動DHCP server,Client端就用靜態IP吧。

接著還要讓我的NB具有route和NAT的功能,請執行
sudo iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
sudo sysctl -w sys.net.ipv4.conf.all.forwarding=1




2011年12月10日 星期六

send signal to user-space


某天有個需求是希望當kernel發生某事件時通知user-space的process,心裡想最快就是送signal,於是google一下,果然有人有類似的需求,signals handling in the kernel,於是改了一下把他放上來,值得一提的是,其實這樣並不被鼓勵的,而且原本的kill_proc_info並沒有被export出來,所以如果是module要使用的話,就必須把他export出來,EXPORT_SYMBOL(kill_proc_info)

#include <linux/module.h>
#include <linux/init.h>
#include <linux/moduleparam.h>

#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
// #include <linux/slab.h> /* kmalloc() */
#include <linux/errno.h>  /* error codes */
#include <linux/types.h>  /* size_t */
#include <linux/signal.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>

#define PROC_NAME "sig2pid"

/**
 * 送signal 到pid去
 */
static int send_sig_to_pid(int sig, pid_t pid)
{
    struct siginfo info;

    info.si_signo = sig;
    info.si_errno = 0;
    info.si_code = SI_USER; // sent by kill, sigsend, raise
    info.si_pid = get_current()->pid; // sender's pid
    info.si_uid = current_uid(); // sender's uid

    return kill_proc_info(sig, &info, pid);
}

/**
 * /proc/sig2pid的write ops
 */
static int
sig2pid_proc_write(struct file *file, const char __user * buffer,
                     unsigned long count, void *data)
{
    int sig, pid, ret;
    char line[count];
    ret = copy_from_user(line, buffer, count);

    if (ret) {
        return -EFAULT;
    }
    sscanf(line, "%d %d", &pid, &sig);
    printk("%s(#%d): pid(%d), sig(%d)\n",
            __func__, __LINE__, pid, sig);
    send_sig_to_pid(sig, (pid_t) pid);
    return count;
}

/**
 * 建立/proc/sig2pid
 */
static int create_proc_file(void)
{
    struct proc_dir_entry *p;
    p = create_proc_entry(PROC_NAME, S_IFREG | S_IWUGO, NULL);
    if (!p) {
        printk("%s(#%d): create proc entry failed\n", __func__, __LINE__);
        return -EFAULT;
    }
    p->write_proc = sig2pid_proc_write;
    return 0;
}

int sig2pid_init_module(void)
{
    return create_proc_file();
}

void sig2pid_exit_module(void)
{
    remove_proc_entry(PROC_NAME, NULL);
}

module_init(sig2pid_init_module);
module_exit(sig2pid_exit_module);


    參考資料:
  • http://old.nabble.com/signals-handling-in-the-kernel-to12032525.html#a12032525 , signals handling in the kernel.
  • http://kerneltrap.org/node/5800, how to send signal from kernel space to user space.

github: https://github.com/brook-kuo/Linux_Module/tree/master/process/send_sig_to_userspace


2011年11月27日 星期日

Allow Unix sockets to be treated like normal files.


某天忽然想要用echo/cat的方式直接對unix socket做存取,結果得到error,只好有請google大神,覓得此良方Allow Unix sockets to be treated like normal files,try了一下沒問題。



#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>

#define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)

int main(int argc, char *argv[])
{
    int srv_fd, cli_fd;
    socklen_t cli_len;
    struct sockaddr_un srv_addr, cli_addr;
    char buf[128] = "Brook: ";
    ssize_t len;

    unlink("server_socket");
    if ((srv_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        handle_error("socket");
    }

    srv_addr.sun_family = AF_UNIX;
    strcpy(srv_addr.sun_path, "/tmp/unix_sock");
    if (bind(srv_fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr)) < 0) {
        handle_error("bind");
    }

    if (listen(srv_fd, 1) < 0) {
         handle_error("listen");
    }

    while (1) {
        cli_fd = accept(srv_fd, (struct sockaddr *)&cli_addr, &cli_len);
        len = read(cli_fd, buf + 6, sizeof(buf) - 6);
        buf[6 + len] = 0;
        write(cli_fd, buf, strlen(buf));
        close(cli_fd);
    }
    return 0;
}

    參考資料:
  • http://lwn.net/Articles/415651/ , net/unix: Allow Unix sockets to be treated like normal files.


github:
https://github.com/brook-kuo/Linux_Module/tree/master/socket/unix_as_normal_file


2011年11月19日 星期六

socket programming in bash


關於Bash的Socket部份您可以在man page中看到這段描述:
/dev/tcp/host/port
        If host is a valid hostname or Internet address, and port is an integer
        port number or service name, bash attempts to open a TCP connection to
        the corresponding socket.

/dev/udp/host/port
        If host is a valid hostname or Internet address, and port is an integer
        port number or service name, bash attempts to open a UDP connection to 
        the corresponding socket.

用一個簡單的例子就會懂了



2011年11月13日 星期日

HTML5 canvas的初體驗


HTML5的新的element,canvas,可以在Browser上繪製圖表/圖片。使用時必須訂出繪製的範圍(width/height),接著就可以開始用JavaScript進行繪圖了。目前多數支援canvas的browser看來也都只有支援2D,未來應該會有3D的。
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Canvas/Simple shapes (rectangles)</title>
    </head>
<body>
    <canvas id="myCanvas" width="300" height="150">
    Fallback content, in case the browser does not support Canvas.
    </canvas>
    <script type="application/x-javascript">
        // Get a reference to the element.
        var elem = document.getElementById('myCanvas');

        // 判斷是否能取得context
        if (elem && elem.getContext) {
            // 你只能對每一個canvas做initialize一次(getContext).
            // context = canvas . getContext(contextId [, ... ])
            var context = elem.getContext('2d');
            if (context) {
                // context.fillRect(x, y, w, h)
                // 畫方形
                context.fillRect(0, 0, 150, 100);

                // context.clearRect(x, y, w, h)
                // 清方形
                context.clearRect(100,50, 50, 50);

                // context.strokeRect(x, y, w, h)
                // 畫框
                context.strokeRect(150,100, 50, 50);
            }
        }
    </script>
</body>
</html>



fillRect(x, y, w, h)使用fillStyle來決定顏色。
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Canvas/FillRect attribute</title>
    </head>
<body>
    <canvas id="myCanvas" width="300" height="150">
    Fallback content, in case the browser does not support Canvas.
    </canvas>
    <script type="application/x-javascript">
        // Get a reference to the element.
        var elem = document.getElementById('myCanvas');

        // 判斷是否能取得context
        if (elem && elem.getContext) {
            // 你只能對每一個canvas做initialize一次(getContext).
            // context = canvas . getContext(contextId [, ... ])
            var context = elem.getContext('2d');
            if (context) {
                context.fillStyle = 'pink';
                context.fillRect(0, 0, 50, 50);

                context.fillStyle = '#f00'; // red
                context.fillRect(50, 50, 50, 50);
                context.fillStyle = '#0f0'; // green
                context.fillRect(100, 100, 50, 50);
                context.fillStyle = '#00f'; // blue
                context.fillRect(150, 150, 50, 50);

                // RGBA(red, green, blue, alpha)
                // Alpha1是透明度
                context.fillStyle = 'RGBA(100, 100, 255, 0.2)';
                context.fillRect(50, 50, 150, 150);
            }
        }
    </script>
</body>
</html>



而strokeRect(x, y, w, h)則會使用strokeStyle(顏色), lineWidth(粗細), lineJoin(連接觸樣式),等屬性來決定,其實就是line style。
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Canvas/Line styles</title>
    </head>
<body>
    <canvas id="myCanvas" width="300" height="150">
    Fallback content, in case the browser does not support Canvas.
    </canvas>
    <script type="application/x-javascript">
        // Get a reference to the element.
        var elem = document.getElementById('myCanvas');

        // 判斷是否能取得context
        if (elem && elem.getContext) {
            // 你只能對每一個canvas做initialize一次(getContext).
            // context = canvas . getContext(contextId [, ... ])
            var context = elem.getContext('2d');
            if (context) {
                // The beginPath() starts a new path
                context.beginPath();
                // reset the path to (0, 0)
                context.moveTo(0,0);
                context.strokeStyle = '#f00';

                // lineWidth是線的大小
                context.lineWidth = 1;
                context.strokeRect(0, 0, 20, 20);
                context.lineWidth = 10;
                context.strokeRect(30, 30, 20, 20);

                // LineJoin是連接處(轉角)的樣式
                context.lineJoin = 'bevel';
                context.strokeRect(60, 60, 20, 20);

                context.lineJoin = 'round';
                context.strokeRect(90, 90, 20, 20);

                context.lineJoin = 'miter';
                context.strokeRect(120, 120, 20, 20);
            }
        }
    </script>
</body>
</html>



參考資料:
  1. http://dev.opera.com/articles/view/html-5-canvas-the-basics/
  2. http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html
  3. https://developer.mozilla.org/en/Canvas_tutorial/Using_images
  4. http://wiki.moztw.org/%E7%94%A8_Canvas_%E7%95%AB%E5%9C%96
  5. http://www.w3school.com.cn/htmldom/dom_obj_canvas.asp


source code:
https://github.com/brook-kuo/JavaScript/tree/master/html5/canvas



2011年11月6日 星期日

關於bridge中hard_header_len/needed_headroom的問題


我的interface在收送上本來沒有問題,但是當它和其他interface作bridge之後就發生crash了,後來才發現是head不夠大,於是參考這篇文章"关于bridge中hard_header_len值的问题",做了些修改,原因是因為我的device在預留head room時,是hard_header_len+needed_headroom。而且有些local generate的packet會使用LL_RESERVED_SPACE()這macro來保留head room,而LL_RESERVED_SPACE()也會使用到needed_headroom,所以最保險的作法就是同時設定bridge的hard_header_len和needed_headroom。
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -369,6 +369,10 @@ void br_features_recompute(struct net_bridge *br)
 {
        struct net_bridge_port *p;
        unsigned long features, mask;
+#if 1 // Brook.
+    unsigned short max_hard_header_len = ETH_HLEN;
+    unsigned short max_needed_headroom = 0;
+#endif

        features = mask = br->feature_mask;
        if (list_empty(&br->port_list))
@@ -379,8 +383,22 @@ void br_features_recompute(struct net_bridge *br)
        list_for_each_entry(p, &br->port_list, list) {
                features = netdev_increment_features(features,
                                                     p->dev->features, mask);
+#if 1 // Brook.
+        if (p->dev->hard_header_len > max_hard_header_len) {
+            max_hard_header_len = p->dev->hard_header_len;
+        }
+
+        if (p->dev->needed_headroom > max_needed_headroom) {
+            max_needed_headroom = p->dev->needed_headroom;
+        }
+#endif
        }

+#if 1 // Brook.
+    br->dev->hard_header_len = max_hard_header_len;
+    br->dev->needed_headroom = max_needed_headroom;
+#endif
+
 done:
        br->dev->features = netdev_fix_features(features, NULL);
 }

    參考資料:
  1. 关于bridge中hard_header_len值的问题
  2. struct net_device结构中添加了needed_headroom/needed_tailroom成员



利用gen_init_cpio建立initrd的script


利用gen_init_cpio建立initrd的script
#!/bin/bash
#kernel的目錄
KERN_DIR=/usr/src/linux-kvm
#gen_initramfs_list.sh產生的暫存檔
INITRAMFS_LIST=/tmp/gen_initramfs_list
#initramfs的來源目錄, 為傳入該script的第一個參數
INITRAMFS_DIR=$1
#initrd的目的檔名, 為傳入該script的第二個參數
INITRD=$2
#給INITRAMFS_DIR default值
: ${INITRAMFS_DIR:="/home/brook/projects/rootfs"}
#給INITRD default值, 
: ${INITRD:="/home/brook/initrd"}

if [ ! -d $INITRAMFS_DIR ]; then
    echo "usage: $0 <initramfs_dir> <output_file>"
    exit 1
fi

sh $KERN_DIR/scripts/gen_initramfs_list.sh -d $INITRAMFS_DIR > $INITRAMFS_LIST
$KERN_DIR/usr/gen_init_cpio $INITRAMFS_LIST > $INITRD



2011年10月22日 星期六

javascript(6.1) - event, onkerpress


onkeypress當鍵盤被按下時觸發,這個event算蠻常用的,尤其是想要限制使用者的輸入範圍時。 其範例如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head>   <title></title> </head> <body>   <script type="text/javascript">     function noNumbers(e)     {        var keynum        var keychar        var numcheck        if (window.event) { // IE          keynum = window.event.keyCode        } else if(e.which) { // Netscape/Firefox/Opera          keynum = e.which        }        alert(keynum)        keychar = String.fromCharCode(keynum)        numcheck = /\d/        return !numcheck.test(keychar)     }   </script>   <form>     <input type="text" onkeypress="return noNumbers(event)">     <input type="text" id="k">   </form>   <script type="text/javascript">     document.getElementById("k").onkeypress = noNumbers;   </script> </body> </html>
這邊要注意的是,不同的瀏覽器會由不同的方式取得該event的值。


參考資料:W3schools, onkeypress Event


2011年9月29日 星期四

[讀書心得]大債時代(序)


「如果你欠銀行一百萬,你的命運掌握在銀行手中;如果你欠銀行一百億,銀行的命運掌握在你手中。」這一句開場白讓我印象深刻,台灣的茂德就是一個例子了,以股作債,金融遊戲沒有所謂的死巷,只有怎麼轉,讓錢轉進你的口袋。
「如果這個世界上,人人都擁有大量存款,沒有債務,那只會導致兩件事發生:第一,銀行倒閉,第二,存款變廢紙,擁有糧食的,才是真正富人。」第一件事情會不會發生我不確定,但是第二件事情肯定會發生,其實這世界最殘酷的事實就是不可能均富,一定要有人擁有大筆財富,而另一大群人缺錢,為錢賣命工作,這世界才可能進步,鄧小平說的最坦白了,先讓一部分的人富起來,沒有說要讓大家都富起來。
序的後面還有一段話讓我感受頗深,「我們希望自己的收入不斷成長,不斷的投入更多的時間與精力,追求下一份更高的薪水、更好的享受。快樂永遠是下一次加薪,下一次旅行,下一次購物。我們從不滿足於自己已經所有的。想像一下,有一個人在四、五十歲的年紀,有一天突然心臟病發作。雖然事後幸運地復原了,但發作那一霎那心痛如刀剮,讓他以為自己就要離開人世的瞬間,卻讓他看清了人生的目的。從此以後,他過著更健康的生活,更珍惜與家人與朋友相處的時光,更知道拿一些時間來做自己覺得真正重要的事。一次健康上的小打擊,卻讓他的人生之路走得更快樂踏實。」如果說,賺錢是要讓自己和家人過得更好,那麼在你追求財富的路途上,是不是真的有過得比較好,還是只看到帳面上的數字在增加,自己的身體或心理卻反其道而行,家人之間的感情是否更好,還是越來越疏遠了,我想都是值得我們去省思的。



2011年9月18日 星期日

[Lua Note] 2 - Types and Values


Types and Values

Lua的變數型態完全取決於assign的值,而Lua有8個基本資料型態nil、boolean、number、string、userdata、function、thread和 table等。
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print(type(a))
nil
> a="hello"
> print(type(a))
string
> a=3*5
> print(type(a))
number
> a=function() end
> print(type(a))
function
> a=true
> print(type(a))
boolean


nil

nil和C/Java Script的null意思差不多,當宣告一個變數還沒有給值,預設值就是nil,而當給變數nil就相當於delete這個變數。
> x = {}
> x["y"] = 1
> for k,v in pairs(x) do
>> print(k,v)
>> end
y       1
> x["y"] = nil -- 將y自x中移除
> for k,v in pairs(x) do
>> print(k,v)
>> end
> -- 沒有印出y了


booleans

說到boolean大家應該都知道boolean只有兩種值,true/false,在lua中,除了nil和false是false以外,其他都是true。not則是反轉boolean。
> print(x)
nil
> print(not not x)
false
> x=0
> print(not not x)
true -- 和C不同唷
> x=false
> print(not not x)
false
> x = function() end
> print(not not x)
true


numbers

Lua中沒有整數(integer),數值(numbers)是用雙精度儲存(double-precision floating-point)。


strings

Lua中的字串是儲存8-bit的字元,所以您可以儲存任何的資訊,和C不同的地方是C用null-terminated("\0"當結數符號),而Lua會用length紀錄字串長度。
當Lua中的字串是不能改變的,一旦改變就等同重新建立一個新字串,這點和C也不同。
Lua的字串除了可以用雙引號和單引號表示外,還可以用 [[...]]表示。
> s1="test1"
> s2='test2'
> s3=[[
>> test1
>> test2
>> ]]
> print(type(s3))
string
> print(s3)
test1
test2

Lua中字串可以用..串接在一起。
和JavaScript一樣,Lua在字串和數字之間的數學運算會試著將字串轉成數字,轉失敗就會出現error。
> print(10 .. "1")
101
> print(10 + "1")
11
> print(10 .. "x")
10x
> print(10 + "x")
stdin:1: attempt to perform arithmetic on a string value
stack traceback:
        stdin:1: in main chunk
        [C]: ?


table

table也稱為associative arrays,key可以是任何的資料型態,除了nil以外,都可以當key(或稱index),而任何其值可以是任何的資料型態,其表示法和一般C的array類似都是用"[]"來取值。
> x = {
[1] = "one",
["2"] = "two",
[3.0] = "three",
}
> print(x[1])
one
> print(x["2"]); print(x[3.0])
two
three



2011年9月17日 星期六

[Lua Note] 1 - Getting Started


Chunks

Lua就和一般的Script一樣,沒有所謂的main function,也不需要分號";"'當成一個statement的結束,分號可有可無,不過我還是習慣性的加上去,就像數學運算式的括號,很可能你想的和你寫出來的意思不同,導致錯誤,以下的範例都是一樣的意思
 
    a = 1
    b = a*2
    
    a = 1;
    b = a*2;
    
    a = 1 ; b = a*2
    
    -- "--"是註解的意思
    a = 1   b = a*2    -- 很醜,但還是合法

您可以在提示符號下執行lua,lua [ options ] [ script [ args ] ]
prompt> lua 會進入interactive 模式。
prompt> lua -la -lb會執行a.lua和b.lua,-l相當於require的意思,lua就像一般的computer language一樣,允許您寫自己的library,並且透過require載入。
lua也提供另外dofile這個function,讓您測試您寫的lua檔,dofile和require最大的不同是,require只會載入一次,而dofile可以重覆載入,所以拿來驗證lua檔就非常適合了。



Global Variables

在Lua中,沒有特別宣告local就是Global Variables,用到沒有宣告的變數,其值就是nil
 
function scope1()      -- step 4.
    function scope2()  -- step. 8
        print(A)               -- step. 9 印出A=20
        local A=30         -- step. 10又宣告一個變數A(範圍更小)
        print(A)               -- step. 11 印出該範圍的A, 即30
    end
    print(A)           -- step 5. 印出 10
    local A=20     -- step 6. 新的A=20, Global的A一樣不變
    scope2()        -- step 7.
     print(A)          -- step 12. 印出這個範圍的A = 20
end

print(A)                -- step 1. 印出 nil
A=10                   -- step 2. A=10
scope1()             -- step 3.
print(A)                -- step 13. 印出這個範圍的A = 10
os.exit()



Some Lexical Conventions

和一般的language一樣,會有所謂的key word,以下是lua的key word
while
and break do else elseif
end false for function if
in local nil not or
repeatreturn then true until

lua是case-sensitive就是有分大小寫的。 變數x和變數X是不同的。
在Lua中的註解 --是單行,像C中的//,而--[[ --]]就像C的/* */屬於多行註解。好用的地方是,只要在"--[["前面多一個"-"就等於取消整個註解,超好用。
 
--[[
    print(10)         -- no action (comment)
--]]

---[[
    print(10)         --> 10
--]]


The Stand-Alone Interpreter

lua會將command-line的參數存到陣列arg中,arg[0]存放執行的script,arg[-1]存放script檔名的前一個參數,arg[1]..arg[n]就是依序存放後面的參數。


參考資料:Programming in Lua (first edition)




2011年9月12日 星期一

Lua - Introduction


最近有幸開發新的Web Page,用的是LuCI(Lua Unified Configuration Interface),所以就得先學學Lua嚕,在這裡做些筆記,也和大家分享一下。
Lua是一種embedded language,就像Java Script一樣,通常會依附在host program底下(就像IE和Java script的關係一樣),而host program會執行Lua的程式碼,(就像網頁中參雜Java Script一樣)。不過,在寫LuCI的時候,感覺比較像在寫PHP或者ASP之類的。

Lua主用是用C寫的,原始的Lua非常的小,因為只有提供非常精簡的能力,但是可以透過擴充Library變得更強(更肥),因為精簡,所以適合在Embedded System上使用。

www.lua.org是Lua的官方網站,其中最重要的莫過於裡面的免費書籍,Programming in Lua (first edition),這本是必看的,後面的筆記應該都會是源自這邊,熟悉Lua之後,也可以看看Lua 5.1 Reference Manual
該網站還提供Web版的Lua,讓您沒有Lua也能學Lua。


如果您是在Windows環境底下,您可以安裝luaforwindows來練習,Practice Makes Perfect。


2011年8月6日 星期六

core dump and debug



看ulimit預設的一些參數,注意core file size若是0,就不會產生core文件了。

brook@vista:~$ cat -n foo.c 
     1  #include 
     2
     3  static void sub(void);
     4
     5  int main(void)
     6  {
     7      sub();
     8      return 0;
     9  }
    10
    11  static void sub(void)
    12  {
    13      int *p = NULL;
    14
    15      /* derefernce a null pointer, expect core dump. */
    16      printf("%d", *p);
    17  }
    18
    19
brook@vista:~$ gcc -g -Wall foo.c 
brook@vista:~$ ./a.out 
Segmentation fault
brook@vista:~$ ls core*
ls: cannot access core*: No such file or directory
brook@vista:~$ ulimit -c 1024
brook@vista:~$ ./a.out 
Segmentation fault (core dumped)
brook@vista:~$ ls core*
core
brook@vista:~$ gdb ./a.out core 
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
 Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /home/brook/a.out...done.
[New Thread 5382]

warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...
Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.13.so...done.
done.
Loaded symbols for /lib/x86_64-linux-gnu/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...
(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0  0x0000000000400518 in sub () at foo.c:16
16          printf("%d", *p);
(gdb) 


    參考資料:
  1. http://blog.csdn.net/borefo/article/details/5029555, 在Linux下产生并调试core文件



2011年7月31日 星期日

台中 - 韓式料理 - 韓香 ☆☆☆


韓香位於居仁國中後面,就在中華電信旁,地理位置應該不難找,因為生意還算不錯,所以如果要吃,記得先預約唷,不然就得在外面慢慢排了,看到很多椅子了吧?就知道要等很久。


這是這家店的菜單,不過每次去都還是必點銅板烤肉+石鍋拌飯。




這家店最大的特色就是,小菜無限量供應,這邊的小菜大概有十多種吧,每次去每個人至少都可以吃掉10盤。



這邊有低消的限制唷。






地點:台中市市府路39號
價位:最低消費140元,另加收10%服務費



2011年7月9日 星期六

ELF之學習心得02 - ELF Header(e_ident篇)



這是ELF的layout,所謂的Linking View是指以檔案呈現之ELF(左圖),而Execution View則是指被載入到RAM上執行的ELF(右圖)。ELF header會包含整個檔案的"road map",我們可以利用readelf -h檢視elf header到底包含哪些東西?

由readelf -h可看出可看出ELF header包含了許多資訊,這些資訊都可以由定義在elf.h中的Elf32_Ehdr解讀出來。介紹ELF header之前,先介紹ELF的Data Types,這些資訊也都放置在elf.h檔中。

/* Standard ELF types.  */

#include <stdint.h>

/* Type for a 16-bit quantity.  */
typedef uint16_t Elf32_Half;
typedef uint16_t Elf64_Half;

/* Types for signed and unsigned 32-bit quantities.  */
typedef uint32_t Elf32_Word;
typedef int32_t  Elf32_Sword;
typedef uint32_t Elf64_Word;
typedef int32_t  Elf64_Sword;

/* Types for signed and unsigned 64-bit quantities.  */
typedef uint64_t Elf32_Xword;
typedef int64_t  Elf32_Sxword;
typedef uint64_t Elf64_Xword;
typedef int64_t  Elf64_Sxword;

/* Type of addresses.  */
typedef uint32_t Elf32_Addr;
typedef uint64_t Elf64_Addr;

/* Type of file offsets.  */
typedef uint32_t Elf32_Off;
typedef uint64_t Elf64_Off;

/* Type for section indices, which are 16-bit quantities.  */
typedef uint16_t Elf32_Section;
typedef uint16_t Elf64_Section;

/* Type for version symbol information.  */
typedef Elf32_Half Elf32_Versym;
typedef Elf64_Half Elf64_Versym;
Elf32和Elf64的data type只有在off和addr這兩種type的資料長度有不同,其餘都相同。您可以在下表中發現Elf32_Ehdr和Elf64_Ehdr的member資料長度只有差e_entry、e_phoff和e_shoff會不相同,其餘都相同,所以,Elf64_Ehdr比Elf32_Ehdr多了12byte。

ELF header如下
/* The ELF file header.  This appears at the start of every ELF file.  */

#define EI_NIDENT (16)

typedef struct
{
    unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
    Elf32_Half  e_type;         /* Object file type */
    Elf32_Half    e_machine;      /* Architecture */
    Elf32_Word  e_version;      /* Object file version */
    Elf32_Addr    e_entry;        /* Entry point virtual address */
    Elf32_Off   e_phoff;        /* Program header table file offset */
    Elf32_Off e_shoff;        /* Section header table file offset */
    Elf32_Word  e_flags;        /* Processor-specific flags */
    Elf32_Half    e_ehsize;       /* ELF header size in bytes */
    Elf32_Half  e_phentsize;        /* Program header table entry size */
    Elf32_Half    e_phnum;        /* Program header table entry count */
    Elf32_Half  e_shentsize;        /* Section header table entry size */
    Elf32_Half    e_shnum;        /* Section header table entry count */
    Elf32_Half  e_shstrndx;     /* Section header string table index */
} Elf32_Ehdr;

typedef struct
{
    unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
    Elf64_Half  e_type;         /* Object file type */
    Elf64_Half    e_machine;      /* Architecture */
    Elf64_Word  e_version;      /* Object file version */
    Elf64_Addr    e_entry;        /* Entry point virtual address */
    Elf64_Off   e_phoff;        /* Program header table file offset */
    Elf64_Off e_shoff;        /* Section header table file offset */
    Elf64_Word  e_flags;        /* Processor-specific flags */
    Elf64_Half    e_ehsize;       /* ELF header size in bytes */
    Elf64_Half  e_phentsize;        /* Program header table entry size */
    Elf64_Half    e_phnum;        /* Program header table entry count */
    Elf64_Half  e_shentsize;        /* Section header table entry size */
    Elf64_Half    e_shnum;        /* Section header table entry count */
    Elf64_Half  e_shstrndx;     /* Section header string table index */
} Elf64_Ehdr;

/* Fields in the e_ident array.  The EI_* macros are indices into the
 *    array.  The macros under each EI_* macro are the values the byte
 *       may have.  */

#define EI_MAG0     0       /* File identification byte 0 index */
#define ELFMAG0     0x7f        /* Magic number byte 0 */

#define EI_MAG1     1       /* File identification byte 1 index */
#define ELFMAG1     'E'     /* Magic number byte 1 */

#define EI_MAG2     2       /* File identification byte 2 index */
#define ELFMAG2     'L'     /* Magic number byte 2 */

#define EI_MAG3     3       /* File identification byte 3 index */
#define ELFMAG3     'F'     /* Magic number byte 3 */

/* Conglomeration of the identification bytes, for easy testing as a word.  */
#define ELFMAG      "\177ELF"
#define SELFMAG     4

#define EI_CLASS    4       /* File class byte index */
#define ELFCLASSNONE    0       /* Invalid class */
#define ELFCLASS32  1       /* 32-bit objects */
#define ELFCLASS64  2       /* 64-bit objects */
#define ELFCLASSNUM 3

#define EI_DATA     5       /* Data encoding byte index */
#define ELFDATANONE 0       /* Invalid data encoding */
#define ELFDATA2LSB 1       /* 2's complement, little endian */
#define ELFDATA2MSB 2       /* 2's complement, big endian */
#define ELFDATANUM  3

#define EI_VERSION  6       /* File version byte index */
                    /* Value must be EV_CURRENT */

#define EI_OSABI            7   /* OS ABI identification */
#define ELFOSABI_NONE       0   /* UNIX System V ABI */
#define ELFOSABI_SYSV       0   /* Alias.  */
#define ELFOSABI_HPUX       1   /* HP-UX */
#define ELFOSABI_NETBSD     2   /* NetBSD.  */
#define ELFOSABI_LINUX      3   /* Linux.  */
#define ELFOSABI_SOLARIS    6   /* Sun Solaris.  */
#define ELFOSABI_AIX        7   /* IBM AIX.  */
#define ELFOSABI_IRIX       8   /* SGI Irix.  */
#define ELFOSABI_FREEBSD    9   /* FreeBSD.  */
#define ELFOSABI_TRU64      10  /* Compaq TRU64 UNIX.  */
#define ELFOSABI_MODESTO    11  /* Novell Modesto.  */
#define ELFOSABI_OPENBSD    12  /* OpenBSD.  */
#define ELFOSABI_ARM_AEABI  64  /* ARM EABI */
#define ELFOSABI_ARM        97  /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */

#define EI_ABIVERSION       8   /* ABI version */

#define EI_PAD              9   /* Byte index of padding bytes */

資料結構大致介紹完畢,接著就可以透過實做readelf -h的程式來了解ELF header了,首先,所有的ELF開頭都會有16 bytes的ELF Identification,也是本章節所要介紹的部份。

EI_MAG0 ~ EI_MAG3

所有的ELF前面4byte為magic number,其內容為{0x7f, 'E', 'L', 'F'},用以判斷是否為ELF檔。

static int elf_header(int fd) 
{
    int sz; 
    unsigned char e_ident[EI_NIDENT];

    sz = read(fd, e_ident, sizeof(e_ident));
    if (sz < sizeof(e_ident)) {
        fprintf(stderr, "invalid elf file\n");
        return -1;
    }   

    // 判斷是否為ELF檔
    if (memcmp(ELFMAG, e_ident, SELFMAG)) {
        fprintf(stderr, "invalid elf file\n");
        return -1;
    }   
    elf_header_magic(e_ident);
}


/**
 * 印出ident(前面16byte)
 */
static int elf_header_magic(unsigned char *c)
{
    int i;
    printf("%-10s", "Magic: ");
    for (i = 0; i < EI_NIDENT; i++) {
        printf("%02X ", c[i]);
    }
    printf("\n");
    return 0;
}

EI_CLASS

EI_CLASS這個byte是用來判斷是32-bit或是64-bit的ELF檔,根據不同的Class就要選擇使用Elf32_Ehdr或是Elf64_Ehdr判讀後面的資料。

/**
 * 判斷是32-bit/64-bit architectures.
 */
static int elf_header_class(unsigned char c)
{
    printf("%-36s", "Class: ");
    switch(c) {
        case ELFCLASSNONE:
            fprintf(stderr, "Invalid class\n");
            return -1;

        case ELFCLASS32:
            printf("32-bit object\n");
            break;

        case ELFCLASS64:
            printf("64-bit object\n");
            break;

        default:
            fprintf(stderr, "unknow class\n");
            return -1;
    }
    return 0;
}


EI_DATA

EI_DATA這個byte是用來判斷ELF檔是LSB(Little-endian)還是MSB(Big-endian)。
/**
 * 判斷ELF檔是LSB(Little-endian)還是MSB(Big-endian)
 */
static int elf_header_data(unsigned char c)
{
    printf("%-36s", "Data: ");
    switch(c) {
        case ELFDATANONE:
            fprintf(stderr, "Invalid data encoding\n");
            return -1;

        case ELFDATA2LSB:
            printf("2's complement, little endian\n");
            break;

        case ELFDATA2MSB:
            printf("2's complement, big endian\n");
            break;

        default:
            fprintf(stderr, "unknow data\n");
            return -1;
    }
    return 0;
}


EI_VERSION

EI_VERSION這個byte是指出這個ELF檔的ELF header的版本是多少?目前這個值必須是EV_CURRENT。
static int elf_header_version(unsigned char c)
{
    printf("%-36s", "Version: ");
    switch(c) {
        case EV_CURRENT:
            printf("Current version");
            break;

        default:
        case EV_NONE:
            printf("Invalid ELF version");
            break;
    }
    printf("(%d)\n", c);
    return 0;
}


EI_OSABI

EI_OSABI這個byte是指出這個ELF檔會在那個OS上運行。
static int elf_header_osabi(unsigned char c)
{
    printf("%-36s", "OS/ABI: ");
    switch(c) {
        case ELFOSABI_SYSV:
            printf("UNIX System V ABI");
            break;

        case ELFOSABI_HPUX:
            printf("HP-UX");
            break;

        case ELFOSABI_NETBSD:
            printf("NetBSD.");
            break;

        case ELFOSABI_LINUX:
            printf("Linux.");
            break;

        case ELFOSABI_SOLARIS:
            printf("Sun Solaris.");
            break;

        case ELFOSABI_AIX:
            printf("IBM AIX.");
            break;

        case ELFOSABI_IRIX:
            printf("SGI Irix.");
            break;

        case ELFOSABI_FREEBSD:
            printf("FreeBSD.");
            break;

        case ELFOSABI_TRU64:
            printf("Compaq TRU64 UNIX.");
            break;

        case ELFOSABI_MODESTO:
            printf("Novell Modesto.");
            break;

        case ELFOSABI_OPENBSD:
            printf("OpenBSD.");
            break;

        case ELFOSABI_ARM_AEABI:
            printf("ARM EABI");
            break;

        case ELFOSABI_ARM:
            printf("ARM");
            break;

        case ELFOSABI_STANDALONE:
            printf("Standalone (embedded) application");
            break;

        default:
            fprintf(stderr, "unknow osabi\n");
            return -1;
    }
    printf("(%d)\n", c);
    return 0;
}


EI_ABIVERSION

EI_ABIVERSION這個byte是指出這個ELF檔會在那個API版本上運行。一個OS上可能有多個ABI的版本在運行的版本在運行,如SYSV至少就有SVR、Solaris、SCO等ABI。0代表不指定(unspecified)。
static int elf_header_abi_version(unsigned char c)
{
    printf("%-36s%d\n", "ABI Version: ", c);
    return 0;
}


EI_PAD

EI_PAD這個byte之後的都是padding。


到目前為止,僅有解釋ELF header中的e_ident,剩下的部份會在後面繼續探討與研究。


2011年6月19日 星期日

Introduction cpufreq


Linux Device Driver是架構在mechanism和policy之間,Mechanism定義了應該提供哪些功能(what capabilities are provided),而policy定義應該如何使用這些功能(how the capabilities are to be used),這樣的分層可以簡化設計,因為policy或mechanism的改變,另外一個可以不需要更動。一般而言,Linux Device Driver都是policy free,只提供Device本身的capabilities,而沒有policy,有時候會在上面再設計一個policy,比如這次的主題cpufreq就提供了一些governors(performance、powersave、userspace、conservative和ondemand) 提供了一些調動CPU頻率的policy,然而每個CPU的CPU frequence的設定方式都不同,所以,每個CPU都有自己的driver來達到CPU frequency scaling,比如Intel的Enhanced SpeedStep或AMD的PowerNow!。

在cpufreq這個sub-system中也提供了一些sys的interface可以操控policy,這邊大概提一下governors.txt中提到的幾個重點。
首先,CPU的frequency policy我們稱為governors,共有Performance、Powersave、Userspace、Ondemand和Conservative等五種。您可以透過讀取/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors知道system提供了哪些的governors,也可以透過/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies了解CPU提供了幾種CPU frequency。透過讀取/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor可以知道現在的governor為何?而要改變governor則是寫入到該檔案,藉由讀取/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_frequencies可以讀取現在的CPU頻率。
    接下來介紹一下各個governor的規則,
  • Performance會always用最高的頻率執行,
  • Powersave會always用最低的頻率執行,
  • 當user使用Userspace時,可以讓user透過寫入/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed改變CPU的頻率,
  • Ondemand則會根據系統的loading來調整頻率,當系統的loading高於/sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold時,就會立刻將CPU調到最高頻率運行,之後再慢慢的降下來,
  • conservative和Ondemand類似,conservative有/sys/devices/system/cpu/cpu0/cpufreq/conservative/up_threshold/sys/devices/system/cpu/cpu0/cpufreq/conservative/down_threshold當系統loading超過up_threshold時,就會調高CPU的頻率,當低於down_threshold就會調降CPU的頻率,
由於ondemand變換CPU頻率過大,所以使用ondemand的CPU必須有能力快速切換CPU的頻率,不然很容易當機。

您也可以透過一些utility如cpufreq-info讀取相關資訊,基本上都還是透過讀取上述的那些檔案內容列印出來而已。

由cpufreq-info可以知道目前是acpi-cpufreq這個driver(應該猜得出是Intel的CPU),還有其他資訊。
    參考資料:
  • Linux Documentation / cpu-freq / governors.txt
  • Linux Documentation / cpu-freq / user-guide.txt
  • https://wiki.archlinux.org/index.php/CPU_Frequency_Scaling
  • http://blog.csdn.net/guoshaobei/archive/2010/12/21/6090359.aspx
  • http://software.intel.com/en-us/articles/enhanced-intel-speedstepr-technology-and-demand-based-switching-on-linux/



2011年6月5日 星期日

ELF之學習心得01


目前Linux的主要的可執行檔格式是ELF(Executable and Linking Format),ELF為COFF格式的後繼者,主要特徵是可擁有多個section,並且有32-bit與64-bit的數值用以區別其格式屬於32-bit或是64-bit。主要缺點是ELF設計時有一個假設,每個系統只會有一個ABI(Application Binary Interface),但是事實上這是錯的,如SYSV至少就有SVR、Solaris、SCO等ABI。(詳細內容請閱讀參考資料)

    ELF主要有三種類型的object files:
  • A relocatable file holds code and data suitable for linking with other object files to create an executable or a shared object file.
  • An executable file holds a program suitable for execution.
  • A shared object file holds code and data suitable for linking in two contexts. First, the link editor may process it with other relocatable and shared object files to create another object file. Second, the dynamic linker combines it with an executable file and other shared objects to create a process image.


這是ELF的layout,所謂的Linking View是指以檔案呈現之ELF(左圖),而Execution View則是指被載入到RAM上執行的ELF(右圖)。

    主要的section包含
  1. .text,存放程式碼的區域。
  2. .data用於存放已經初始化的變數。
  3. .bss用於存放未初始化的變數或者內容初始化為0的,該區域不占檔案空間。
  4. .rodata用於存放read-only data。
  5. 其他section和使用者自訂section後面再慢慢介紹。
這些以"."開頭的section為系統保留之section,使用者可以自訂section,但是應該避免使用"."開頭。
#include <stdio.h>

int i0 = 0;
int i1 = 1;
static int si0 = 0;
static int si1 = 1;
const int ci0 = 0;
const int ci1 = 1;
const static int csi0 = 0;
const static int csi1 = 1;

int main(void)
{
    return 0;
}


objdump -x a.out 

SYMBOL TABLE:
0000000000601034 l   O .bss     0000000000000004  si0
000000000060101c l   O .data    0000000000000004  si1
00000000004005b4 l   O .rodata  0000000000000004  csi0
00000000004005b8 l   O .rodata  0000000000000004  csi1
00000000004005b0 g   O .rodata  0000000000000004  ci1
0000000000601030 g   O .bss     0000000000000004  i0
00000000004005ac g   O .rodata  0000000000000004  ci0
0000000000601018 g   O .data    0000000000000004  i1
根據前面的規則用const修飾的變數會被放置在.rodata中,有ci0、ci1、csi0、csi1。未初始化的變數或者內容初始化為0的都會被放置在.bss中,有i0、si0。已經初始化的變數則放在.data中,有i1、si1。



2011年5月21日 星期六

Android on OpenWrt


這篇要介紹openwrt上面的Andorid emulator,使用openwrt只有一個原因,因為內建android emulator,只要configure好,就可以執行。
步驟如下:
brook@vista:~/projects$ git git://nbd.name/openwrt.git
brook@vista:~/projects$ cd openwrt
brook@vista:~/projects/openwrt$ make menuconfig
    Target System選擇"Goldfish (Android Emulator)"
    Target Images選擇"jffs2"
    Emulators選擇"goldfish-qemu"
brook@vista:~/projects/openwrt$ make world




有相關的package沒裝好就會出現error,再依照指示逐一裝上即可。
最後執行內建的script就可以呼叫android模擬器出來了。
brook@vista:~/projects/openwrt/bin/goldfish$ sh run-emulator.sh



    參考資料:
  • http://lwn.net/Articles/332301/
  • http://nbd.name/blog/?p=36
  • http://nbd.name/blog/?p=48
  • https://forum.openwrt.org/viewtopic.php?id=15201



2011年5月7日 星期六

Linux Kernel(14)- Kernel Synchronization


這裡簡單介紹的介紹一下Kernel Synchronization的幾個觀念的幾個觀念。
  1. Race Condition
  2. 當多個process同時對同一個資料進行存取,且執行結果和其存取順序的不同而有所不同,稱為race condition。
  3. Critical Regions(或稱critical sections)
  4. 指的是一個存取共用資源的程式片斷。
  5. Kernel Synchronization
  6. 簡單說防止kernel發生race condition。保護的重點是shared data,而且保護的範圍和負擔越小越好。

Kernel Synchronization常見的作法就是locking,每次只允許一個process可以存取share data,就可以避免race condition了。

    在kernel中有幾種引發concurrency的可能
  1. Interrupt
  2. 當CPU收到interrupt會立刻中斷目前工作去執行interrupt handler。
  3. Softirq
  4. 當softirq被raise起來就會中斷目前工作去執行softirq。
  5. kernel preemption
  6. 如果kernel preemption被開啟,那麼task就可能被中斷。
  7. Sleeping
  8. 如果kernel執行到blocking code,就可能被schedule出去。
  9. SMP
  10. 同時間兩個以上的CPU存取相同的資料就會發生race condition。


在linunx kernel中,執行的context主要分成兩種interrupt context和process context,凡是只要in_interrupt()都是interrupt context,所以引起的原因包含Hardware interrupt和softirq兩種。以下就擷取片段程式碼說明。
// thread_info存放在task的stack裡面
# define task_thread_info(task)  ((struct thread_info *)(task)->stack)

// thread_info中的preempt_count分成幾個部份
// bits 0-7 are the preemption count (max preemption depth: 256)
// bits 8-15 are the softirq count (max # of softirqs: 256)
// bits 16-25 are the hardirq count (max # of nested hardirqs: 1024)
// bit 26 is the NMI_MASK
// bit 28 is the PREEMPT_ACTIVE flag
struct thread_info {
    struct task_struct *task;   /* main task structure */
    int    preempt_count;       /* 0 => preemptable */
};

# define preempt_count()        (current_thread_info()->preempt_count)
# define add_preempt_count(val) do { preempt_count() += (val); } while (0)
# define sub_preempt_count(val) do { preempt_count() -= (val); } while (0)

// 當每次呼叫irq_enter()就會將preempt_count屬於HARDIRQ的部份遞增
#define __irq_enter()                       \
    do {                                    \
        account_system_vtime(current);      \
        add_preempt_count(HARDIRQ_OFFSET);  \
        trace_hardirq_enter();              \
    } while (0)

# define invoke_softirq()   do_softirq()
# define IRQ_EXIT_OFFSET    HARDIRQ_OFFSET
/*
 * Exit an interrupt context. Process softirqs if needed and possible:
 */
void irq_exit(void)
{
    // 離開hard interrupt所以要減回去HARDIRQ_OFFSET
    sub_preempt_count(IRQ_EXIT_OFFSET);
    // 如果不在interrupt context(如softirq裡面),
    // 而且softirq有被raise就執行softirq
    if (!in_interrupt() && local_softirq_pending())
        invoke_softirq();
}

此圖出於http://blog.csdn.net/hero7935/archive/2011/05/07/6401522.aspx

    參考資料:
  • Linux Kernel Development 2nd, Novell Press