今天在调试内核的时候, 发现一个变量指针在一个函数中变了, 但是代码中又没有改变他的值
(gdb) p sc
$13 = (struct scan_control *) 0xffffc900079b3da8
(gdb) n
(gdb) p sc
$14 = (struct scan_control *) 0xffff880a4c55a800
根据以往的经验, 肯定是gcc的debuginfo又不对了, 因为以前干过这种事情
(从一个地方看来的, 没有求证过, gcc每次编译完会自检
一共编译3边, 同一份源代码, 系统gcc产生gcc1, gcc1产生gcc2, gcc2产生gcc3
gcc1和gcc2的二进制可能会不一样, 虽然源代码一样, 但是编译器不一样
gcc2和gcc3的二进制肯定会一样, 源代码一样, 编译器的二进制不一样, 但是编译器的行为是一样的
所以自检只会检查代码正确性, 不会检查到debuginfo)
源代码
用了O0函数属性
__attribute__((optimize("-O0"))) static bool kswapd_shrink_node(pg_data_t *pgdat,
struct scan_control *sc)
{
struct zone *zone;
int z;
sc->nr_to_reclaim = 0;
............
return sc->nr_scanned >= sc->nr_to_reclaim;
}
检查汇编
00000000000074d0 <kswapd_shrink_node>:
74d0: e8 00 00 00 00 callq 74d5 <kswapd_shrink_node+0x5>
74d5: 55 push %rbp
74d6: 48 89 e5 mov %rsp,%rbp
74d9: 53 push %rbx
74da: 48 83 ec 38 sub $0x38,%rsp
74de: 48 89 7d c8 mov %rdi,-0x38(%rbp) pgdat没错, 是O0, 把参数保存成局部变量
74e2: 48 89 75 c0 mov %rsi,-0x40(%rbp) sc
74e6: 65 48 8b 04 25 28 00 mov %gs:0x28,%rax
检查debuginfo
#objdump --dwarf=info mm/vmscan.o |grep kswapd_shrink_node -A 25
<26545> DW_AT_name : (indirect string, offset: 0xe966): kswapd_shrink_node
<26549> DW_AT_decl_file : 1
<2654a> DW_AT_decl_line : 3190
<2654c> DW_AT_prototyped : 1
<2654c> DW_AT_type : <0x25e>
<26550> DW_AT_low_pc : 0x74d0
<26558> DW_AT_high_pc : 0x144
<26560> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa)
<26562> DW_AT_GNU_all_call_sites: 1
<26562> DW_AT_sibling : <0x26636>
<2><26566>: Abbrev Number: 110 (DW_TAG_formal_parameter)
<26567> DW_AT_name : (indirect string, offset: 0xa7ed): pgdat
<2656b> DW_AT_decl_file : 1
<2656c> DW_AT_decl_line : 3190
<2656e> DW_AT_type : <0xf0d8>
<26572> DW_AT_location : 1 byte block: 55 (DW_OP_reg5 (rdi)) debuginfo居然还是rdi
<2><26574>: Abbrev Number: 140 (DW_TAG_formal_parameter)
<26576> DW_AT_name : sc
<26579> DW_AT_decl_file : 1
<2657a> DW_AT_decl_line : 3191
<2657c> DW_AT_type : <0x13f59>
<26580> DW_AT_location : 1 byte block: 54 (DW_OP_reg4 (rsi)) 同样的问题
<2><26582>: Abbrev Number: 119 (DW_TAG_variable)
看起来是gcc的问题, 因为cmdline里面是O2, 但是文件里面是O0, 所以代码按照O0来生成, 但是debuginfo用O2的来生成
网上暂时没找到方法解决, 估计这样用的人比较少
看起来cmdline要用O0来能让gcc避免这个bug, 但是O0又编译不了vmscan.c, 所以最后只能这样用
cmdline先执行O0, 然后把O2的那些选项手动得加上, 这样才避免这个gcc bug
<1f268> DW_AT_name : (indirect string, offset: 0xe812): kswapd_shrink_node
<1f26c> DW_AT_decl_file : 56
<1f26d> DW_AT_decl_line : 3190
<1f26f> DW_AT_prototyped : 1
<1f26f> DW_AT_type : <0x25e>
<1f273> DW_AT_low_pc : 0xcf63
<1f27b> DW_AT_high_pc : 0x136
<1f283> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa)
<1f285> DW_AT_GNU_all_tail_call_sites: 1
<1f285> DW_AT_sibling : <0x1f2f5>
<2><1f289>: Abbrev Number: 91 (DW_TAG_formal_parameter)
<1f28a> DW_AT_name : (indirect string, offset: 0xa673): pgdat
<1f28e> DW_AT_decl_file : 56
<1f28f> DW_AT_decl_line : 3190
<1f291> DW_AT_type : <0xf434>
<1f295> DW_AT_location : 3 byte block: 91 b8 7f (DW_OP_fbreg: -72)这样就没有问题了
<2><1f299>: Abbrev Number: 96 (DW_TAG_formal_parameter)
<1f29a> DW_AT_name : sc
<1f29d> DW_AT_decl_file : 56
<1f29e> DW_AT_decl_line : 3191
<1f2a0> DW_AT_type : <0x1aae2>
<1f2a4> DW_AT_location : 3 byte block: 91 b0 7f (DW_OP_fbreg: -80)
<2><1f2a8>: Abbrev Number: 92 (DW_TAG_variable)
<1f2a9> DW_AT_name : (indirect string, offset: 0xb7ce): zone
<1f2ad> DW_AT_decl_file : 56
<1f2ae> DW_AT_decl_line : 3193