转自:http://blog.csdn.net/larryliuqing/article/details/8674274

http://lenky.info/2013/03/10/%E5%A6%82%E4%BD%95%E7%A6%81%E6%AD%A2linux%E5%86%85%E6%A0%B8%E7%9A%84-o2%E7%BC%96%E8%AF%91%E9%80%89%E9%A1%B9/

已有各种工具可以帮助我们调试内核,比如UML、kgdb、qemu等,但比较麻烦的是gdb经常给我一个“value optimized out”的提示,而且执行的路径与gdb的显示也不对应,最近我在利用UML调试ext3文件系统的逻辑时就为此而感到非常麻烦(2.6.30.8的内核):

1
2
3
4
5
Breakpoint 1, journal_invalidatepage (journal=0x6c4bd800, page=0x61918b28, offset=0) at fs/jbd/transaction.c:2036
2036    {
(gdb) p bh
$2 = <value optimized out>
(gdb)

这应该是因为Linux内核打开gcc的-O2选项优化导致,于是我尝试修改内核Makefile文件(/usr/src/uml/linux-2.6.30.8/Makefile):

1
2
3
4
5
ifdef
CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS  
+= -Os
else
KBUILD_CFLAGS  
+= -O2
endif

改为这样(CONFIG_CC_OPTIMIZE_FOR_SIZE可以通过内核选项:General setup —> [ ] Optimize for size,进行开启/关闭,这里不管该选项而也就统一改了):

1
2
3
4
5
ifdef
CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS  
+= -O0
else
KBUILD_CFLAGS  
+= -O0
endif

执行编译,gcc给了我一个华丽的错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@lenky
linux-2.6.30.8]# make ARCH=um -B V=1
...
mm/built-in.o:
In function `index_of':
/usr/src/uml/linux-2.6.30.8/mm/slab.c:341:
undefined reference to `__bad_size'
/usr/src/uml/linux-2.6.30.8/mm/slab.c:341:
undefined reference to `__bad_size'
/usr/src/uml/linux-2.6.30.8/mm/slab.c:341:
undefined reference to `__bad_size'
/usr/src/uml/linux-2.6.30.8/mm/slab.c:341:
undefined reference to `__bad_size'
/usr/src/uml/linux-2.6.30.8/mm/slab.c:341:
undefined reference to `__bad_size'
mm/built-in.o:/usr/src/uml/linux-2.6.30.8/mm/slab.c:341:
more undefined references to `__bad_size' follow
collect2:
ld returned 1
exit

status
  KSYM   
.tmp_kallsyms1.S
nm:
'.tmp_vmlinux1':
No such file
No
valid symbol.
make:
*** [.tmp_kallsyms1.S] Error 1

根据上面的提示信息,我尝试把文件slab.c的编译选项调为-O2,即编辑mm/Makefile文件,在最后加上如下一行:

1
2
3
4
5
6
7
[root@lenky
linux-2.6.30.8]# vi mm/Makefile
[root@lenky
linux-2.6.30.8]# tail -n 5 mm/Makefile
endif
obj-$(CONFIG_QUICKLIST)
+= quicklist.o
obj-$(CONFIG_CGROUP_MEM_RES_CTLR)
+= memcontrol.o page_cgroup.o
 
CFLAGS_slab.o
= -O2

格式是:
CFLAGS_对应源文件[要去除通常意义上扩展名].o = gcc选项
所以上面加的是:
CFLAGS_slab.o = -O2

重新编译:

1
[root@lenky
linux-2.6.30.8]# make ARCH=um -B V=1

选项-B:以强制所有内核源文件全部重新编译(因为我前面编译过一次了,为了保险起见,就让目标文件全部重新生成吧)
选项V=1:显示详细的编译信息,而不再是简单的“CC init/main.o”。

编译出来的可执行程序linux比-O2的情况还小几M,一启动UML没多久,果然奔溃。

看来内核里有大量的底层代码在书写时只兼容了-O2选项,所以如果以-O0的形式强制编译会导致出错,这即便不在编译时报错,也有极大可能会在实际执行时候出错,完全关闭所有内核源文件的-O2编译选项的风险太大。

退而求次,我是为了调试journal_invalidatepage()函数,那么可以仅把对应源文件transaction.c的优化选项关闭即可,这个源文件的实现在比较高的层次,关闭优化选项应该不会出错。

编辑文件fs/jbd/Makefile,再其最后加上一行:
CFLAGS_transaction.o = -O0

重新编译(之前的其它改动需回滚)后启动UML,一切OK。

试试最开始的示例,用gdb绑定到UML主进程,调试函数journal_invalidatepage(),打印变量bh:

1
2
3
4
5
6
7
8
9
Breakpoint
1, journal_invalidatepage (journal=0x6c06e800, page=0x61502e30, offset=0) at fs/jbd/transaction.c:2038
2038       
unsigned
int

curr_off = 0;
(gdb)
p bh
$1
= (
struct

buffer_head *) 0x6bd5f0c8
(gdb)
p *bh
$2
= {b_state = 3211305, b_this_page = 0x6bd5f268, b_page = 0x61501fc0, b_blocknr = 263, b_size = 1024, b_data = 0x6a648c00
"",
  b_bdev
= 0x6bc02380, b_end_io = 0x600aa760 <end_buffer_async_write>, b_private = 0x6bdc46d8, b_assoc_buffers = {
    next
= 0x6bd5f110, prev = 0x6bd5f110}, b_assoc_map = 0x0, b_count = {counter = 2}}
(gdb)

嗯,效果不错。

另外Google到由teawater提供了对应的补丁对整个内核进行关闭-O2优化,有没有问题不知道,我暂没有测试:
http://sourceware.org/ml/gdb/2010-12/msg00009.html

PS:
错误:
arch/um/os-Linux/mem.c: In function ‘create_tmp_file’:
arch/um/os-Linux/mem.c:216: error: implicit declaration of function ‘fchmod’
make[1]: *** [arch/um/os-Linux/mem.o] Error 1
make: *** [arch/um/os-Linux] Error 2

编辑文件arch/um/os-Linux/mem.c,加入头文件:

1
#include
<sys/stat.h>

即可。

转载请保留地址:http://lenky.info/2013/03/10/%e5%a6%82%e4%bd%95%e7%a6%81%e6%ad%a2linux%e5%86%85%e6%a0%b8%e7%9a%84-o2%e7%bc%96%e8%af%91%e9%80%89%e9%a1%b9/ 或 http://lenky.info/?p=2238

如何禁止Linux内核的-O2编译选项【转】的更多相关文章

  1. Linux内核RCU(Read Copy Update)锁简析

    在非常早曾经,大概是2009年的时候.写过一篇关于Linux RCU锁的文章<RCU锁在linux内核的演变>,如今我承认.那个时候我尽管懂了RCU锁,可是我没有能力用一种非常easy的描 ...

  2. 用于阻止缓冲区溢出攻击的 Linux 内核参数与 gcc 编译选项

    先来看看基于 Red Hat 与 Fedora 衍生版(例如 CentOS)系统用于阻止栈溢出攻击的内核参数,主要包含两项: kernel.exec-shield 可执行栈保护,字面含义比较“绕”, ...

  3. Linux内核卸载和禁止更新

    注意:对于可以用好几条命令实现的,第一条命令已经验证,其他的命令参考自网上,没有进行验证. 查看Linux系统内核的命令有下面几条 dpkg --get-selections | grep linux ...

  4. Linux内核调试方法总结【转】

    转自:http://my.oschina.net/fgq611/blog/113249 内核开发比用户空间开发更难的一个因素就是内核调试艰难.内核错误往往会导致系统宕机,很难保留出错时的现场.调试内核 ...

  5. linux内核调试指南

    linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 ...

  6. 【转】Linux内核调试方法总结

    目录[-] 一  调试前的准备 二  内核中的bug 三  内核调试配置选项 1  内核配置 2  调试原子操作 四  引发bug并打印信息 1  BUG()和BUG_ON() 2  dump_sta ...

  7. Linux内核调试方法总结

    Linux内核调试方法总结 一  调试前的准备 二  内核中的bug 三  内核调试配置选项 1  内核配置 2  调试原子操作 四  引发bug并打印信息 1  BUG()和BUG_ON() 2   ...

  8. Linux Kernel - Debug Guide (Linux内核调试指南 )

    http://blog.csdn.net/blizmax6/article/details/6747601 linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级 ...

  9. 《Linux内核设计与实现》CHAPTER17阅读梳理

    <Linux内核设计与实现>CHAPTER17阅读梳理 [学习时间:3.5hours] [学习内容:设备类型,模块,内核对象,sysfs] 个人思考部分见[]标出的部分 一.课堂讲解整理& ...

随机推荐

  1. 20165218 《网络对抗技术》Exp1 逆向及Bof基础

    Exp1 逆向及Bof基础 基础知识 1. NOP, JNE, JE, JMP, CMP汇编指令的机器码 指令 机器码 NOP NOP指令即"空指令",在x86的CPU中机器码为0 ...

  2. mysql source导入多个sql文件

    mysql>use dbtest; mysql>set names utf8; mysql>source D:/mysql/all.sql; 通过source命令导入多个文件,可以新 ...

  3. codeforces div1 & div2 参与人员分数统计

    Analysis helps to see the nature of things.

  4. 把矩阵分成n*m个块,从任意一个块出发,问是否可以一笔画遍历矩阵中所有的块

  5. fcntl文件锁操作

    文件锁经常应用于两个方面:1.一是锁定文件中的临界数据,比如并发投票时文件记录的投票数2.二是利用具有互斥性质的写锁,实现进程的并发控制. /*使用文件锁*/<F5>#include &l ...

  6. 如何在servlet的监听器中使用spring容器的bean

    另外补充下:在web Server容器中,无论是Servlet,Filter,还是Listener都不是Spring容器管理的,因此我们都无法在这些类中直接使用Spring注解的方式来注入我们需要的对 ...

  7. python基础之模块之sys模块

    sys模块的功能 sys是python中较为常用的一个模块,他提供了对python脚本运行时的环境的操作. sys功能: 1  sys.argv     #将python脚本运行时的脚本名以及参数作为 ...

  8. linux 命令操作记录

    1.查找名为 migrations 的文件夹/文件,并删除 find . -name "migrations" -type d #查找当前目录下文件夹名为 migrations 的 ...

  9. 并发库应用之二 & Java原子性操作类应用

    Java5的线程并发库中,提供了一组atomic class来帮助我们简化同步处理.基本工作原理是使用了同步synchronized的方法实现了对一个long, integer, 对象的增.减.赋值( ...

  10. linux(ubuntu) mysql安装使用

    简单的安装一下: sudo apt-get install mysql-server apt-get isntall mysql-client sudo apt-get install libmysq ...