Strange behaviour of gdb - c++

I am debugging following sample code in gdb
#include <iostream>
#include <string.h>
using namespace std;
void c (char** q)
{
q = new char*[2];
if (q == NULL)
cout<<"NO OK";
else
cout<<"OK";
}
int main ()
{
char** d = NULL;
c(d);
return 1;
}
Now this program gives output as "OK"
but while debugging this code in gdb i found following behavior
gdb -version
GNU gdb (GDB) 7.5.1
Breakpoint 1, c (q=0x0) at issue.cpp:8
warning: Source file is more recent than executable.
8 q = new char*[2];
(gdb) p q
$1 = (char **) 0x0
(gdb) n
9 if (q == NULL)
(gdb) p q
$2 = (char **) 0x0
(gdb) p q==0
$3 = true
(gdb) n
12 cout<<"OK";
(gdb) p q
$4 = (char **) 0x0
(gdb) p q==0
$5 = true
(gdb)
gdb is showing q value a null but code is executing differently.

Well: warning: Source file is more recent than executable. - That may be your answer. Try recompiling your code.

There is definitely something going on that messes up with the gdb logic. I am encountering your described behavior in gcc 4.8.3 running in cygwin (32 bits).
I am getting this output in my gdb session for your code:
Breakpoint 1, main () at test.cpp:21
21 char** d = NULL;
(gdb) s
22 c(d);
(gdb) s
c (q=0x0) at test.cpp:9
9 q = new char*[2];
(gdb) s
13 if (q == NULL)
(gdb) p q
$1 = (char **) 0x0
(gdb) p &q
$2 = (char ***) 0x22abd0
(gdb) x 0x22abd0
0x22abd0: 0x00000000
Now if I simply change your function like this:
void c (char** q)
{
cout << q << endl;
q = new char*[2];
if (q == NULL)
cout<<"NO OK";
else
cout<<"OK";
}
gdb seems now capable of getting that q parameter's value:
Breakpoint 1, main () at test.cpp:21
21 char** d = NULL;
(gdb) s
22 c(d);
(gdb) s
c (q=0x0) at test.cpp:8
8 cout << q << endl;
(gdb) s
0
9 q = new char*[2];
(gdb) s
13 if (q == NULL)
(gdb) p q
$1 = (char **) 0x2004a0a8
(gdb) p &q
$2 = (char ***) 0x22abd0
(gdb) x 0x22abd0
0x22abd0: 0x2004a0a8
Let's change the code like this:
void c (char** q)
{
q = new char*[2];
cout << q << endl;
if (q == NULL)
cout<<"NO OK";
else
cout<<"OK";
}
The generated code for this function looks something like this: (compiled -g -ggdb -O0)
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $40, %esp
movl $8, (%esp)
call __Znaj
movl %eax, -12(%ebp)
movl -12(%ebp), %eax
movl %eax, 4(%esp)
movl $__ZSt4cout, (%esp)
call __ZNSolsEPKv
movl $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)
movl %eax, (%esp)
call __ZNSolsEPFRSoS_E
cmpl $0, -12(%ebp)
jne L2
movl $LC0, 4(%esp)
movl $__ZSt4cout, (%esp)
call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
jmp L1
Now it seems from this code that the compiler uses for if (q == NULL) the value at $ebp - 12. Let's see how this goes during the gdb session:
Breakpoint 1, main () at test.cpp:19
19 char** d = NULL;
(gdb) s
20 c(d);
(gdb) s
c (q=0x0) at test.cpp:8
8 q = new char*[2];
(gdb) s
9 cout << q << endl;
(gdb) s
0x2003a078
11 if (q == NULL)
(gdb) p q
$1 = (char **) 0x0
(gdb) p &q
$2 = (char ***) 0x22abd0
(gdb) p $ebp
$3 = (void *) 0x22abc8
(gdb) p $ebp - 12
$4 = (void *) 0x22abbc
(gdb) x 0x22abbc
0x22abbc: 0x2003a078
Looks like gdb looks for q at a different address than the one it actually is at. You probably just got yourself into a delicate gcc - gdb interaction issue.

Normally debugging is done on the non-optimized executable (and measuring performance - on optimized executable). This is because doing things fast and doing them exactly the way want them to do is mutually exclusive.
Your c function can be rewritten to
void c (char** q)
{
cout<<"OK";
}
This is because you assign the newed array on the function argument, that is, the local variable. This means the code has no side effects to the rest of the world. Also, new never returns NULL, and so q == 0 is always false.
EDIT: Ok, it's actually more complicated than a simple debug/release difference. Since the actual problem lies elsewhere, to make this answer more useful, this is how it should behave (code compiled with g++ 4.9.0, and gdb version is 7.7)
Non-optimized g++ -g
Breakpoint 1, c (q=0x0) at a.cpp:8
8 q = new char*[2];
(gdb) p q
$1 = (char **) 0x0
(gdb) n
9 if (q == NULL)
(gdb) p q
$2 = (char **) 0x611290
(gdb) p q==0
$3 = false
(gdb) n
12 cout<<"OK";
(gdb) p q
$4 = (char **) 0x611290
(gdb) p q==0
$5 = false
Optimized g++ -g -O2
Breakpoint 1, c (q=0x0) at a.cpp:8
8 q = new char*[2];
(gdb) p q
$1 = (char **) 0x0
(gdb) n
12 cout<<"OK";
(gdb) p q
$2 = <optimized out>
(gdb)

Related

How to step through C++ code with structured binding in GDB without jumping to the declaration line?

Given a program:
[]$ cat a.cpp
#include <iostream>
int main(){
auto [a, b] = std::make_pair(1, 2);
for(int x = 0; x < 2; ++x) {
a += b;
b += x;
}
}
If I compile it and step through it line by line in GDB:
[]$ g++ -std=c++17 -g a.cpp
[]$ gdb -q a.out
Reading symbols from a.out...
(gdb) break main
Breakpoint 1 at 0x114d: file a.cpp, line 4.
(gdb) run
Starting program: /tmp/a.out
Breakpoint 1, main () at a.cpp:4
4 auto [a, b] = std::make_pair(1, 2);
(gdb) next
5 for(int x = 0; x < 2; ++x) {
(gdb)
4 auto [a, b] = std::make_pair(1, 2);
(gdb)
6 a += b;
(gdb)
4 auto [a, b] = std::make_pair(1, 2);
(gdb)
7 b += x;
(gdb)
5 for(int x = 0; x < 2; ++x) {
(gdb)
4 auto [a, b] = std::make_pair(1, 2);
(gdb)
6 a += b;
(gdb)
4 auto [a, b] = std::make_pair(1, 2);
(gdb)
7 b += x;
(gdb)
5 for(int x = 0; x < 2; ++x) {
(gdb)
9 }
Then the structured binding declaration line is stepped over every time the variable is accessed or written to.
Is there any way so that it does not step through those lines, expect for the first time, similar to this:
(gdb) run
Starting program: /tmp/a.out
Breakpoint 1, main () at a.cpp:4
4 auto [a, b] = std::make_pair(1, 2);
(gdb) next
5 for(int x = 0; x < 2; ++x) {
(gdb)
6 a += b;
(gdb)
7 b += x;
(gdb)
5 for(int x = 0; x < 2; ++x) {
(gdb)
6 a += b;
(gdb)
7 b += x;
(gdb)
5 for(int x = 0; x < 2; ++x) {
(gdb)
9 }
It's possible to change the structured binding to auto& a = pair.first; auto& b = pair.second and it works correctly, but it means not using structured binding at all.
Setting a breakpoint at the line and enter command commands | next | end does not completely work, and still require manual work for each structured binding.
Adding any optimization flag (even -Og in this case) optimize the whole code away (because it doesn't have any observable side effect); or optimizes some unused variables away.
When there are observable side effect however, it does work.
Searching online for "gdb debug structured binding", or even "gdb skip through particular line while stepping" does not give any useful result. The skip command can only skip through functions, not lines.
Tools version:
[]$ g++ --version
g++ (Arch Linux 9.2.1+20200130-2) 9.2.1 20200130
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[]$ gdb --version
GNU gdb (GDB) 9.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

GDB doesn't print the output in signed decimal

I'm trying to use gdb to do some maths. Look at this two conversions
gdb$ p/x -8
$8 = 0xfffffff8
gdb$ p/d 0xfffffff8
$9 = 4294967288
Why in the second case gdb doesn't return -8 instead of the unsigned value of the number?
Indeed, there is no difference at all between p/d and p/u
gdb$ p/u 0xfffffff8
$10 = 4294967288
I can't find the documentation for this, but it looks that default type for integer values in gdb is 64 bit signed integer. See this:
(gdb) p/d 0xfffffffffffffff8
$7 = -8
So it interprets 0xfffffff8 as (int64_t) 0x00000000fffffff8, which is a positive value.
You are looking for this:
(gdb) p/d (int)0xfffffff8
$9 = -8
(gdb) p/u (int)0xfffffff8
$10 = 4294967288

Why watchpoint doesn't effect?

I am studying the watchpoint of GDB. I write a simple test code as following:
int main(int argc, char **argv)
{
int x = 30;
int y = 10;
x = y;
return 0;
}
I build it via gcc -g -o wt watch.c. And then I started gdb and did following experiment:
lihacker#lihacker-laptop:~/mySrc$ gdb ./wt
GNU gdb (GDB) 7.3
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/lihacker/mySrc/wt...done.
(gdb) b main
Breakpoint 1 at 0x80483a5: file watch.c, line 5.
(gdb) run
Starting program: /home/lihacker/mySrc/wt
Breakpoint 1, main (argc=<optimized out>, argv=<optimized out>) at watch.c:5
5 int x = 30;
(gdb) watch x
Hardware watchpoint 2: x
(gdb) c
Continuing.
Watchpoint 2 deleted because the program has left the block in
which its expression is valid.
0xb7e83775 in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6
(gdb)
In my test codes, the variable "x" is changed, but gdb doesn't stop then.
Why the watchpoint doesn't effect here? Thanks a lot.
This:
Breakpoint 1, main (argc=<optimized out>, argv=<optimized out>) at watch.c:5
suggests that you used -O2 or some such flag when building the test. Try building with -O0 (which will explicitly disable optimization).
Even then, there is a glitch (a buglet) in GDB. Here is what I see:
(gdb) b main
Breakpoint 3 at 0x80483ba: file t.c, line 3.
(gdb) r
Breakpoint 3, main (argc=1, argv=0xffffca94) at t.c:3
3 int x = 30;
(gdb) watch x
Hardware watchpoint 4: x
(gdb) c
Hardware watchpoint 4: x
Old value = 0
New value = 10
main (argc=1, argv=0xffffca94) at t.c:8
8 return 0;
(gdb) c
Watchpoint 4 deleted because the program has left the block in
which its expression is valid.
0xf7e7cbd6 in __libc_start_main () from /lib32/libc.so.6
This can't be right: the value of x changes from 30 to 10, not from 0 to 10.
If I set the breakpoint on the very first instruction of main, then it works as expected:
(gdb) b *main
Breakpoint 1 at 0x80483b4: file t.c, line 2.
(gdb) r
Breakpoint 1, main (argc=1, argv=0xffffca94) at t.c:2
2 {
(gdb) watch x
Hardware watchpoint 2: x
(gdb) c
Hardware watchpoint 2: x
Old value = 0
New value = 30
main (argc=1, argv=0xffffca94) at t.c:4
4 int y = 10;
(gdb) c
Hardware watchpoint 2: x
Old value = 30
New value = 10
main (argc=1, argv=0xffffca94) at t.c:8
8 return 0;
(gdb) c
Watchpoint 2 deleted because the program has left the block in
which its expression is valid.
0xf7e7cbd6 in __libc_start_main () from /lib32/libc.so.6

GDB: Why can I not print this?

(gdb) print argv[1]
$5 = 0xbffffb1d "hello"
(gdb) step
21 sz = strlen(argv[1]) + 1;
(gdb) print sz
$6 = 0
(gdb) printf "%s", sz
Cannot access memory at address 0x0
(gdb) printf "%i", sz
0
I am expecting 4 in sz, why is it coming out as 0?
I am not sure why you are expecting 4. You get 5 from strlen(argv[1]) because hello has 5 characters. And then you are adding 1 to it which is why the answer is 6.
sz = strlen(argv[1]) + 1; // 5 + 1 = 6

Why I can't access the memory directly?

(gdb) p it
$2 = (item *) 0x6
(gdb) p *it
$3 = {next = 0x0, prev = 0x0, h_next = 0x0, time = 0, exptime = 0, nbytes = 7, refcount = 1, nsuffix = 6 '\006', it_flags = 2 '\002', slabs_clsid = 1 '\001', nkey = 6 '\006',
end = 0x7f0890b6e040}
(gdb) p *0x6
Cannot access memory at address 0x6
Isn't p *it and p *0x6 the same thing here??
Unless you are on an embedded target that has real memory mapped at address 0, the value of it == 0x6 is bogus (usually result of a null pointer dereference).
The fact that gdb prints *it probably means there is a bug in gdb, but it's hard to say. Unfortunately you didn't say which version of GDB, and what OS, you are using.
The gdb 'p' command can only be used for printing variables value.
If you want to inspect memory have a look there