| Previous Post | Top | Next Post | 
TOC
An example C program with Makefile
In order to practice with a simple C program, I created test.c and Makefile
at github.
Let me recap basic GCC options used in this example together with some popular situation.
- CPP
- -D_FORTIFY_SOURCE=2: add checks for buffer overflows via CPP (pre-processor)- GCC warns for unused return value for function such as scanf(...)with this.
 
- GCC warns for unused return value for function such as 
 
- GCC optimization
- -O0: default optimization if not specified -> May yield uninitialized variable memory
- -Og: optimization for debug
- -O2: optimization for normal use
 
- GCC warning
- -Wall: Enable every warning
- -Werror: Error for warning
- -g: Produce debug symbol in the operating system’s native format (GDB compatible)
- -ggdb: Produce debug symbol by GDB (with extra data)
 
- Other GCC notable options
- -E: Get the preprocessor output only
- -S: Get the assembly code
- -V: Get the verbose output of compilation
- -fPIC: Get a position-independent code
- -Wl,option: Linker option
- -Wl,-z,relo: pass- -z reloto LD.
 
- LD (linker) option
- -l: Link with a shared library- -lm: link with math library
 
- -L: Specify the location of the external library
- -z relro: memory segment made read-only after relocation
 
Uninitialized variable was zeroed by code generated by -Og and -O2 but not
by -O0. So I should use -O2 or -Og to make debug easy.
Jump to errors in the source code: C program example with quickfix
Above example compiles without issue.  So let me intensionally break it by
removing ; in some lines by editing with:
$ vi test.c
While in Nvim, let me type :make in NORMAL mode.  This runs the content of
Makefile with make.  It sure causes errors and the cursor moves to the
first error position. I can jump around errors with [q and ]q.  Cool.
I can also open quickfix list window with :copen.
Pressing ENTER on quickfix list window line jumps cursor to its corresponding position.
Inspect running program (direct GDB)
Use of GDB was touched in Fun to Program – Debug: level 3.
$ make
$ gdb -q ./test
Reading symbols from ./test...
(gdb) list 1,15
1#include <stdlib.h>
2#include <stdio.h>
3int main() {
4  int i, final, factorial = 1;
5  printf("Enter the number: ");
6  if (scanf("%d", &final)) {
7    for (i = 1; i <= final; i++)
8      factorial = factorial * i;
9    printf("The factorial of %d is %d\n", final, factorial);
10    exit(0);
11  } else {
12    exit(1);
13  }
14}
(gdb) b 8
Breakpoint 1 at 0x1199: file test.c, line 8.
(gdb) run
Starting program: /home/osamu/github/osamuaoki.github.io/osamuaoki-hugo-proj/021_gcc_debug/test
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Enter the number: 17
Breakpoint 1, main () at test.c:8
8      factorial = factorial * i;
(gdb) info locals
i = 1
final = 17
factorial = 1
(gdb) c 16
Will ignore next 15 crossings of breakpoint 1.  Continuing.
Breakpoint 1, main () at test.c:8
8      factorial = factorial * i;
(gdb) info locals
i = 17
final = 17
factorial = 2004189184
(gdb) n
7    for (i = 1; i <= final; i++)
(gdb) n
9    printf("The factorial of %d is %d\n", final, factorial);
(gdb) info locals
i = 18
final = 17
factorial = -288522240
(gdb) n
The factorial of 17 is -288522240
10    exit(0);
(gdb) c
Continuing.
[Inferior 1 (process 72091) exited normally]
Since 17 * 2,004,189,184 =  36,507,221,999, and int is 32 bit signed integer,  overflow occurred (max = 0x7FFF_FFFF= 2,147,483,647).
Inspect running program (remote GDB)
Let’s think about simple single host with 2 terminal console case.
On console GDBSERVER (remote), let’s start gdbserver to test ./test:
$ gdbserver localhost:1234 ./test
Process ./test created; pid = 32761
Listening on port 1234
On console GDB (local), start gdb:
$ gdb -q
(gdb) target remote localhost:1234
(gdb) b 7
Breakpoint 1 at 0x55555555519c: file test.c, line 7.
(gdb) c
Continuing.
Reading /lib/x86_64-linux-gnu/libc.so.6 from remote target...
On console GDBSERVER, we now see the following and enter 5 on prompt.
$ gdbserver localhost:1234 ./test
Process ./test created; pid = 32761
Listening on port 1234
Remote debugging from host ::1, port 60566
Enter the number: 5
On console GDB, we now see gdb stopping at break point:
$ gdb -q
(gdb) target remote localhost:1234
(gdb) b 7
Breakpoint 1 at 0x55555555519c: file test.c, line 7.
(gdb) c
Continuing.
Reading /lib/x86_64-linux-gnu/libc.so.6 from remote target...
Breakpoint 1, main () at test.c:7
With above, ./test is tested with full access to stdin and stdout.
Inspect running program (via DAP)
Since Debian/Bookworm 12 currently has GDB 13, we need to follow
“C C Rust (gdb via vscode cpptools)”
using
“github: microsoft/vscode-cpptools”.
LazyVim can activate dap.core LazyExtra and activate cpptools  in DAP by running :Mason (or <leader>cm).
Next GDB 14 can support DAP (Debug Adapter Protocol) natively.
Problem is Nvim with DAP UI doesn’t seem to allow running program using STDIN.
Run ./test on a separate console under gdbserver as above solved this
issue for me.
I need to read
nvim-dap-ui/doc/nvim-dap-ui.txt and nvim-dap-ui/README.md directory since this is not
shown in normal Vim-help system.
Let’s check the meaning of DAP-UI.  Following are reordered to match the GUI display by the lua source code of nvim-dap-ui (for icons in repl element):
- play = “” / pause = “”
- step_into = “” – step
- step_over = “” – next
- step_out = “” – finish
- step_back = “” – (PC–)
- run_last = “” – (run again)
- terminate = “” – This one is tricky
- disconnect = “” – This one is tricky
(The above needs font support)
Now I see why debug session terminated when I was playing with icons. Variable names give me good hints, here.
Setting BP etc., are by keymaps like <leader>db etc. in the main C source display.
As for each meanings of sidebar elements, I guess them as follows from variable names in the layout table:
- left(sidebar)- scopes
- breakpoints
- stacks
- watches
 
- bottom(sidebar)- repl
- console
 
Also, I see following keymaps. These seem to work in left and bottom sidebars. The meaning of these are still vague for me, though.
- edit = “e”
- expand = { "<CR>" "<2-LeftMouse>" }
- open = “o”
- remove = “d”
- repl = “r”
- toggle = “t”
Also UI dialog for “Input” and “Condition” needs to be investigated. ….
After fiddling updates, DAP stops working even with simple hello with direct
gdb run without using gdbserver.  It errors as:
DAP Couldn't connect to localhost:${port}: ECONNREFUSED
This makes no sense to me. TBH, it’s too complicated and unstable for me at this moment to use this DAP.
Hmmm… it looks like LazyExtras store data in
~/.config/$NVIM_APPNAME/*.json.  Ensuring to store these updated data in VCS seems to be important.
Let me stick to the basic direct CLI GDB usage for now.
Jump to the specific position in a file: generic Vim
Let me revisit trick to jump to the specific position manually.
To go to line 99 of file.txt, try:
$ vim +99 file.txt
To go to line 99 column 40 of file.txt, try any one of the following:
$ vim +99 file.txt +'norm 40|'
$ vim file.txt +'norm 99G40|'
$ vim +'call cursor(99, 40)' file.txt
NOTE: | (bar) in NORMAL mode is “goto column”, and in EX-mode is “command
separator”.
NOTE: Indexing for line and column in Vim starts at 1. 0G is for the last
line.  (List index in Vim Script starts at 0.)
My TODO list
- LUA debug
- PYTHON debug
- The Python Debugger from python.org
- python3-trepan
 
| Previous Post | Top | Next Post |