GDB 调试技巧集锦

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 <http://gnu.org/licenses/gpl.html>
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:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
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 <http://gnu.org/licenses/gpl.html>
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:
<http://www.friendlyarm.com/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
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 <http://gnu.org/licenses/gpl.html>
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:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
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

747115ac-10ae-4705-bc96-63444ee6d770

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>:
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 <task_h_load+0xf0>
/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 <task_h_load+0x60>
8014a724:	ea00002d 	b	8014a7e0 <task_h_load+0x10c>
8014a728:	e594404c 	ldr	r4, [r4, #76]	; 0x4c
8014a72c:	e3540000 	cmp	r4, #0
8014a730:	0a00001b 	beq	8014a7a4 <task_h_load+0xd0>
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 <task_h_load+0x54>
8014a74c:	e59c2088 	ldr	r2, [ip, #136]	; 0x88
8014a750:	e59c1058 	ldr	r1, [ip, #88]	; 0x58
8014a754:	ea000000 	b	8014a75c <task_h_load+0x88>
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 <task_h_load+0x84>
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 <task_h_load+0xb4>
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+0x88>
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 <task_h_load+0xb8>
posted @ 2025-08-20 14:12  JiMoKuangXiangQu  阅读(206)  评论(0)    收藏  举报