我們習慣在SI(Source Insight)中閱讀Linux內核,SI會建立符號表數據庫,能非常方便地跳轉到變量、宏、函數等的定義處。但在處理系統調用的函數時,卻會遇到一些麻煩:我們知道系統調用函數名的特點是sys_×××,例如我們想找open函數的內核系統調用代碼,在SI提供的符號表中搜索sys_open,能找到函數的聲明:
asmlinkage long sys_open(const char __user *filename, int flags, umode_t mode);
原本SI提供從函數名按住Ctrl單擊鼠標左鍵能跳轉到定義處的功能,但運用在系統調用函數sys_open上卻失敗了,這是什麼回事呢?
經過分析,原來內核中系統調用采用了宏定義,如這裡的sys_open就被定義為:
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
可以猜測出這個宏定義展開之後就是上面函數聲明那樣的,難怪SI不能跳轉到系統調用的定義處呢!
下面以open系統調用為例分析這個宏是如何展開的:
首先在 include/linux/syscall.h
中有下面這樣的宏定義:
#define SYSCALL_DEFINE3(name, ...) \
SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
針對這個宏定義有幾點說明:
__VA_AEGS__
代表省略的變長部分;#define VAR(type, name) type name##_##type
VAR(int, var1);
展開之後就是:
int var1_int;
那麼:
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
展開之後是:
SYSCALL_DEFINEx(3, _open, __VA_ARGS__)
這又是一個宏,根據宏定義:
#define SYSCALL_DEFINEx(x, sname, ...) \
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
SYSCALL_DEFINEx(3, _open, __VA_ARGS__)
展開為:
__SYSCALL_DEFINEx(3, _open, __VA_ARGS__)
再根據宏定義:
#define __SYSCALL_DEFINEx(x, name, ...) \
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))
__SYSCALL_DEFINEx(3, _open, __VA_ARGS__)
展開為:
asmlinkage long sys_name(__SC_DECL3(__VA_ARGS__))
這裡 __VA_ARGS__
是 const char __user *, filename, int, flags, umode_t, mode
,而同樣__SC_DECL3
又是一組宏定義:
#define __SC_DECL1(t1, a1) t1 a1
#define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__)
#define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__)
這樣,一步一步地展開:
__SC_DECL3(const char __user *, filename, int, flags, umode_t, mode)
==> __SC_DECL3(const char __user *, filename, int, flags, umode_t, mode)
==> const char __user* filename, __SC_DECL2( int, flags, umode_t, mode)
==> const char __user* filename, int flags, __SC_DECL1(umode_t, mode)
==> const char __user* filename, int flags, umode_t mode
最終:
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
宏定義展開之後就成為:
asmlinkage long sys_open(const char __user *filename, int flags, umode_t mode);
正如我們之前猜測的那樣。
更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-12/110240p2.htm