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 relo
to 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 |