系統呼叫lseek和核心file結構體之間的關係

stormbm發表於2016-08-15

大家都知道lseek就是移動檔案的讀寫位置, 也就是對應核心中file結構體中的某一個變數, 今天就是特別想看一下具體之間的關係.
軟體就在於實踐

首先需要有一個很方便呼叫lseek的環境, 這樣才不會影響我們除錯的興趣, 希望能達到像python, matlab這樣每個函式可以手動跑, 而不像c語言一樣要編寫, 然後編譯, 然後執行, 然後再修改, 編譯. gdb可以

  1. 先準備檔案1.c, 前面的標頭檔案很重要, 不能漏
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int main()
{
return 0;
}
gcc 1.c -ggdb3

-ggdb3是為了能方便的使用巨集

gdb ./a.out
b main
r

接下來會使用call open來開啟檔案, 但是如何找到我們將要開啟的檔案在核心中的file結構體的地址呢? kgtp
找到a.out程式號是1138

找到核心do_sys_open原始碼

1012 long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
1013 {
1014 struct open_flags op;
1015 int lookup = build_open_flags(flags, mode, &op);
1016 struct filename *tmp = getname(filename);
1017 int fd = PTR_ERR(tmp);
(gdb) 
1018
1019 if (!IS_ERR(tmp)) {
1020 fd = get_unused_fd_flags(flags);
1021 if (fd >= 0) {
1022 struct file *f = do_filp_open(dfd, tmp, &op, lookup);
1023 if (IS_ERR(f)) {

所以要在1023設定tracepoint找到f的值, 並且使用pid 1138來過濾, 總結就是要得到程式1138呼叫do_sys_open的時候的f的值
kgtp命令

tmp=`mktemp`; echo `set pagination off
set confirm off
set circular-trace-buffer on
target remote /sys/kernel/debug/gtp
d
trace open.c:1023
actions
collect f
end
tstart` > $tmp; echo $tmp; cat $tmp; sudo gdb /usr/lib/debug/lib/modules/3.10.0-327.el7.x86_64/vmlinux -x $tmp
`f` has been optimized out, cannot use

但是發現f被優化, 只能找彙編地址來定位f的值

0xffffffff811dd7de <+238>: callq 0xffffffff811efdf0 <do_filp_open>
0xffffffff811dd7e3 <+243>: cmp $0xfffffffffffff000,%rax

所以tracepoint到0xffffffff811dd7e3
kgtp的命令

tmp=`mktemp`; echo `set pagination off
set confirm off
set circular-trace-buffer on
target remote /sys/kernel/debug/gtp
d
trace *0xffffffff811dd7e3 if ((struct task_struct *)$current_task)->pid == 1138
actions
collect $rax
end
tstart` > $tmp; echo $tmp; cat $tmp; sudo gdb /usr/lib/debug/lib/modules/3.10.0-327.el7.x86_64/vmlinux -x $tmp

Tracepoint 1 at 0xffffffff811dd7e3: file fs/open.c, line 1023

回到gdb中手動呼叫call open

(gdb) call open("/root/1.c", O_WRONLY )
$5 = 7

回到kgtp中檢視f的值

(gdb) p/x $rax
$3 = 0xffff88003ad2ee00
(gdb) tfind -1
(gdb) p ((struct file*)$3)->f_pos
$7 = 0

到gdb中call lseek

(gdb) call lseek(7, 1, 0)
$6 = 1

檢視file結構體

p ((struct file*)$3)->f_pos
$9 = 1

到gdb中call lseek

(gdb) call lseek(7, 234, 0)
$7 = 234

檢視file結構體

(gdb) p ((struct file*)$3)->f_pos
$10 = 234


相關文章