内存调试:检查段错误
memwatch工具来检测段错误
将需要测试文件与memwatch.c共同编译
内核调试错误:Oops机制(内核提供)
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c0004000
[00000000] *pgd=00000000
Internal error: Oops: 805 [#1] PREEMPT SMP ARM
Modules linked in:
CPU: 1 PID: 1 Comm: swapper/0 Not tainted 3.14.0 #11
task: ee8a0000 ti: ee8a4000 task.ti: ee8a4000
PC is at dm9000_probe+0x1c/0x8f0
LR is at platform_drv_probe+0x18/0x48
pc : [<c0277cc8>] lr : [<c0247f7c>] psr: 60000153 oops需要查看的内容
sp : ee8a5e48 ip : 00000000 fp : 00000000
r10: c052a4fc r9 : 00000000 r8 : c0591e98 pc : [<c0277cc8>] 崩溃前最后一个执行位置
r7 : 00000000 r6 : ee97c810 r5 : ee97c800 r4 : 00000000
r3 : 000000ff r2 : 00000000 r1 : ee8a5de8 r0 : ee97c800
Flags: nZCv IRQs on FIQs off Mode SVC_32 ISAARM Segment kernel
Control: 10c5387d Table: 4000404a DAC: 00000015
Process swapper/0 (pid: 1, stack limit = 0xee8a4240)
Stack: (0xee8a5e48 to 0xee8a6000)
5e40: ee975cf0 00000000 ee1503a8 00000001 c0561afc ee150438
5e60: 00000000 ee97c810 c0591e98 ee97c810 00000000 c0591e98 c0561afc c052a4fc 显示是内存使用错误
5e80: 00000000 c0247f7c c0247f64 c05d931c c0591e98 c0246668 ee97c810 c0591e98
5ea0: ee97c844 00000000 c054332c c0246804 c0591e98 c0246778 00000000 c0244fbc
5ec0: ee805478 ee9771c0 c0591e98 eeb73a00 c0590028 c0245e28 c04c3128 c0591e98
5ee0: 00000000 c0591e98 00000000 c054e2ac c059f280 c0246e1c 00000000 ee8a4000
5f00: 00000000 c00087b4 ee903b00 c05c3d50 60000153 c0571c00 60000100 c0571c00
5f20: 00000000 00000000 c0571bfc 00000000 c0505bc8 ef7fc918 00000089 c0034c6c
5f40: c04ca680 c0505338 00000006 00000006 00000000 c054e2c8 c054e2cc 00000006
5f60: c054e2ac c059f280 00000089 c052a4fc 00000000 c052ac4c 00000006 00000006
5f80: c052a4fc c003e0dc 00000000 c03b46ec 00000000 00000000 00000000 00000000
5fa0: 00000000 c03b46f4 00000000 c000e4b8 00000000 00000000 00000000 00000000
5fc0: 0000000000000000 00000000 00000000 00000000 00000000 00000000 00000000
5fe0: 00000000 00000000 00000000 00000000 00000013 00000000 ffffffff ffffffff
[<c0277cc8>] (dm9000_probe) from [<c0247f7c>] (platform_drv_probe+0x18/0x48) | 这一部显示是函数执行错误
[<c0247f7c>] (platform_drv_probe) from [<c0246668>] (driver_probe_device+0x100/0x210) | 往上看 报错提示
[<c0246668>] (driver_probe_device) from [<c0246804>] (__driver_attach+0x8c/0x90) |oops内核中内存使用错误
[<c0246804>] (__driver_attach) from [<c0244fbc>] (bus_for_each_dev+0x58/0x88)
[<c0244fbc>] (bus_for_each_dev) from [<c0245e28>] (bus_add_driver+0xd8/0x1cc)
[<c0245e28>] (bus_add_driver) from [<c0246e1c>] (driver_register+0x78/0xf4)
[<c0246e1c>] (driver_register) from [<c00087b4>] (do_one_initcall+0x30/0x144)
[<c00087b4>] (do_one_initcall) from [<c052ac4c>] (kernel_init_freeable+0xfc/0x1c8)
[<c052ac4c>] (kernel_init_freeable) from [<c03b46f4>] (kernel_init+0x8/0xe4)
两种方法
1、反汇编 objdump -D vmlinux 查找 pc : [<c0277cc8>]
2、 addr2line 0xc0277cc8 -e vmlinux -f (在编译后的linux源码目录下执行)
pc寄存器地址值 指明是执行程序 进行显示
书写位置及现象
[email protected]:~/sys/linux-3.14$ addr2line 0xc0277cc8 -e vmlinux -f
usb_set_configuration
/home/lf/sys/linux-3.14/drivers/usb/core/message.c:1846
内核调试方法:
1、点灯
在汇编阶段,串口输出,只能使用点灯的方式提示一些信息
2、打印
必须在串口输出后
内核解压前
putstr
console初始化前
printascii
内核解压后
信息输出显示是在 console 初始化之后
printk
369 printk(KERN_INFO "VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",s->s_type->name,
s->s_flags & MS_RDONLY ? " readonly" : "",MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
kernel/printk/printk.c
1674 asmlinkage int printk(const char *fmt, ...)
KERN_INFO 打印级别
字符串拼接 + 格式化输出
重点关注打印级别
printk打印级别 0-7 随着数字的减小,需要打印信息越重要
终端输出级别 1-7
proc/sys/kernel/printk
4 4 1 7
当前终端输出级别 默认级别 最小终端级别 最大终端级别
如果当前打印级别小于终端输出级别,进行打印,反之,不打印
对应数字级别
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>” /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant condition */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages
文件系统
根文件系统:是存放运行、维护系统所必须的各种工具软件、库文件、脚本、配置文件和其他特殊文件的地方,也可以安装各种软件包,已经提供交互
linux/unix文件系统设计是以树形结构来完成文件系统设计
文件系统标准
1. 文件系统中每个区域的用途
2. 所需要的最小构成的文件和目录
文件系统目录结构
bin(可执行程序) dev(设备文件) etc(配置文件) lib(库文件) linuxrc(文件系统启动的第一个文件) mnt(挂载点) proc(挂载点) root(root用户相关内容) sbin(super bin) sys(挂载点) tmp(挂载点) usr(普通用户相关内容) var(可变的 日志文件)
此目录结构是当前的标准目录结构,但是不是最小的目录结构
最小目录结构
bin linuxrc sbin usr etc lib dev
文件系统的制作
使用工具:busybox
1、配置 交叉编译工具链(arm-none-linux-gnueabi-) 在busybox目录下
2、添加内核支持 (linux 3.14中执行make menuconfig 添加文件系统格式支持)
3、进行编译 (make)
就是生成了要添加在bin等目录下的可执行程序 busybox帮咱们制作好了linux系统使用的通用命令
4、make _install 将编译生成的文件 放在指定目录中 _install
在目录下生成了/bin linuxrc /sbin /usr
5、根据FHS标准完成了目录的创建
6、添加库支持,库来源于交叉编译工具链
7、删除链接库和符号表(瘦身) 完成lib库瘦身 为了后面制作ramdisk.img(10M)准备
du -mh lib/ 查看lib的大小
8、添加系统启动的配置文件
需要添加关于文件系统启动配置
etc/
├── fstab 挂载点的配置
├── init.d
│ └── rcS 自启动脚本
├── inittab 启动文件
└── profile 前置文件(变量的赋值)
fstab(添加内核子系统的挂载点,仅仅是挂载点的确定,只是列表)
1 #device mount-point type options dump fsck order
2 proc /proc proc defaults 0 0
3 tmpfs /tmp tmpfs defaults 0 0
4 sysfs /sys sysfs defaults 0 0
5 tmpfs /dev tmpfs defaults 0 0
inittab(系统启动相关文件)
1 ::sysinit:/etc/init.d/rcS 系统启动执行脚本 --> /etc/init.d/rcS
2 ::askfirst:-/bin/sh 第一个启动文件类型
3 ::restart:/sbin/init 重启文件系统执行程序 /sbin/init (init进程)
4 ::ctrlaltdel:/sbin/reboot ctrl + alt + del 执行reboot程序 重启
init.d/rcS(系统启动脚本)
#!/bin/sh
bin/mount -a 挂载的就是fstab中类型与挂载点
echo /sbin/mdev > /proc/sys/kernel/hotplug hotplug 热插拔 /proc/sys/kernel/hotplug就是管道 就是将mdev定向到管道中
/sbin/mdev -s 执行后生效热插拔机制
产品化后需要随着系统启动执行的命令可以添加到该文件中
profile(添加了一些环境变量)
1 #!/bin/sh
2 export HOSTNAME=farsight
3 export USER=root
4 export HOME=root
7 export PS1="[[email protected]$HOSTNAME \W]\# "
8 PATH=/bin:/sbin:/usr/bin:/usr/sbin
9 LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
10 export PATH LD_LIBRARY_PATH
PS1 = [[email protected] ] 进入文件系统后 登录后显示的用户名
PATH指的就是当前所有可执行程序与命令的路径
LD_LIBRARY_PATH指的就是库的路径
rootfs(没有压缩过的) 进行nfs挂载
ramdisk文件系统:文件系统的镜像,就是压缩包 (rootfs进行压缩,目的是存入flash中) 进行从emmc中启动
sudo mount -t ext2 ramdisk /mnt/initrd 往挂载目录中拷贝就是往ramdisk中拷贝
挂载 文件系统格式 dd的空文件 挂载目录
mkimage -n "ramdisk" -A arm -O linux -T ramdisk -C gzip -d ramdisk.gz ramdisk.img 就是为了变成uboot能够识别的格式