GDB

2021-04-28

  • 1 Basics
    • 1.1 Operations
      • 1.1.1 Conditional break
      • 1.1.2 Remove A Variable from the Auto Display
      • 1.1.3 List Class Methods
      • 1.1.4 Print An Element of 2D Array
      • 1.1.5 Print Multiple Variables
      • 1.1.6 Call Stack
      • 1.1.7 Debug core file
    • 1.2 Configuration
      • 1.2.1 Print to file instead of stdout
      • 1.2.2 Limit of number of elements in print setting
  • 2 Advanced
    • 2.1 hexdump
      • 2.1.1 View the content of a binary file
    • 2.2 Operations
      • 2.2.1 Check the Value at a Memory Address
      • 2.2.2 Watchpoint a fixed address
      • 2.2.3 Print whole string verbatim
      • 2.2.4 Display the elements of vector
      • 2.2.5 GDB Gives SQRT(3.0) = 0?
      • 2.2.6 Check 16-bytes Floating Number
      • 2.2.7 Reversible Debugging
    • 2.3 Python support
      • 2.3.1 Enable Python Support
      • 2.3.2 Usage
      • 2.3.3 Example 1: Read and Replace Data
    • 2.4 Misc
      • 2.4.1 ptrace operation not permitted using GDB in docker

1 Basics

1.1 Operations

1.1.1 Conditional break

break x:20 if strcmp(y, "hello") == 0

1.1.2 Remove A Variable from the Auto Display

(gdb) display a
1: a = 32767
(gdb) display b
2: b = 0
(gdb) display c
3: c = 0
(gdb) undisplay 2
(gdb) step
6  b = 2;
1: a = 1
3: c = 0

1.1.3 List Class Methods

ptype

1.1.4 Print An Element of 2D Array

In C,

p arr[1][3]

1.1.5 Print Multiple Variables

Use the following command

printf "%d,%d\n", a, b

1.1.6 Call Stack

Each time your program performs a function call, information about the call is generated. The information is saved in a block of data called a stack frame. The stack frames are allocated in a region of memory called the call stack.

A backtrace is a summary of how your program got where it is. It shows one line per frame, for many frames, starting with the currently executing frame (frame zero), followed by its caller (frame one), and on up the stack.

  • backtrace or bt: Print a backtrace of the entire stack: one line per frame for all frames in the stack.

1.1.7 Debug core file

When your program fails during the runtime, a core file would be dumped out if ulimit -c unlimited is already executed.

Then gdb your_program even if the command to run your program is gdb --args your_program input_file. Remember that .gdbinit file should be not presented. Otherwise, gdb would follow the commands in .gdbinit to run. When gdb starts, type core core.114172 to load the core file. Then bt shows the backtrace.

Use frame num to go to that frame.

1.2 Configuration

1.2.1 Print to file instead of stdout

You need to enable logging.

(gdb) set logging on

You can tell it which file to use.

(gdb) set logging file my_god_object.log

And you can examine current logging configuration.

(gdb) show logging

1.2.2 Limit of number of elements in print setting

set print elements number-of-elements 

Set a limit on how many elements of an array GDB will print. If GDB is printing a large array, it stops printing after it has printed the number of elements set by the set print elements command. This limit also applies to the display of strings. When GDB starts, this limit is set to 200. Setting number-of-elements to zero means that the printing is unlimited.

2 Advanced

2.1 hexdump

2.1.1 View the content of a binary file

$ hexdump -v -n 28 -e '1/4 "%08d " "\n"' Restart_files/out.149403.done.rst 
00000004 
00000005 
00000005 
00982600 
00000027 
-0000001 
00149403

Explanations

  • -v outputs all the content and does not collapse duplicates
  • -n 28 outputs 28 bytes. Note that integer-32 is 32 bits or say 4 bytes. Thus 28 bytes means 7 integer-32 numbers.
  • -e '1/4 "%08d " "\n"' specifies the output format. 1/4 means that the iteration count is 1 and the byte count is 4. Thus the number of bytes to be formatted as a group is 4. "%08d " "\n" is the C printf format notation. Note that 4/1 does not work as 1/4.

2.2 Operations

2.2.1 Check the Value at a Memory Address

p usp_ngb(1, 1, ws)
$1 = 7.4697350049059708
p &usp_ngb(1, 1, ws)
$2 = (PTR TO -> ( real(kind=8) )) 0x7fffffff7af0
x/xg &usp_ngb(1, 1, ws)
0x7fffffff7af0: 0x401de102368f6e20

Use this website IEEE-754 Floating-Point Conversion: From 64-bit Hexadecimal Representation To Decimal Floating-Point to see that 0x401de102368f6e20 is 7.4697350049059710.

For the format, refer to 10.6 Examining Memory and 10.5 Output Formats.

2.2.2 Watchpoint a fixed address

watch *0x10793ad0

2.2.3 Print whole string verbatim

(gdb) p "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$6 = 'a' <repeats 30 times>
(gdb) set print repeats 0
(gdb) p "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$7 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
(gdb) set print repeats 10
(gdb) p "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$8 = 'a' <repeats 30 times>

2.2.4 Display the elements of vector

It’s really difficult. Link

For now, I cannot see the difficulty.

2.2.5 GDB Gives SQRT(3.0) = 0?

The reason is that GDB has no debug info about the math function.

Use info func sqrt to check the available math functions.

Usually __sqrt is available in GDB.

(gdb) p (double) sin(4.0)
$16 = -0.7568024953079282
(gdb) p (float) sin(4.0)
$17 = -1.98266328e+18
(gdb) p (double) sqrt(4.0)
$18 = 2
(gdb) p (float) sqrt(4.0)
$19 = 0

Note you should use double as the type of the return value.

2.2.6 Check 16-bytes Floating Number

Use gdb to debug Fortran program. Normally, you cannot print correctly the values of 16-bytes floating number.

You can examine the memory by the following commands.

(gdb) p &(xy_qp(2))
$31 = (PTR TO -> ( real(kind=16) )) 0x7fffffffc410
(gdb) x/2xg 0x7fffffffc410
0x7fffffffc410: 0x0000000000000000  0xbfff000000000000
  • xy_qp(2) is actually -1.0 in 16-bytes format.
  • In x/2xg, the first x is the command of examining the content of a memory address, the second x is the format of hex, g is the unit size as giant word (8-bytes) and 2 means repeating twice.
  • Note: since the real content of this 16-bytes number is split into 2 parts, x/2xg gives reversed order of the split parts. The real content is actually 0xbfff000000000000 0x0000000000000000, i.e. 0xbfff0000000000000000000000000000
  • Use the Python function defined in Python Scientific Notes to get the decimal expression of this 16-bytes number.

2.2.7 Reversible Debugging

Reversible Debugging

2.3 Python support

2.3.1 Enable Python Support

Compile gdb source codes as follows,

./configure --prefix=/home/jcshi/Softwares/gdb-8.3.1 --with-python=/home/jcshi/Softwares/Python/bin/python3
make -j 4
make install

Note: If python is compiled from source codes by --enable-shared, configuring gdb will complain that no usable python. I tried to debug the configure script of gdb, but I failed. So I turn back to re-compile python without --enable-shared. However, --enable-shared seems to be required by pyinstaller. Maybe I should use a virtual environment for pyinstaller.

2.3.2 Usage

Load python script in .gdbinit: source python_script.py

2.3.3 Example 1: Read and Replace Data

from os.path import join
import gdb

def read2DMat(in_fpath):
    f = open(in_fpath,"r")
    content = f.readlines()
    data_mat = [[]]
    for i in range(len(content)):
        line_str = content[i].strip()
        val_list = line_str.split(',')
        for j in range(len(val_list)):
            val = float(val_list[j])
            data_mat[i].append(val)
        if( i < len(content)-1 ):
            data_mat.append([])
    return data_mat

ref_dir = '/home/jcshi/code_ref/cases/naca0012/viscous'
nc_list = [23,24,25,64]
for nc in nc_list:
    ref_q_fname = "Q_nc%d.dat"%(nc-1)
    ref_q_fpath = join(ref_dir, ref_q_fname)
    gdb_var_str = "grid_base_mod::cell(%d)%%beg_sp"%(nc)
    beg_sp = gdb.parse_and_eval(gdb_var_str)
    gdb_var_str = "grid_base_mod::cell(%d)%%end_sp"%(nc)
    end_sp = gdb.parse_and_eval(gdb_var_str)
    # Read in the data
    ref_q_data = read2DMat(ref_q_fpath)
    # gdb execute cmd
    for isp in range(beg_sp,end_sp+1):
        for iq in range(4):
            gdb_cmd_str = "set cdof%%v(%d,%d)=%23.15e"%(iq+1,isp,ref_q_data[isp-beg_sp][iq])
            gdb.execute( gdb_cmd_str )

2.4 Misc

2.4.1 ptrace operation not permitted using GDB in docker

Exit and run a new docker with the following option,

docker run --cap-add=SYS_PTRACE

Reference

.
Created on 2021-04-28 with pandoc