Skip to content

Instantly share code, notes, and snippets.

@cuiwm
Last active June 8, 2017 03:31
Show Gist options
  • Save cuiwm/b5365a3a1b0826ef47d12427e25c0979 to your computer and use it in GitHub Desktop.
Save cuiwm/b5365a3a1b0826ef47d12427e25c0979 to your computer and use it in GitHub Desktop.
gdb useful command
from :https://blogs.oracle.com/ksplice/8-gdb-tricks-you-should-know
break WHERE if COND
(gdb) break context_switch if next == init_task
(gdb) command 1
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>print addr
>print len
>print prot
>end
(gdb)
If you just want to start a program under gdb, passing some arguments on the command line, you can just build your command-line like usual, and then put "gdb --args" in front to launch gdb with the target program and the argument list both set:
[~]$ gdb --args pizzamaker --deep-dish --toppings=pepperoni
(gdb) show args
Argument list to give program being debugged when it is started is " --deep-dish --toppings=pepperoni".
(gdb) b main
Breakpoint 1 at 0x45467c: file oven.c, line 123.
(gdb) run
[~/src]$ apt-get source coreutils
[~/src]$ sudo apt-get install coreutils-dbgsym
[~/src]$ gdb /bin/ls
GNU gdb (GDB) 7.1-ubuntu
(gdb) list main
1192 ls.c: No such file or directory.
in ls.c
(gdb) directory ~/src/coreutils-7.4/src/
Source directories searched: /home/nelhage/src/coreutils-7.4:$cdir:$cwd
(gdb) list main
1192 }
1193 }
1194
1195 int
1196 main (int argc, char **argv)
1197 {
1198 int i;
1199 struct pending *thispend;
1200 int n_files;
1201
Sometimes, however, debug symbols end up with absolute paths, such as the kernel's. In that case, I can use set substitute-path to tell gdb how to translate paths:
[~/src]$ apt-get source linux-image-2.6.32-25-generic
[~/src]$ sudo apt-get install linux-image-2.6.32-25-generic-dbgsym
[~/src]$ gdb /usr/lib/debug/boot/vmlinux-2.6.32-25-generic
(gdb) list schedule
5519 /build/buildd/linux-2.6.32/kernel/sched.c: No such file or directory.
in /build/buildd/linux-2.6.32/kernel/sched.c
(gdb) set substitute-path /build/buildd/linux-2.6.32 /home/nelhage/src/linux-2.6.32/
(gdb) list schedule
5519
5520 static void put_prev_task(struct rq *rq, struct task_struct *p)
5521 {
5522 u64 runtime = p->se.sum_exec_runtime - p->se.prev_sum_exec_runtime;
5523
5524 update_avg(&p->se.avg_running, runtime);
5525
5526 if (p->state == TASK_RUNNING) {
5527 /*
5528 * In order to avoid avg_overlap growing stale when we are
However, if you're willing to tell GCC to generate debug symbols specifically optimized for gdb, using -ggdb3, it can preserve this information:
$ make KCFLAGS=-ggdb3
...
(gdb) break schedule
(gdb) continue
(gdb) p/x GFP_ATOMIC
$1 = 0x20
(gdb) p task_is_stopped_or_traced(init_task)
$2 = 0
You can also use the macro and info macro commands to work with macros from inside your gdb session:
(gdb) macro expand task_is_stopped_or_traced(init_task)
expands to: ((init_task->state & (4 | 8)) != 0)
(gdb) info macro task_is_stopped_or_traced
Defined at include/linux/sched.h:218
included at include/linux/nmi.h:7
included at kernel/sched.c:31
#define task_is_stopped_or_traced(task) ((task->state & (__TASK_STOPPED | __TASK_TRACED)) != 0)
Note that gdb actually knows which contexts macros are and aren't visible, so when you have the program stopped inside some function, you can only access macros visible at that point. (You can see that the "included at" lines above show you through exactly what path the macro is visible).
gdb variables
Whenever you print a variable in gdb, it prints this weird $NN = before it in the output:
(gdb) p 5+5
$1 = 10
This is actually a gdb variable, that you can use to reference that same variable any time later in your session:
(gdb) p $1
$2 = 10
You can also assign your own variables for convenience, using set:
(gdb) set $foo = 4
(gdb) p $foo
$3 = 4
This can be useful to grab a reference to some complex expression or similar that you'll be referencing many times, or, for example, for simplicity in writing a conditional breakpoint (see tip 1)
Register variables
In addition to the numeric variables, and any variables you define, gdb exposes your machine's registers as pseudo-variables, including some cross-architecture aliases for common ones, like $sp for the the stack pointer, or $pc for the program counter or instruction pointer.
These are most useful when debugging assembly code or code without debugging symbols. Combined with a knowledge of your machine's calling convention, for example, you can use these to inspect function parameters:
(gdb) break write if $rsi == 2
will break on all writes to stderr on amd64, where the $rsi register is used to pass the first parameter.
The x command
Most people who've used gdb know about the print or p command, because of its obvious name, but I've been surprised how many don't know about the power of the x command.
x (for "examine") is used to output regions of memory in various formats. It takes two arguments in a slightly unusual syntax:
x/FMT ADDRESS
ADDRESS, unsurprisingly, is the address to examine; It can be an arbitrary expression, like the argument to print.
FMT controls how the memory should be dumped, and consists of (up to) three components:
A numeric COUNT of how many elements to dump
A single-character FORMAT, indicating how to interpret and display each element
A single-character SIZE, indicating the size of each element to display.
x displays COUNT elements of length SIZE each, starting from ADDRESS, formatting them according to the FORMAT.
There are many valid "format" arguments; help x in gdb will give you the full list, so here's my favorites:
x/x displays elements in hex, x/d displays them as signed decimals, x/c displays characters, x/i disassembles memory as instructions, and x/s interprets memory as C strings.
The SIZE argument can be one of: b, h, w, and g, for one-, two-, four-, and eight-byte blocks, respectively.
If you have debug symbols so that GDB knows the types of everything you might want to inspect, p is usually a better choice, but if not, x is invaluable for taking a look at memory.
[~]$ grep saved_command /proc/kallsyms
ffffffff81946000 B saved_command_line
(gdb) x/s 0xffffffff81946000
ffffffff81946000 <>: "root=/dev/sda1 quiet"
x/i is invaluable as a quick way to disassemble memory:
(gdb) x/5i schedule
0xffffffff8154804a <schedule>: push %rbp
0xffffffff8154804b <schedule+1>: mov $0x11ac0,%rdx
0xffffffff81548052 <schedule+8>: mov %gs:0xb588,%rax
0xffffffff8154805b <schedule+17>: mov %rsp,%rbp
0xffffffff8154805e <schedule+20>: push %r15
If I'm stopped at a segfault in unknown code, one of the first things I try is something like x/20i $ip-40, to get a look at what the code I'm stopped at looks like.
A quick-and-dirty but surprisingly effective way to debug memory leaks is to let the leak grow until it consumes most of a program's memory, and then attach gdb and just x random pieces of memory. Since the leaked data is using up most of memory, you'll usually hit it pretty quickly, and can try to interpret what it must have come from.
(gdb) x/4i $pc # print 4 i-instructions after the current address of the program counter/instruction pointer $pc
=> 0x400515 <main+15>: mov $0xa,%esi
0x40051a <main+20>: mov $0x4005c4,%edi
0x40051f <main+25>: mov $0x0,%eax
0x400524 <main+30>: callq 0x4003e0 <printf@plt>
(gdb) p/d 0xa # print hexadecimal number 0xa in d-igits
$2 = 10
(gdb) p (char *) 0x4005c4 # cast this address in char* and print it
$3 = 0x4005c4 "test1 10 vs 15 -> %d\n"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment