Linux内核分析误区:陷入细节而忽略框架。看代码前应该了解框架,心中带着框架再研究代码,在具体代码的研究中修正自己的认识偏差和误差。
一、计算机系统
计算机系统整体抽象视图如上,系统粗略分为 4 个组件:
● 硬件:CPU、内存、IO设备
● 操作系统
● 软件
● 用户
二、操作系统定义
操作系统(operating system)是管理计算机硬件与软件资源的程序。操作系统用于分离软件和硬件,因此,操作系统向下管理硬件,向上为软件提供操作接口。
三、操作系统功能
操作系统主要功能:
● 进程管理
● 内存管理
● 设备管理
● ……
四、系统调用
操作系统提供的供所有系统调用的程序接口集合;用户程序通常只在用户态下运行,当用户程序想要调用只能在内核态运行的子程序时,所以操作系统需要提供访问这些内核态运行的程序的接口,这些接口的集合就叫做系统调用,简要的说,系统调用是内核向用户进程提供服务的唯一方法。
用户程序通过系统调用从用户态(user mode)切换到核心态(kernel mode ),从而可以访问相应的资源。这样做的好处是:
- 为用户空间提供了一种硬件的抽象接口,使编程更加容易。
- 有利于系统安全。
- 有利于每个进程度运行在虚拟系统中,接口统一有利于移植。
五、系统调用类型
系统调用大致可分为六类:
- 进程控制
- 文件管理
- 设备管理
- 信息维护
- 通信
- 保护
六、操作系统调试
广义而言,调试是查找和更正系统(包括硬件和软件)错误。调试也包括性能优化,即通过解决处理瓶颈而改善性能。
七、linux下程序调试方法
调试工具能让我们能够监测、控制和纠正正在运行的程序。我们在运行一些程序的时候,可能被卡住或出现错误,或者运行过程或结果,没能如我们预期,此时,最迫切需要明白究竟发生了什么。为了修复程序,剖析和了解程序运行的细节, 调试工具就成为了我们的必备工具,工于善其事,必先利其器。在Linux下的用户空间调试工具主要有系统工具和专门调试工具:‘print’ 打印语句,这是新手最常用的,也是最不提倡使用的;查询 (/proc, /sys 等)系统的虚拟文件查看,这个方法有局限性;跟踪 (strace/ltrace)工具使用这个比较普遍,值得提倡;Valgrind (memwatch)内存排除工具,在内存排除方面比较独到,是内存排错的法宝;GDB大名鼎鼎的程序调试工具,这个是个全能的工具,没有完不成的,只有你不知道的。
1.‘print’ 语句
这是一个基本的调试问题的方法。 我们在程序中怀疑的地方插入print语句来了解程序的运行流程控制流和变量值的改变。 这是一个最简单的技术, 它的缺点。 需要进行程序编辑,添加’print’语句,必须重新编译,重新运行来获得输出。若需要调试的程序比较大,这将是一个耗时费力的方法。
2. 查询
在某些情况下,我们需要弄清楚在一个运行在内核中的进程的状态和内存映射。为了获得这些信息,我们不需要在内核中插入任何代码。 相反,可以用 /proc 文件系统。在 /proc的伪文件系统,保留系统启动运行就收集的运行时信息 (cpu信息, 内存容量等)。
ls -l /proc’的输出结果,通过对 系统中运行的每一个进程在/proc文件系统中有一个以进程id命名的项。每个进程的细节信息可以在进程id对应的目录下的文件中获得。也可以’ls /proc/pid’的输出
解释/proc文件系统内的所有条目超出了本文的范围。一些有用的列举如下:
/proc/cmdline
-> 内核命令行
/proc/cpuinfo
-> 关于处理器的品牌,型号信息等
/proc/filesystems
-> 文件系统的内核支持的信息
/proc/<pid>/cmdline
-> 命令行参数传递到当前进程
/proc/<pid>/mem
-> 当前进程持有的内存
/proc/<pid>/status
-> 当前进程的状态
3. 跟踪
strace 的和 ltrace是两个在Linux中用来追踪程序的执行细节的跟踪工具。
4. Valgrind
Valgrind是一套调试和分析工具。它的一个被广泛使用的默认工具——‘Memcheck’——可以拦截malloc(),new(),free()和delete()调用。换句话说,它在检测下面这些问题非常有用:
- 内存泄露
- 重释放
- 访问越界
- 使用未初始化的内存
- 使用已经被释放的内存等。
它直接通过可执行文件运行。
Valgrind也有一些缺点,因为它增加了内存占用,会减慢你的程序。它有时会造成误报和漏报。它不能检测出静态分配的数组的访问越界问题。
5. GDB
GDB是来自自由软件基金会的调试器。它对定位和修复代码中的问题很有帮助。当被调试的程序运行时,它给用户控制权去执行各种动作, 比如:
- 启动程序
- 停在指定位置
- 停在指定的条件
- 检查所需信息
- 改变程序中的数据 等。
你也可以将一个崩溃的程序coredump附着到GDB并分析故障的原因。
6、总结
在这篇文章中,我们已经看到不同类型的Linux用户空间的调试工具。总结以上所有内容,如下是什么时候使用该什么的快速指南:
- 基本调试,获得关键变量 - print 语句
- 获取有关文件系统支持,可用内存,CPU,运行程序的内核状态等信息 - 查询 /proc 文件系统
- 最初的问题诊断,系统调用或库调用的相关问题,了解程序流程 – strace / ltrace
- 应用程序内存空间的问题 – valgrind
- 检查应用程序运行时的行为,分析应用程序崩溃 – gdb