检查lfs从内核到到第一个进程init是否成功

当系统从bootloader传递参数到linux的start_kernel


一般内核里面不会出什么BUG。主要是上层构建的rootfs有没有问题。

即使内核里面出了问题,也会在串口提示。也可以通过打log来跟踪 一步步到哪里出问题了。

使用printk 打印内核日志。可以很快定位到哪里出了问题。


一般最后内核会运行到

kernel_init

尝试运行init进程

if (!try_to_run_init_process("/sbin/init") )
if ( !try_to_run_init_process("/etc/init"))

if ( !try_to_run_init_process("/bin/init"))
if (  !try_to_run_init_process("/bin/sh"))

这四个里面有一个运行成功就算运行到init进程了。只要有一个成功就会立马返回。


如果这个进程完成。后续的过程也可以从init进程里面打日志printf来调试了。

关键就是这个init进程能否起来。一般不能起来主要是缺少某些依赖库。特别是lib下面的

我们可以一步步跟踪过去。返回0表示 成功。其他的值一般是错误

这一条路径上可以多打日志

try_to_run_init_process->run_init_process->do_execve->do_execveat_common->(prepare_binprm  exec_binprm)

这个exec_binprm最容易返回错误 导致最后执行try_run的值返回-2没有找到模块

exec_binprm->search_binary_handler


search_binary_handler会根据读取的binary的头部判断是不是可执行的bin格式。

然后调用相应的函数执行

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,
};


list_for_each_entry(fmt, &formats, lh) 枚举当前的处理bin文件的handler然后调用他们的

retval = fmt->load_binary(bprm);的方法。


load_binary方法主要是 load_elf_binary和load_elf_library


主要是load_elf_binary加载的过程容易出错也就是说

try_to_run_init_process("/sbin/init)

最后用load_elf_binary来加载执行这个进程


load_elf_binary中间解析了init头部

确认binary需要加载哪些库然后尝试加载这些库

这中间需要调用 open_exec来打开这些库


open_exec->do_open_execat->do_filp_open->path_openat-> do_last做最后一步打开的工作->lookup_open


do_last里面如何确认是哪个文件miss?

{


printk("CRITICAL BEGIN \n\n")

打印当前准备打开的文件名 在第一个参数

struct nameidata *nd,

struct nameidata {
struct path path;
struct qstr last;
struct path root;
struct inode *inode; /* path.dentry.d_inode */
unsigned int flags;
unsigned seq, m_seq;
int last_type;
unsigned depth;
struct file *base;
char *saved_names[MAX_NESTED_LINKS + 1];
};

struct qstr {
union {
struct {
HASH_LEN_DECLARE;
};
u64 hash_len;
};
const unsigned char *name;
};


nd->last->name这里是文件名字 打印出来(这里是不带路径的。只有文件名,也可以直接去lookup_dcache函数里面打印 这里会打出全路径)

lookup_open 


printk("CRITICAL END \n\n")



在return之前打印返回值 如果return 地方不好找,可以直接在do_last之后打印

return xxxxxx

}


如果 do_last返回值不是0表示这个文件由错误。一般是不存在。我们在这里面又打印了文件名字,可以一下就定位到是哪个文件出了问题。



关键是看do_last打开文件的时候是否返回了0,0表示成功。非0表失败。把这个文件打印出来就知道哪里的问题了。


我的init起不来表现为

Kernel panic - not syncing: No working init found.  Try passing init= option to kernel. See Linux Documentation/init.txt for guidance.
CPU: 0 PID: 1 Comm: swapper Not tainted 4.1.19 #2
Hardware name: ARM-Versatile PB
[<c001ac70>] (unwind_backtrace) from [<c00177c4>] (show_stack+0x10/0x14)
[<c00177c4>] (show_stack) from [<c0375e34>] (panic+0x7c/0x1d8)
[<c0375e34>] (panic) from [<c0375584>] (kernel_init+0xa8/0x148)
[<c0375584>] (kernel_init) from [<c00145e8>] (ret_from_fork+0x14/0x2c)
---[ end Kernel panic - not syncing: No working init found.  Try passing init= option to kernel. See Linux Documentation/init.txt for guidance.



根据这个方法成功定位到

lookup_dcache=lib/ld-linux.so.3
openat ERROR 3350=00000000
CRITICAL BEGIN 
lookup_dcache=ld-linux.so.3
 dentry flag 0 
do_last  FLAGS  3083=00000080
CRITICAL END 
do_last ERROR NEGATIVE 3141=fffffffe

返回了-2.是ld-linux.so.3丢失了。


你可能感兴趣的:(检查lfs从内核到到第一个进程init是否成功)