命令:b [函数名] if $_streq(函数参数可得到的变量名, "自己定义的字符串")
$_streq(str1, str2)是gdb的内置函数,用于判断两个字符串是否相等。
示例:读“fio”文件时设置断点:
(gdb) b __do_page_cache_readahead if $_streq(filp->f_path.dentry->d_name.name, "fio") Breakpoint 1 at 0xffffffff81179e60: file mm/readahead.c, line 156. (gdb) c ---------设置条件断点后,按C键继续执行 Continuing. (gdb) --------终端执行cat fio命令,触发断点 Breakpoint 1, __do_page_cache_readahead (mapping=0xffff88800610b9f0, filp=0xffff888005e8ed80, offset=0, nr_to_read=320, lookahead_size=160) at mm/readahead.c:156 156 struct inode *inode = mapping->host; |
类似的gdb内置函数还有:
$_memeq(buf1, buf2, length) | 内存值是否相同 |
$_regex(str, regex) | str中是否包含regex字符串(str2指定待匹配的字符串模式) |
$_strlen(str) | 求字符串长度 |
命令:b 变量表达式 if 条件
示例:在某一行满足某个条件时,设置断点
1630 /* preallocate blocks in batch for one dnode page */
Breakpoint 2, f2fs_map_blocks (inode=inode@entry=0xffff8880044cf878, map=map@entry=0xffffc90000267d88, create=create@entry=1, |
命令:watch 变量表达式 if 条件
watch命令配合bt命令,可用来检查变量值被什么代码改动了。
示例:检测page何时上锁示例:
(gdb) watch ((struct page *)0xffffea0000098b00)->flags if (((struct page *)0xffffea0000098b00)->flags & 0x01 == 1) (因为gcc优化了代码,无法直接访问page变量,这里直接访问page的内存地址来访问page成员。如果代码没有优化,可以简单地通过watch page->flags if (page->flags & 0x01 == 1)来设置断点。) 代码运行一段时间后触发断点 Hardware watchpoint 3: ((struct page *)0xffffea0000098b00)->flags Old value = 4611686018427387904----触发前page->flags的bit0=0 |
命令: x/内存单元数量格式字母内存单元长度 内存地址
内存单元数量 | repeat count,有多少个内存单元 | |
格式字母 | format letter,x命令的输出格式 | x(hex) d(decimal) u(unsigned decimal) t(binary) f(float) a(address) i(instruction) c(char) s(string) |
内存单元长度 | size letter,每个内存单元的长度 | b:1 byte h:2 bytes w:4 bytes g:8 bytes |
常用组合:
x/3cb-----输出3个char内存单元内容
x/4uw----输出4个unsigned int内存单元内容
示例:
- char data_buf[10];
- for (i = 0; i < 10; i++)
- data_buf[i] = 'a' + i;
-
- /* data_buf地址为0x7fffffffde4e */
示例:
(gdb) b page_cache_sync_readahead if $_streq(filp->f_path.dentry->d_name.name, "fio")
Breakpoint 3 at 0xffffffff8117a710: page_cache_sync_readahead. (2 locations)
(gdb) c
Continuing.
Error in testing breakpoint condition:
value has been optimized out
Breakpoint 3, page_cache_sync_readahead (req_size=
mapping=
527 if (filp && (filp->f_mode & FMODE_RANDOM)) { --------不满足条件断点触发条件,但是却能断住指定的函数,不符合预期。
原因:gcc优化了page_cache_sync_readahead ,gdb运行时没法检查函数参数值,导致即使不满足断点条件,gdb也会停在断点处。
解决:函数声明加上__attribute__((optimize("O0")))关键字。
void page_cache_sync_readahead(struct address_space *mapping,
struct file_ra_state *ra, struct file *filp,
pgoff_t offset, unsigned long req_size) __attribute__((optimize("O0")));
通过set var命令修改变量index的值。
命令格式: set var 变量=值
916行语句没有修改变量level的值,但是gdb p命令显示level值变了,这是由于局部变量index存放在寄存器$rax中导致的,p level显示的是rax中的值,这对代码功能没有影响,代码取level值时取的是level实际的值。
- (gdb) p level
- $3 = 1186560
- (gdb) n
- 916 dn->inode_page_locked = true;
- (gdb) p level
- $4 = 80680
-
- (gdb) p &level
- Address requested for identifier "level" which is in register $rax
如果想在gdb中正确显示level值,可以定义volatile关键字:
volatile int level;
这是编译器优化导致的。
解决方法:函数声明加上__attribute__((optimize("O0")))关键字。
使用__attribute__((optimize("O0")))关键字声明函数类型时,如果编译错误,大概率是因为函数中用到了一些复杂的宏,比如container_of(常见与list_entry、list_first_entry等)、do { xxx } while( xxx )宏。