跟蹤sys_execve的執行過程

鄭德倫 原創作品轉載請註明出處 《Linux內核分析》MOOC課程
http://mooc.study.163.com/course/USTC-1000029000
一、 配置新的MenuOS環境
在終端進入LinuxKernel目錄,輸入

rm –rf menu
git clone https://github.com/mengning/menu.git
mv test_exec.c test.c
make rootfs

完成新的MenuOS的配置。在此版本的MenuOS中,加入了exec功能。也就是執行execlp庫函數,來創建一個新的進程hello。
二、 追蹤sys_execve的執行過程
打開終端,進入LinuxKernel目錄輸入
qemu –kernel linux-3.18.6/arch/x86/boot/bzImage –initrd rootfs.img –S –s
然後打開另一個終端輸入

gdb
(gdb)file linux-3.18.6/vmlinux
(gdb)target remote:1234
(gdb)c
(gdb)b sys_execve
(gdb)b load_elf_binary
(gdb)b start_thread
(gdb)b do_execve
(gdb)c

我們開始跟蹤執行過程,在qemu中輸入exec,首先進入斷點是sys_execve,在在中端處理程序中,調用了do_execve(),其中getname從用戶空間獲取filename(也就是hello)的路徑,到內核中。

這裏寫圖片描述
進入do_execve函數體內發現,實際工作是完成argv envp賦值,然後調用do_execve_common
這裏寫圖片描述
我們進入do_execve_common函數體內
這裏寫圖片描述
我們看下do_execve_common的源代碼,do_execve_common完成了一個linux_binprm的結構體 bprm的初始化工作:

retval = bprm_mm_init(bprm);初始化了mm_strcut
bprm->argc = count(argv, MAX_ARG_STRINGS);//計算參數個數,直到爲NULL
retval = prepare_binprm(bprm);//把要加載文件的前128 讀入bprm->buf
retval = copy_strings_kernel(1, &bprm->filename, bprm);//copy第一個參數filename
bprm->exec = bprm->p;//參數的起始地址
retval = copy_strings(bprm->envc, envp, bprm);//copy環境變量
retval = copy_strings(bprm->argc, argv, bprm);//copy可執行文件所帶參數:argv[0]:hello argv[1]:hello
retval = exec_binprm(bprm);//執行bprm
int do_execve_common(struct filename *filename,
                struct user_arg_ptr argv,
                struct user_arg_ptr envp)
{
    struct linux_binprm *bprm;
    struct file *file;
    struct files_struct *displaced;
    int retval;

    /**省略中間一部分***/
    bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
    if (!bprm)
        goto out_files;

    retval = prepare_bprm_creds(bprm);
    if (retval)
        goto out_free;

    check_unsafe_exec(bprm);
    current->in_execve = 1;

    file = do_open_exec(filename);
    retval = PTR_ERR(file);
    if (IS_ERR(file))
        goto out_unmark;

    sched_exec();

    bprm->file = file;
    bprm->filename = bprm->interp = filename->name;

    retval = bprm_mm_init(bprm);
    if (retval)
        goto out_unmark;

    bprm->argc = count(argv, MAX_ARG_STRINGS);
    if ((retval = bprm->argc) < 0)
        goto out;

    bprm->envc = count(envp, MAX_ARG_STRINGS);
    if ((retval = bprm->envc) < 0)
        goto out;

    retval = prepare_binprm(bprm);
    if (retval < 0)
        goto out;

    retval = copy_strings_kernel(1, &bprm->filename, bprm);
    if (retval < 0)
        goto out;

    bprm->exec = bprm->p;
    retval = copy_strings(bprm->envc, envp, bprm);
    if (retval < 0)
        goto out;

    retval = copy_strings(bprm->argc, argv, bprm);
    if (retval < 0)
        goto out;

    retval = exec_binprm(bprm);
    if (retval < 0)
        goto out;

    /***省略中間一部分代碼****/
    return retval;
}

然後我們跟蹤到exec_binprm,查看函數代碼,這段代碼將父進程的pid保存,獲取新的pid,然後執行search_binary_hander(bprm),用來遍歷format鏈表,找到合適的處理hello的方式。

static int exec_binprm(struct linux_binprm *bprm)
{
    pid_t old_pid, old_vpid;
    int ret;

    /* Need to fetch pid before load_binary changes it */
    old_pid = current->pid;
    rcu_read_lock();
    old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent));
    rcu_read_unlock();

    ret = search_binary_handler(bprm);
    if (ret >= 0) {
        audit_bprm(bprm);
        trace_sched_process_exec(current, old_pid, bprm);
        ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
        proc_exec_connector(current);
    }

    return ret;
}

我們繼續continue 調試,達到斷點search_bintary_handler
這裏寫圖片描述
在這裏面有個結構體linux_binfmt *fmt;

static struct linux_binfmt elf_format = {

    .module         = THIS_MODULE,
    .load_binary    = load_elf_binary,
    .load_shlib     = load_elf_library,
    .core_dump      = elf_core_dump,
    .min_coredump   = ELF_EXEC_PAGESIZE,
};

裏面的.load_binary字段初始化爲load_elf_binary由此可見load_binary應該是一個函數指針。
我們繼續跟蹤到達load_elf_binary,這個函數完成的二進制文件的裝載和啓動,其中在函數的末尾有start_thread(regs, elf_entry, bprm->p);是二進制的啓動代碼,我們繼續跟蹤到達start_thread

這裏寫圖片描述
start_thread函數完成pt_reg結構的轉換,從當前進程轉換到新進程,完成進程的切換,從而開始執行execve的進程。
三、 總結
通過上面的調試過程,我們已經比較清楚的瞭解到一個sys_execve系統調用的執行過程,具體的流程圖如下:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章