当系统从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丢失了。