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.
Related
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
I have this small program:
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[]) {
printf("argv[1] -> %s\n", argv[1]);
}
Which I analyzed in gdb with the following commands:
$ gdb -q --args foo hello
Reading symbols from foo...
(gdb) break main
Breakpoint 1 at 0x1148: file foo.c, line 5.
(gdb) run
Starting program: /tmp/foo/foo hello
Breakpoint 1, main (argc=2, argv=0x7fffffffea68) at foo.c:5
5 printf("argv[1] -> %s\n", argv[1]);
(gdb) print argv#2
$1 = {0x7fffffffea68, 0x200000000}
(gdb) print *argv#2
$2 = {0x7fffffffecd8 "/tmp/foo/foo", 0x7fffffffece5 "hello"}
I don't understand how argv[1] can yield the string "hello" when the content of argv[1] is
0x200000000 and not 0x7fffffffece5 which is the actual address of the string "hello".
print argv#2 doesn't do what you think it does. Instead of printing argv[0] and argv[1], it appears to print (&argv)[0] and (&argv)[1].
Here's what I got when I tried debugging your program:
(gdb) p argv
$1 = (char **) 0x7fffffffecd8
(gdb) p argv[0]
$2 = 0x7fffffffeeb8 "/home/a.out"
(gdb) p argv[1]
$3 = 0x0
(gdb) p argv#2
$4 = {0x7fffffffecd8, 0x100000000}
(gdb) p (&argv)[1]
$5 = (char **) 0x100000000
I used the examine command in gdb and now things make sense:
(gdb) x/2xg argv
0x7fffffffea58: 0x00007fffffffecc2 0x00007fffffffecd5
(gdb) x/1s 0x00007fffffffecc2
0x7fffffffecc2: "/tmp/foo/foo"
(gdb) x/1s 0x00007fffffffecd5
0x7fffffffecd5: "hello"
(gdb)
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
I am compiling the simple code below, and run it in gdb. I set a break point at the strcpy line, as soon as I run it for the input for instance abc, and then press s, I get the following error:
Breakpoint 1, main (argc=2, argv=0x7fffffffdd98) at ExploitMe.c:9
9 strcpy(buffer, argv[1]);
(gdb) s
__strcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:48
48 ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory.
I am using ubuntu 12.04 AMD64 and gcc 2.15. Any idea?
main(int argc, char *argv[]) {
char buffer[80];
strcpy(buffer, argv[1]);
return 0;
}
It is completely harmless to ignore these "errors" when debugging.
The error is simply because GDB is looking for the source of the strcpy function. Any function in libc that you don't have the source for will you give a similar error, e.g.:
int *p = malloc(sizeof *p);
Then...
(gdb) s
5 int *p = malloc(sizeof *p);
(gdb) s
__GI___libc_malloc (bytes=4) at malloc.c:2910
2910 malloc.c: No such file or directory.
You can always download GNU libc's source and link it with GDB:
git clone https://github.com/jeremie-koenig/glibc /opt/src/glibc
Then...
(gdb) dir /opt/src/glibc/malloc
(gdb) s
5 int *p = malloc(sizeof *p);
(gdb) s
__GI___libc_malloc (bytes=4) at malloc.c:2910
2910 }
(gdb) s
2915 } else if (!in_smallbin_range(size))
... which will let you step through malloc's source code. It's not particularly useful, but it can come in handy sometimes.
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..