C99 Variable length arrays in GDB - c

At this simple C99-Code:
int main(void){
int a[3][3] = {1};
int m = 3;
int x;
int b[m][m];
x = sizeof(b);
b[0][0] = -1;
return 0;
}
with GDB we set a breakpoint at the return line and run. Now let's look at the following:
(gdb) p a
$1 = {{1, 0, 0}, {0, 0, 0}, {0, 0, 0}}
(gdb) p b
$2 = 0x7fffffffe3a0
(gdb) p sizeof(a)
$3 = 36
(gdb) p sizeof(b)
$4 = 0
(gdb) p x
$5 = 36
(gdb) whatis a
type = int [3][3]
(gdb) whatis b
type = int [][]
(gdb)
I wonder how this does happen. The C runtime environment assumes that the type of b is int [3][3] (because sizeof(b) is 36), but GDB does not.

The most obvious explanation would be that you have entered into main, but apparently have not reached VLA declaration.
To cover this, the C11 (N1570) ยง6.2.4/7 Storage durations of objects states that (emphasis mine):
For such an object that does have a variable length array type, its
lifetime extends from the declaration of the object until execution of
the program leaves the scope of the declaration.35)
The remedy is to step up into the declaration of VLA (tested with gcc 4.4.7 and gdb 7.2):
Breakpoint 1, main () at so.c:1
1 int main(void){
(gdb) s
2 int a[3][3] = {1};
(gdb) s
3 int m = 3;
(gdb) s
5 int b[m][m];
(gdb) s
6 x = sizeof(b);
(gdb) p b
$5 = {{-1207961984, 0, 1114472}, {6381016, 6319652, -1073745804}, {6416216, 14, 129100401}}
gdb) whatis b
type = int [variable][variable]
It may be also a discrepancy between gdb versions or some sort of bug, though the latter is always the last thing to consider.
EDIT:
I have build gdb 7.7 (CentOS 6.8 32-bit) from source and it displays the address of b instead of array content, so I confirm that issue is with this specific version and consider it has a potential bug or misfeature.
On the other hand, the latest version 7.11 behaves correctly.
GDB 7.7
[grzegorz#centos workspace]$ gdb-7.7/gdb/gdb -q a.out
Reading symbols from a.out...done.
(gdb) b main
Breakpoint 1 at 0x80483ab: file so.c, line 1.
(gdb) r
Starting program: /home/grzegorz/workspace/a.out
Breakpoint 1, main () at so.c:1
1 int main(void){
(gdb) s
2 int a[3][3] = {1};
(gdb) s
3 int m = 3;
(gdb)
5 int b[m][m];
(gdb)
6 x = sizeof(b);
(gdb) p b
$1 = 0xbffff0c0
GDB 7.11
[grzegorz#centos workspace]$ gdb-7.11/gdb/gdb -q a.out
Reading symbols from a.out...done.
(gdb) b main
Breakpoint 1 at 0x80483ab: file so.c, line 1.
(gdb) r
Starting program: /home/grzegorz/workspace/a.out
Breakpoint 1, main () at so.c:1
1 int main(void){
(gdb) s
2 int a[3][3] = {1};
(gdb)
3 int m = 3;
(gdb)
5 int b[m][m];
(gdb)
6 x = sizeof(b);
(gdb) p b
$1 = {{-1207961984, 0, 1114472}, {6381016, 6319652, -1073745676}, {6416216, 14, 129100401}}
Moral story: Either upgrade or downgrade your version of gdb to get correct behaviour

Related

struct member value zero but macro checking if it's zero returns 0, why?

in arch/arm64/include/asm/pgtable-types.h
typedef struct { pgdval_t pgd; } pgd_t;
#define pgd_val(x) ((x).pgd)
#define __pgd(x) ((pgd_t) { (x) } )
And in arch/arm64/include/asm/pgtable.h,
#define pgd_none(pgd) (!pgd_val(pgd))
I was in arch/arm64/mm/mmu.c during the debug using qemu and gdb, it read pgd entry in addr pgdp and if it's empty, fills it with pointer to bm_pud.
void __init early_fixmap_init(void)
{
pgd_t *pgdp, pgd;
pud_t *pudp;
pmd_t *pmdp;
unsigned long addr = FIXADDR_START;
pgdp = pgd_offset_k(addr);
pgd = READ_ONCE(*pgdp);
if (CONFIG_PGTABLE_LEVELS > 3 &&
!(pgd_none(pgd) || pgd_page_paddr(pgd) == __pa_symbol(bm_pud))) {
/*
* We only end up here if the kernel mapping and the fixmap
* share the top level pgd entry, which should only happen on
* 16k/4 levels configurations.
*/
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
pudp = pud_offset_kimg(pgdp, addr);
} else {
if (pgd_none(pgd)) <====== here!!
__pgd_populate(pgdp, __pa_symbol(bm_pud), PUD_TYPE_TABLE);
pudp = fixmap_pud(addr);
}
When gdb is at the line marked with <=== here!! above,
(gdb) p pgd
$4 = {pgd = 0x0}
(gdb) p pgd_none(pgd)
$5 = 0x0
The pgd value is 0, but the pgd_none output is also 0 when it should be 1(true) and it skipps the __pgd_populate function. What is wrong here?
What does (gdb) info func pgd_none say?
I suspect you are calling a function, not the macro you are intending to "call".
In fact, I am not sure GDB is even capable of evaluating a macro.
Update:
As ssbssa# noted, GDB is documented to support macro evaluation, and will do that automatically if the source is compiled with -g3.
However, there is a bug in GDB (current as of version 12.0.50.20220221-git) which prevents this from working, unless the code is compiled with -gdwarf-4.
Here is a trivial test:
#define FOO(x) (x - 42)
int main()
{
int x = 42;
return FOO(x);
}
Compile with gcc -g3 foo.c -gdwarf-4.
Reading symbols from ./a.out...
(gdb) start
Temporary breakpoint 1 at 0x112d: file foo.c, line 5.
Starting program: /tmp/a.out
Temporary breakpoint 1, main () at foo.c:5
5 int x = 42;
(gdb) n
6 return FOO(x);
(gdb) p FOO(1)
$1 = -41

Malloc'd memory cannot be accessed - GDB [duplicate]

The square root of 3, as estimated by Wolfram Alpha:
1.7320508075688772935274463415058723669428052538103806280558...
When I do sqrt(3) in C, it evaluates to 0. Why?
EDIT4: here's how you can reproduce this issue in GDB. Create test.c as follows:
#include <stdio.h>
#include <math.h>
int main()
{
printf("sqrt(3): %f\n", sqrt(3));
return 0;
}
Compile:
gcc -O0 -g -Wall -pedantic -ansi -lm -o test test.c
Run debugger:
gdb test
Enter this at console:
(gdb) break test.c:6
Breakpoint 1 at 0x400578: file test.c, line 6.
(gdb) r
Starting program: /home/pdedecker/Desktop/test
Breakpoint 1, main () at test.c:6
6 printf("sqrt(3): %f\n", sqrt(3));
(gdb) print sqrt(3)
$1 = 0
(gdb) s
sqrt(3): 1.732051
My GDB version is GNU gdb (GDB) SUSE (7.1-3.12).
The problem is not the missing function declaration (which isn't missing, since you did include <math.h>).
The problem is missing debug info for the sqrt you are actually using. Without that debug info, GDB has no clue what parameter type to pass to sqrt(), and what it returns.
You can get the required debug info on many Linux distributions by installing libc-debuginfo package. Here is what I see on such a system:
gdb -q ./a.out
Reading symbols from /tmp/a.out...done.
(gdb) b main
Breakpoint 1 at 0x400558: file t.c, line 6.
(gdb) r
Breakpoint 1, main () at t.c:6
6 printf("sqrt(3): %f\n", sqrt(3));
(gdb) p sqrt
$1 = {<text variable, no debug info>} 0x7ffff7b7fb50 <__sqrt>
Note: "no debug info"
(gdb) p sqrt(3)
$2 = 0
(gdb) p sqrt(3.0)
$3 = 0
Note: matches your behavior.
What sqrt functions do have debug info?
(gdb) info func sqrt
All functions matching regular expression "sqrt":
File ../sysdeps/x86_64/fpu/e_sqrt.c:
double __ieee754_sqrt(double);
File s_csqrt.c:
complex double __csqrt(complex double);
File ../sysdeps/x86_64/fpu/e_sqrtf.c:
float __ieee754_sqrtf(float);
File w_sqrtf.c:
float __sqrtf(float);
File s_csqrtf.c:
complex float __csqrtf(complex float);
File ../sysdeps/i386/fpu/e_sqrtl.c:
long double __ieee754_sqrtl(long double);
File w_sqrtl.c:
long double __sqrtl(long double);
File s_csqrtl.c:
complex long double __csqrtl(complex long double);
File ../sysdeps/ieee754/dbl-64/mpsqrt.c:
void __mpsqrt(mp_no *, mp_no *, int);
File w_sqrt.c:
double __sqrt(double);
(gdb) p __sqrt
$4 = {double (double)} 0x7ffff7b7fb50 <__sqrt>
Note: __sqrt is at the same address as sqrt, but GDB knows its type!
(gdb) p __sqrt(3)
$5 = 1.7320508075688772
(gdb) p __sqrt(3.0)
$6 = 1.7320508075688772
One can reasonably argue this is a bug in GDB. Feel free to create one in GDB bugzilla.
I predict that you didn't do #include <math.h>
Without a function declaration, C will default the return value of a function to int. A floating point number might come back as 0 depending on the size of your int. C will also not know how to convert the function argument. It will default to passing the argument as whatever type it happens to be. If you pass an integer to sqrt() it will not be converted to a double, but the sqrt() function will interpret the bit pattern as double.
To call a function without debug info, you must explicitly tell gdb the type for the return and arguments, using a function pointer cast. So, for your example:
(gdb) print ((double (*) (double)) sqrt) (3)
$1 = 1.7320508075688772
#include <stdio.h>
#include <math.h>
int main()
{
printf("sqrt(3): %f\n", sqrt(3));
return 0;
}
Output:
josh#josh-ubuntu:~/scratch$ ./a.out
sqrt(3): 1.732051
Maybe calling sqrt is not supported ! Maybe because it's a libc function. I don't know the deep reason why, but the following test shows an interesting behaviour:
double mysqrt(double x) { return sqrt(x) };
Then in a gdb session:
(gdb) p mysqrt(3)
$1 = 1.7320508075688772
(gdb) p sqrt(3)
$2 = -1209775368

GDB misses to display const qualifier?

Give the following source (main.c):
void foo(const char (*pa)[4])
{
}
int main(void)
{
const char a[4] = "bar";
foo(&a);
}
... compiled with GCC (gcc (Debian 4.9.2-10) 4.9.2) and run under GDB (GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1) ...
(gdb) b main
Breakpoint 1 at 0x4004c8: file main.c, line 7.
(gdb) b foo
Breakpoint 2 at 0x4004be: file main.c, line 3.
(gdb) r
Breakpoint 1, main () at main.c:7
7 const char a[4] = "bar";
(gdb) p &a
$1 = (const char (*)[4]) 0x7fffffffe1a0
(gdb) c
Continuing.
Breakpoint 2, foo (pa=0x7fffffffe1a0) at main.c:3
3 }
(gdb) p pa
$2 = (char (*)[4]) 0x7fffffffe1a0
... why does GDB show me (char (*)[4]) instead of (const char (*)[4]) as type for foo()'s parameter pa? What happened to the const qualifier? Or am I missing something essential? :-S
Update:
pa behaves as expected. If for example doing
char (*t)[4] = pa;
inside foo() the compiler complains:
warning: initialization from incompatible pointer type
Whereas doing
const char (*t)[4] = pa;
works fine.

Why does gdb evaluate sqrt(3) to 0?

The square root of 3, as estimated by Wolfram Alpha:
1.7320508075688772935274463415058723669428052538103806280558...
When I do sqrt(3) in C, it evaluates to 0. Why?
EDIT4: here's how you can reproduce this issue in GDB. Create test.c as follows:
#include <stdio.h>
#include <math.h>
int main()
{
printf("sqrt(3): %f\n", sqrt(3));
return 0;
}
Compile:
gcc -O0 -g -Wall -pedantic -ansi -lm -o test test.c
Run debugger:
gdb test
Enter this at console:
(gdb) break test.c:6
Breakpoint 1 at 0x400578: file test.c, line 6.
(gdb) r
Starting program: /home/pdedecker/Desktop/test
Breakpoint 1, main () at test.c:6
6 printf("sqrt(3): %f\n", sqrt(3));
(gdb) print sqrt(3)
$1 = 0
(gdb) s
sqrt(3): 1.732051
My GDB version is GNU gdb (GDB) SUSE (7.1-3.12).
The problem is not the missing function declaration (which isn't missing, since you did include <math.h>).
The problem is missing debug info for the sqrt you are actually using. Without that debug info, GDB has no clue what parameter type to pass to sqrt(), and what it returns.
You can get the required debug info on many Linux distributions by installing libc-debuginfo package. Here is what I see on such a system:
gdb -q ./a.out
Reading symbols from /tmp/a.out...done.
(gdb) b main
Breakpoint 1 at 0x400558: file t.c, line 6.
(gdb) r
Breakpoint 1, main () at t.c:6
6 printf("sqrt(3): %f\n", sqrt(3));
(gdb) p sqrt
$1 = {<text variable, no debug info>} 0x7ffff7b7fb50 <__sqrt>
Note: "no debug info"
(gdb) p sqrt(3)
$2 = 0
(gdb) p sqrt(3.0)
$3 = 0
Note: matches your behavior.
What sqrt functions do have debug info?
(gdb) info func sqrt
All functions matching regular expression "sqrt":
File ../sysdeps/x86_64/fpu/e_sqrt.c:
double __ieee754_sqrt(double);
File s_csqrt.c:
complex double __csqrt(complex double);
File ../sysdeps/x86_64/fpu/e_sqrtf.c:
float __ieee754_sqrtf(float);
File w_sqrtf.c:
float __sqrtf(float);
File s_csqrtf.c:
complex float __csqrtf(complex float);
File ../sysdeps/i386/fpu/e_sqrtl.c:
long double __ieee754_sqrtl(long double);
File w_sqrtl.c:
long double __sqrtl(long double);
File s_csqrtl.c:
complex long double __csqrtl(complex long double);
File ../sysdeps/ieee754/dbl-64/mpsqrt.c:
void __mpsqrt(mp_no *, mp_no *, int);
File w_sqrt.c:
double __sqrt(double);
(gdb) p __sqrt
$4 = {double (double)} 0x7ffff7b7fb50 <__sqrt>
Note: __sqrt is at the same address as sqrt, but GDB knows its type!
(gdb) p __sqrt(3)
$5 = 1.7320508075688772
(gdb) p __sqrt(3.0)
$6 = 1.7320508075688772
One can reasonably argue this is a bug in GDB. Feel free to create one in GDB bugzilla.
I predict that you didn't do #include <math.h>
Without a function declaration, C will default the return value of a function to int. A floating point number might come back as 0 depending on the size of your int. C will also not know how to convert the function argument. It will default to passing the argument as whatever type it happens to be. If you pass an integer to sqrt() it will not be converted to a double, but the sqrt() function will interpret the bit pattern as double.
To call a function without debug info, you must explicitly tell gdb the type for the return and arguments, using a function pointer cast. So, for your example:
(gdb) print ((double (*) (double)) sqrt) (3)
$1 = 1.7320508075688772
#include <stdio.h>
#include <math.h>
int main()
{
printf("sqrt(3): %f\n", sqrt(3));
return 0;
}
Output:
josh#josh-ubuntu:~/scratch$ ./a.out
sqrt(3): 1.732051
Maybe calling sqrt is not supported ! Maybe because it's a libc function. I don't know the deep reason why, but the following test shows an interesting behaviour:
double mysqrt(double x) { return sqrt(x) };
Then in a gdb session:
(gdb) p mysqrt(3)
$1 = 1.7320508075688772
(gdb) p sqrt(3)
$2 = -1209775368

accessing command-line arguments with gdb

I am on linux using gdb version 6.8-debian. I have been curious about how the main function in a c-program gets executed and playing around and looking in different places, I learned that the function __libc_start_main is responsiple for this. The arguments to __libc_start_main are, among others: The address of main (like we know from c, the path is always given as argv[0]), next argc which should reside in the register ESI, and next address of argv which should be in ECX.
To play around I made the following simple program, cmdargs.c, which simply outputs the first command-line argument given at start:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
printf("%s: %s\n", "argv[1]", *++argv);
return EXIT_SUCCESS;
}
Now I start to debug cmdargs and set a breakpoint on main and __libc_start_main (info from starting gdb removed):
gdb cmdargs
(gdb) b main
Breakpoint 1 at 0x80483d2
(gdb) b __libc_start_main
Breakpoint 2 at 0xb7f3f5a8
(gdb) r qwerty
Here i hit the Breakpoint 2 in __libc_start_main and can view argc and argv[0] with
(gdb) p $esi
and
(gdb) x/s *($ecx)
This works as expected, but how do I access the first non-implicit commandline-argument "qwerty" ? I have tried continuing to the breakpoint at main and stepping in, but argc and argv are not recognised (Why?). Can someone tell me whats going on ?
Breakpoint 1, 0x080483d2 in main ()
(gdb) stepi
0x080483d5 in main ()
(gdb) p argc
No symbol "argc" in current context.
(gdb) p argv
No symbol "argv" in current context.
(gdb)
Yep, your problem is the lack of symbols, not included at compilation time.
To compile with debugging information:
$ gcc -g3 cmdargs.c -o cmdargs
Then:
$ gdb ./cmdargs
...
Reading symbols from ./cmdargs...done.
(gdb) b main
Breakpoint 1 at 0x400545: file cmdargs.c, line 6.
(gdb) r
Starting program: cmdargs
Breakpoint 1, main (argc=1, argv=0x7fffffffdc28) at cmdargs.c:6
6 printf("%s: %s\n", "argv[1]", *++argv);
(gdb) p argc
$1 = 1
(gdb) p argv
$2 = (char **) 0x7fffffffdc28
(gdb) p *argv
$3 = 0x7fffffffe00c "/home/jcgonzalez/cmdargs"
See, now you get access to the symbols (they are recognized), as well as to the line numbers. As shown by Let_Me_Be, you can access single array elements with array[n] notation, but you can also show all the command line arguments at once (including the [0]-ed one) with the *array#times notation. Note that the first argument in the following example is a quoted string:
(gdb) set args "this is an argument" these are four more
(gdb) r
Starting program: cmdargs "this is an argument" these are four more
Breakpoint 1, main (argc=6, argv=0x7fffffffdbd8) at cmdargs.c:6
6 printf("%s: %s\n", "argv[1]", *++argv);
(gdb) p argc
$4 = 6
(gdb) p *argv#argc
$5 = {0x7fffffffdfe6 "/home/jcgonzalez/cmdargs", 0x7fffffffdfff "this is an argument", 0x7fffffffe012 "these", 0x7fffffffe017 "are", 0x7fffffffe01b "four",
0x7fffffffe020 "more"}
(gdb) p argv[1]
$6 = 0x7fffffffdfff "this is an argument"
(gdb) p argv[2]
$7 = 0x7fffffffe012 "these"
The output looks as if you don't have enough debuging information. GDB shouldn't print only addresses but line numbers as well.
(gdb) b main
Breakpoint 1 at 0x400543: file test.c, line 3.
(gdb) r test1 test2
Starting program: /home/simon/a.out test1 test2
Breakpoint 1, main (argc=3, argv=0x7fffffffdca8) at test.c:3
3 puts("blabla");
(gdb) print argc
$1 = 3
(gdb) print argv
$2 = (char **) 0x7fffffffdca8
(gdb) print argv[0]
$3 = 0x7fffffffe120 "/home/simon/a.out"
(gdb) print argv[1]
$4 = 0x7fffffffe132 "test1"
(gdb) print argv[2]
$5 = 0x7fffffffe138 "test2"
(gdb)
you should add the -g options to gcc, which tells it to build debug info too..

Resources