GDB 调试技巧集锦
目录1. 将代码地址映射到代码行2. 显示源码3. 多窗口调试4. 映照汇编代码和源代码
1. 将代码地址映射到代码行
编译代码时需带上 -g 选项。如 Linux 内核开启了 CONFIG_DEBUG_INFO (即编译时带上 -g 选项),然后可以通过 addr2line 工具将代码地址映射到代码行:
$ arm-linux-gnueabi-addr2line -e output/kernel/sched/fair.o 0x204
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7045
# 0x809008e0 为 start_kernel 的链接地址,可以从 System.map 中查找到
$ arm-linux-gnueabi-addr2line -e output/vmlinux 0x809008e0
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../init/main.c:514
2. 显示源码
以 Linux 内核的调试为例进行说明。注意,需要开启内核的 CONFIG_DEBUG_INFO 配置,即为内核生成调试信息:
# linux/Makefile
ifdef CONFIG_DEBUG_INFO
ifdef CONFIG_DEBUG_INFO_SPLIT
KBUILD_CFLAGS += $(call cc-option, -gsplit-dwarf, -g)
else
KBUILD_CFLAGS += -g
endif
KBUILD_AFLAGS += -Wa,-gdwarf-2
endif
ifdef CONFIG_DEBUG_INFO_DWARF4
KBUILD_CFLAGS += $(call cc-option, -gdwarf-4,)
endif
list 命令输出当前调试附近的源代码:
$ gdb-multiarch output/kernel/sched/fair.o
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
Find the GDB manual and other documentation resources online at:
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from output/kernel/sched/fair.o...done.
(gdb) list *0x228
0x228 is in task_h_load (../kernel/sched/fair.c:7018).
7013 struct rq *rq = rq_of(cfs_rq);
7014 struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)];
7015 unsigned long now = jiffies;
7016 unsigned long load;
7017
7018 if (cfs_rq->last_h_load_update == now)
7019 return;
7020
7021 cfs_rq->h_load_next = NULL;
7022 for_each_sched_entity(se) {
(gdb)
或者类似的,用 gdb 加载 vmlinux:
$ arm-linux-gdb vmlinux
GNU gdb (ctng-1.21.0-229g-FA) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-build_pc-linux-gnu --target=arm-cortexa9-linux-gnueabihf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
Find the GDB manual and other documentation resources online at:
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from vmlinux...done.
(gdb) list *(run_init_process+0x38)
0xc0201bf8 is in try_to_run_init_process (init/main.c:948).
943 (const char __user *const __user *)argv_init,
944 (const char __user *const __user *)envp_init);
945 }
946
947 static int try_to_run_init_process(const char *init_filename)
948 {
949 int ret;
950
951 ret = run_init_process(init_filename);
952
(gdb)
3. 多窗口调试
命令组合 layout split + list 可以开启多窗口(汇编 + 源代码)调试。
$ gdb-multiarch output/kernel/sched/fair.o
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
Find the GDB manual and other documentation resources online at:
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from output/kernel/sched/fair.o...done.
(gdb) layout split
4. 映照汇编代码和源代码
用 gdb 调试汇编代码的时候,可能需要将汇编代码对应到源代码的行数。虽然 addr2line 可以达到目的,但一个一个地址去映射,然后再去看源代码文件,很繁琐,这时可通过 objdump 来对应汇编及地址到源码行,如反汇编 Linux 内核函数 task_h_load() 函数。首先从 System.map 查找函数的地址:
8014a6d4 t task_h_load
8014a7f0 t __calc_delta
然后反汇编:
$ arm-linux-gnueabi-objdump -dSl --start-address=0x8014a6d4 --stop-address=0x8014a7f0 vmlinux > task_h_load.S
$ cat task_h_load.S
output/vmlinux: file format elf32-littlearm
Disassembly of section .text:
8014a6d4
task_h_load():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7045
cfs_rq->last_h_load_update = now;
}
}
static unsigned long task_h_load(struct task_struct *p)
{
8014a6d4: e92d41f0 push {r4, r5, r6, r7, r8, lr}
update_cfs_rq_h_load():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7015
*/
static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq)
{
struct rq *rq = rq_of(cfs_rq);
struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)];
unsigned long now = jiffies;
8014a6d8: e3023d00 movw r3, #11520 ; 0x2d00
task_cfs_rq():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:287
#define for_each_sched_entity(se) \
for (; se; se = se->parent)
static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
{
return p->se.cfs_rq;
8014a6dc: e59050d0 ldr r5, [r0, #208] ; 0xd0
update_cfs_rq_h_load():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7015
*/
static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq)
{
struct rq *rq = rq_of(cfs_rq);
struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)];
unsigned long now = jiffies;
8014a6e0: e34830a0 movt r3, #32928 ; 0x80a0
task_h_load():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7045
cfs_rq->last_h_load_update = now;
}
}
static unsigned long task_h_load(struct task_struct *p)
{
8014a6e4: e1a08000 mov r8, r0
update_cfs_rq_h_load():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7018
struct rq *rq = rq_of(cfs_rq);
struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)];
unsigned long now = jiffies;
unsigned long load;
if (cfs_rq->last_h_load_update == now)
8014a6e8: e3a07000 mov r7, #0
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7015
*/
static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq)
{
struct rq *rq = rq_of(cfs_rq);
struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)];
unsigned long now = jiffies;
8014a6ec: e5936000 ldr r6, [r3]
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7018
unsigned long load;
if (cfs_rq->last_h_load_update == now)
8014a6f0: e1c529d0 ldrd r2, [r5, #144] ; 0x90
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7014
* group is a fraction of its parents load.
*/
static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq)
{
struct rq *rq = rq_of(cfs_rq);
struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)];
8014a6f4: e59500ac ldr r0, [r5, #172] ; 0xac
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7018
unsigned long now = jiffies;
unsigned long load;
if (cfs_rq->last_h_load_update == now)
8014a6f8: e1530007 cmp r3, r7
cpu_of():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/sched.h:823
};
static inline int cpu_of(struct rq *rq)
{
#ifdef CONFIG_SMP
return rq->cpu;
8014a6fc: e595109c ldr r1, [r5, #156] ; 0x9c
update_cfs_rq_h_load():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7018
8014a700: 01520006 cmpeq r2, r6
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7014
* group is a fraction of its parents load.
*/
static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq)
{
struct rq *rq = rq_of(cfs_rq);
struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)];
8014a704: e5903068 ldr r3, [r0, #104] ; 0x68
8014a708: e5912518 ldr r2, [r1, #1304] ; 0x518
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7018
unsigned long now = jiffies;
unsigned long load;
if (cfs_rq->last_h_load_update == now)
8014a70c: 0a00002c beq 8014a7c4
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7014
* group is a fraction of its parents load.
*/
static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq)
{
struct rq *rq = rq_of(cfs_rq);
struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)];
8014a710: e7934102 ldr r4, [r3, r2, lsl #2]
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7021
unsigned long load;
if (cfs_rq->last_h_load_update == now)
return;
cfs_rq->h_load_next = NULL;
8014a714: e3a03000 mov r3, #0
8014a718: e5853098 str r3, [r5, #152] ; 0x98
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7022
for_each_sched_entity(se) {
8014a71c: e1540003 cmp r4, r3
8014a720: 1a000003 bne 8014a734
8014a724: ea00002d b 8014a7e0
8014a728: e594404c ldr r4, [r4, #76] ; 0x4c
8014a72c: e3540000 cmp r4, #0
8014a730: 0a00001b beq 8014a7a4
cfs_rq_of():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:293
}
/* runqueue on which this entity is (to be) queued */
static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
{
return se->cfs_rq;
8014a734: e594c050 ldr ip, [r4, #80] ; 0x50
update_cfs_rq_h_load():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7025
cfs_rq->h_load_next = NULL;
for_each_sched_entity(se) {
cfs_rq = cfs_rq_of(se);
cfs_rq->h_load_next = se;
if (cfs_rq->last_h_load_update == now)
8014a738: e1cc29d0 ldrd r2, [ip, #144] ; 0x90
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7024
return;
cfs_rq->h_load_next = NULL;
for_each_sched_entity(se) {
cfs_rq = cfs_rq_of(se);
cfs_rq->h_load_next = se;
8014a73c: e58c4098 str r4, [ip, #152] ; 0x98
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7025
if (cfs_rq->last_h_load_update == now)
8014a740: e1570003 cmp r7, r3
8014a744: 01560002 cmpeq r6, r2
8014a748: 1afffff6 bne 8014a728
8014a74c: e59c2088 ldr r2, [ip, #136] ; 0x88
8014a750: e59c1058 ldr r1, [ip, #88] ; 0x58
8014a754: ea000000 b 8014a75c
8014a758: e5931058 ldr r1, [r3, #88] ; 0x58
div_u64_rem():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../include/linux/math64.h:67
#define div64_ul(x, y) div_u64((x), (y))
#ifndef div_u64_rem
static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
{
*remainder = do_div(dividend, divisor);
8014a75c: e5940098 ldr r0, [r4, #152] ; 0x98
8014a760: e2811001 add r1, r1, #1
8014a764: e0000290 mul r0, r0, r2
8014a768: eb145de2 bl 80661ef8 <__aeabi_uidiv>
group_cfs_rq():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:299
}
/* runqueue "owned" by this group */
static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
{
return grp->my_q;
8014a76c: e5943054 ldr r3, [r4, #84] ; 0x54
update_cfs_rq_h_load():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7034
if (!se) {
cfs_rq->h_load = cfs_rq_load_avg(cfs_rq);
cfs_rq->last_h_load_update = now;
}
while ((se = cfs_rq->h_load_next) != NULL) {
8014a770: e5934098 ldr r4, [r3, #152] ; 0x98
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7040
load = cfs_rq->h_load;
load = div64_ul(load * se->avg.load_avg,
cfs_rq_load_avg(cfs_rq) + 1);
cfs_rq = group_cfs_rq(se);
cfs_rq->h_load = load;
cfs_rq->last_h_load_update = now;
8014a774: e1c369f0 strd r6, [r3, #144] ; 0x90
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7034
if (!se) {
cfs_rq->h_load = cfs_rq_load_avg(cfs_rq);
cfs_rq->last_h_load_update = now;
}
while ((se = cfs_rq->h_load_next) != NULL) {
8014a778: e3540000 cmp r4, #0
8014a77c: e1a02000 mov r2, r0
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7039
load = cfs_rq->h_load;
load = div64_ul(load * se->avg.load_avg,
cfs_rq_load_avg(cfs_rq) + 1);
cfs_rq = group_cfs_rq(se);
cfs_rq->h_load = load;
8014a780: e5830088 str r0, [r3, #136] ; 0x88
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7034
if (!se) {
cfs_rq->h_load = cfs_rq_load_avg(cfs_rq);
cfs_rq->last_h_load_update = now;
}
while ((se = cfs_rq->h_load_next) != NULL) {
8014a784: 1afffff3 bne 8014a758
8014a788: e5951058 ldr r1, [r5, #88] ; 0x58
task_h_load():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7049
static unsigned long task_h_load(struct task_struct *p)
{
struct cfs_rq *cfs_rq = task_cfs_rq(p);
update_cfs_rq_h_load(cfs_rq);
return div64_ul(p->se.avg.load_avg * cfs_rq->h_load,
8014a78c: e5983118 ldr r3, [r8, #280] ; 0x118
8014a790: e2811001 add r1, r1, #1
8014a794: e5950088 ldr r0, [r5, #136] ; 0x88
8014a798: e0000390 mul r0, r0, r3
8014a79c: eb145dd5 bl 80661ef8 <__aeabi_uidiv>
8014a7a0: e8bd81f0 pop {r4, r5, r6, r7, r8, pc}
8014a7a4: e59c4098 ldr r4, [ip, #152] ; 0x98
cfs_rq_load_avg():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:3542
return cfs_rq->runnable_load_avg;
}
static inline unsigned long cfs_rq_load_avg(struct cfs_rq *cfs_rq)
{
return cfs_rq->avg.load_avg;
8014a7a8: e59c1058 ldr r1, [ip, #88] ; 0x58
update_cfs_rq_h_load():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7034
if (!se) {
cfs_rq->h_load = cfs_rq_load_avg(cfs_rq);
cfs_rq->last_h_load_update = now;
}
while ((se = cfs_rq->h_load_next) != NULL) {
8014a7ac: e3540000 cmp r4, #0
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7031
break;
}
if (!se) {
cfs_rq->h_load = cfs_rq_load_avg(cfs_rq);
cfs_rq->last_h_load_update = now;
8014a7b0: e1cc69f0 strd r6, [ip, #144] ; 0x90
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7030
if (cfs_rq->last_h_load_update == now)
break;
}
if (!se) {
cfs_rq->h_load = cfs_rq_load_avg(cfs_rq);
8014a7b4: e58c1088 str r1, [ip, #136] ; 0x88
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7034
cfs_rq->last_h_load_update = now;
}
while ((se = cfs_rq->h_load_next) != NULL) {
8014a7b8: 0afffff2 beq 8014a788
cfs_rq_load_avg():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:3542
return cfs_rq->runnable_load_avg;
}
static inline unsigned long cfs_rq_load_avg(struct cfs_rq *cfs_rq)
{
return cfs_rq->avg.load_avg;
8014a7bc: e1a02001 mov r2, r1
8014a7c0: eaffffe5 b 8014a75c
task_h_load():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7049
static unsigned long task_h_load(struct task_struct *p)
{
struct cfs_rq *cfs_rq = task_cfs_rq(p);
update_cfs_rq_h_load(cfs_rq);
return div64_ul(p->se.avg.load_avg * cfs_rq->h_load,
8014a7c4: e5980118 ldr r0, [r8, #280] ; 0x118
8014a7c8: e5953088 ldr r3, [r5, #136] ; 0x88
8014a7cc: e5951058 ldr r1, [r5, #88] ; 0x58
8014a7d0: e0000390 mul r0, r0, r3
8014a7d4: e2811001 add r1, r1, #1
8014a7d8: eb145dc6 bl 80661ef8 <__aeabi_uidiv>
8014a7dc: e8bd81f0 pop {r4, r5, r6, r7, r8, pc}
update_cfs_rq_h_load():
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7030
if (cfs_rq->last_h_load_update == now)
break;
}
if (!se) {
cfs_rq->h_load = cfs_rq_load_avg(cfs_rq);
8014a7e0: e5951058 ldr r1, [r5, #88] ; 0x58
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7031
cfs_rq->last_h_load_update = now;
8014a7e4: e1c569f0 strd r6, [r5, #144] ; 0x90
/home/lxj/Work/qemu-lab/linux-4.14.111/output/../kernel/sched/fair.c:7030
if (cfs_rq->last_h_load_update == now)
break;
}
if (!se) {
cfs_rq->h_load = cfs_rq_load_avg(cfs_rq);
8014a7e8: e5851088 str r1, [r5, #136] ; 0x88
8014a7ec: eaffffe6 b 8014a78c