Gdb: Difference between revisions

From miki
Jump to navigation Jump to search
Line 409: Line 409:
da m w 0x1000 0x10 # Watch memory zone at 0x1000 for 16 bytes
da m w 0x1000 0x10 # Watch memory zone at 0x1000 for 16 bytes
da m w 0x2000 0x10 # Add a second zone at 0x2000
da m w 0x2000 0x10 # Add a second zone at 0x2000
</source>

=== 8 gdb tricks you should know ===
From https://blogs.oracle.com/ksplice/entry/8_gdb_tricks_you_should:

* Use <code>break WHERE if COND</code>
: For instance <code>break context_switch if next == init_task</code>.

* Use <code>command</code>
: This sets commands to be executed when a breakpoint is hit. For instance
<source lang=python>
b do_mmap_pgoff
# Breakpoint 1 at 0xffffffff8111a441: file mm/mmap.c, line 940.
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
</source>

* Use <code>gdb --args</code> to specify runtime arguments

* Finding source files
: Use <code>directory</code> to add directory to search for source files.
<source lang=python>
list main
# 1192 ls.c: No such file or directory.
# in ls.c
directory ~/src/coreutils-7.4/src/
# Source directories searched: /home/nelhage/src/coreutils-7.4:$cdir:$cwd
list main
</source>
: Use <code>set substitute-path</code> to fix absolute paths
<source lang=python>
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
set substitute-path /build/buildd/linux-2.6.32 /home/nelhage/src/linux-2.6.32/
list schedule
</source>

* Use gcc <code>-ggdb3</code> to add MACRO's symbol as gdb macro

* Use gdb's variable like <code>$1</code> but also define your own
<source lang=python>
set $foo = 4
p $foo
# $3 = 4
</source>

* Use register variables
: All CPU registers are available as variables like <code>$R0</code>, <code>$R1</code>, but gdb also defines cross-architectures ones like <code>$sp</code> and <code>$pc</code>. For instance, if <code>$rsi</code> register is used to pass the 1st parameter,
<source lang=python>
break write if $rsi == 2
</source>

* The <code>x</code> command
<source lang=python>
x/s 0xffffffff81946000
# ffffffff81946000 <>: "root=/dev/sda1 quiet"

# Use x/i as a quick way to disassemble memory
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

# Print code surround current pc
x/20i $ip-40
</source>

* Use the <code>@</code> symbol
:The following works if source code is something like <tt>int a[ 10 ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };</tt>:
<source lang=python>
p a
# $1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
</source>
:But if the array is much bigger, or array is a C++ vector, we can use <code>@</code>:

<source lang=python>
p *&a[0]@10
# $1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
p *&a[550]@4
# $1 = {551, 552, 553, 554}
</source>
</source>

Revision as of 06:43, 25 November 2016

References

GDB front-ends

Reference list:

Ideally front-ends must use the GDB/MI2 interface. There is also the built-in Text User Interface to GDB (C-x C-a: http://davis.lbl.gov/Manuals/GDB/gdb_21.html

Good candidates

Mainly from SO post above:

Vim:

Use old shell implementation, not the new neovim terminal.
Read some comment it was not convenient, and would require extra plugin like https://github.com/notEvil/vim-debug.

Neovim:

Only for LLDB.

GDBInit hacks

  • Using colout one may color almost any gdb output.

Old front-ends

These are using the old "annotation" mechanisms:

GDB configuration

GDB reads file ~/.gdbinit at start.

Some references:

Bare minimum configuration

From StackOverflow [1]:

set history save on
set print pretty
set output-radix 16
set height 0

GDB dashboard

GDB dashboard is a modular visual interface for GDB in Python.

To install simply copy .gdbinit as ~/.gdbinit

cp gdb-dashboard/.gdbinit ~/.gdbinit


Alternatively, source it from ~/.gdbinit:

source ~/.gdbinit-dashboard
Install pygments

Install pygments to get source highlighting

sudo pip install Pygments        # Globally
pip install Pygments             # Locally

If GDB uses python3 (ldd $(which gdb))), you'll need to install with pip3:

sudo pip3 install Pygments       # Globally
pip3 install Pygments            # Locally

To get the list of available styles:

python from pygments.styles import get_all_styles as styles
python for s in styles(): print(s)

Alternative styles:

Prepare debug session

  • Compile with debug symbols, use option -g:
gcc -g program.c               # -g : debug symbols
gcc -g -O0 program.c           #  ... -O0: disable optimization
  • Force core dumps (see bash help ulimit):
ulimit -c unlimited
./a.out
# Segmentation fault (core dumped)

GDB invocation

gdb a.out
gdb a.out core.1234           # If coredump available

GDB commands

Reference:

Break points and watch points

b [+-][NUMBER]
break [+-][NUMBER]

Set a breakpoint at current line, at given line NUMBER or NUMBER lines after/before current line.

b LOCATION
break LOCATION

Set breakpoint at LOCATION.
b main sets a breakpoint at beginning of function main().
b foo.c:42 sets a breakpoint at file foo.c, line 42.

watch EXPR

Stop execution when EXPR changes

awatch EXPR

Stop execution when EXPR is accessed

i b
info b
info break

list breakpoints

cl LOCATION
clear LOCATION

Clear breakpoint by LOCATION

d
delete

Delete all breakpoints

d NUMBER
delete NUMBER

Clear breakpoint by NUMBER (as listed by i b)

dis NUMBER
disable NUMBER

Disable breakpoint by NUMBER (as listed by i b)

save b FILE
save breakpoints FILE

Save current breakpoints as script FILE. Use source to reload.
Execute program

r [ARGS]
run [ARGS]

Start (or restart) program. Arguments may include wildcards (*) and redirections (<, <<...)

kill

Kill current program.

c
cont

Continue and interrupted program.

s [NUMBER]
step [NUMBER]

Step (into) current line, or NUMBER lines.

n
next

Run to next line (over current line)

fin
finish

Execute till returning from current selected frame.

advance LOCATION

Run until temporary breakpoint set at LOCATION.

u [NUMBER] until [NUMBER]

Execute until the program reaches a source line greater than current (very handy).
View stack

bt
bt [COUNT]
backtrace [COUNT]
where [COUNT]

Print backtrace of all stack frames, or innermost (outermost) COUNT frames if COUNT>0 (COUNT<0)

f [FRAME]
frame [FRAME]

Select frame FRAME and print stack frame

up

Go up a level in the stack (frame calling current frame).

do
down

Go down a level in the stack (frame called by current frame).
View memory

disp EXPR
display EXPR

Display EXPR at each prompt (if within scope).

x/FMT ADDRESS

Examine memory at ADDRESS as FMT(x)

i locals
i args
info locals
info args

Print information on local variables / function arguments in the current frame

print EXPR

print EXPR.

undisplay NUMBER

Undisplay expression by NUMBER.
View code

l
list

List (10 by default) lines of current frame

disassemble /m
disassemble /s
disassemble 'foo.c'::bar

Disassemble a specified section of memory
Miscellaneous

q
quit

Quit gdb.

help COMMAND
apropos WORD

Get help on COMMAND, or search commands related to WORD.

source FILE

Source script FILE.
RETURN Repeat last command.

Tips

Define a custom label for breakpoint in C/C++

Say we want to set a breakpoint at a specified location in source file, but this position may move over time. The easiest is to use an asm statement to define the label [2]:

#include <stdio.h>

int main () {
  void *ret_p = &&ret;
  printf("ret: %p\n", ret_p);
  goto *ret_p;

  return 1;

ret:
  asm("RET:")

    return 0;
}

This will add a symbol table entry as follows.

gcc  -Wl,--export-dynamic t.c  -ldl
readelf -s a.out | grep RET
# 41: 0804858a     0 NOTYPE  LOCAL  DEFAULT   13 RET

Use help to test a command abbreviation

Don't know if f stands for finish or frame? Just use help f:

help f
# Select and print a stack frame.
# ...

Examples

Simple Segmentation Fault Example

(From [3])

Example program segfault.c:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
  char *buf;

  buf = malloc(1<<31);

  fgets(buf, 1024, stdin);
  printf("%s\n", buf);

  return 1;
}
Compile and launch gdb:
gcc -g segfault.c
gdb a.out

The debug session

run
backtrace
frame 3
print buf
kill
break segfault.c:8
run
print buf
next
print buf

Fix the bug, then start again, watching now buf:

watch buf
# Start again, answer 'y' when asked to start from beginning
run
# Break at watch point, let's _c_ontinue
c

More GDB stuff

display i            # Display i at each stop
display/4i $pc       # Display the 4 next instruction at each stop
u                    # Continue until we reach an higher pc address

Using gdb-dashboard

da                   # Print dashboard again
da reg               # Remove register
da reg               # Add it back
da m w 0x1000 0x10   # Watch memory zone at 0x1000 for 16 bytes
da m w 0x2000 0x10   # Add a second zone at 0x2000

8 gdb tricks you should know

From https://blogs.oracle.com/ksplice/entry/8_gdb_tricks_you_should:

  • Use break WHERE if COND
For instance break context_switch if next == init_task.
  • Use command
This sets commands to be executed when a breakpoint is hit. For instance
b do_mmap_pgoff 
# Breakpoint 1 at 0xffffffff8111a441: file mm/mmap.c, line 940.
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
  • Use gdb --args to specify runtime arguments
  • Finding source files
Use directory to add directory to search for source files.
list main
# 1192    ls.c: No such file or directory.
#     in ls.c
directory ~/src/coreutils-7.4/src/
# Source directories searched: /home/nelhage/src/coreutils-7.4:$cdir:$cwd
list main
Use set substitute-path to fix absolute paths
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
set substitute-path /build/buildd/linux-2.6.32 /home/nelhage/src/linux-2.6.32/
list schedule
  • Use gcc -ggdb3 to add MACRO's symbol as gdb macro
  • Use gdb's variable like $1 but also define your own
set $foo = 4
p $foo
# $3 = 4
  • Use register variables
All CPU registers are available as variables like $R0, $R1, but gdb also defines cross-architectures ones like $sp and $pc. For instance, if $rsi register is used to pass the 1st parameter,
break write if $rsi == 2
  • The x command
x/s 0xffffffff81946000
# ffffffff81946000 <>:     "root=/dev/sda1 quiet"

# Use x/i as a quick way to disassemble memory
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

# Print code surround current pc
x/20i $ip-40
  • Use the @ symbol
The following works if source code is something like int a[ 10 ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };:
p a
# $1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
But if the array is much bigger, or array is a C++ vector, we can use @:
p *&a[0]@10
# $1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
p *&a[550]@4
# $1 = {551, 552, 553, 554}