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

Copyright © 2088 海豹复古游戏中心-经典怀旧服专题站 All Rights Reserved.
友情链接
Top