gdb printing array/strings with a certain offset - c

I have the following defined:
strings: .asciz "Once\n", "upon\n", "a\n", "time\n", "...\n", ""
And I can see the label is stored at the following memory address, 600109:
>>> info va strings
Non-debugging symbols:
0x0000000000600109 strings
I can print this as:
>>> x/s 0x0000000000600109
0x600109: "Once\n"
>>> x/s 0x0000000000600109+6
0x60010f: "upon\n"
# etc...
Or referencing the variable to get the first string:
>>> x/s &strings
0x600109: "Once\n"
How do I do proper offsets in gdb to do addition on the memory address -- for example, to be able to do x/s &strings+6 to get the value "upon\n"?
What would be the correct way to do the following?
>>> x/s &strings+6
# Cannot perform pointer math on incomplete type "<data variable, no debug info>", try casting to a known type, or void *.

You need to cast this to (void *) to be able to do addition/subtraction on the memory address:
>>> x/s 6 + (void *) &strings
0x60010f: "upon\n"

Related

Assign string stored in memory into a GDB variable

When debugging a C program, how can I assign a string (array of bytes terminated by \0 byte) stored at some known memory location into a GDB convenience variable?
E.g.:
There is a string "hello_world" stored at memory location 0xAAAAAAAA, how can I store the string into a GDB variable string_variable using that memory location? Using (gdb) set $string_Variable = (char *) 0xAAAAAAAA stores the address and not the string itself.
A string convenience variable in GDB is an array of char:
(gdb) set $foo = "bbb"
(gdb) ptype $foo
type = char [4]
Using GDB's CLI, I can't find a straightforward way to create a string convenience variable from an address of a NUL-terminated string of bytes in the debuggee.
What does work is to use GDB's Python extension to get a gdb.Value from the debuggee, then convert it to a string:
(gdb) python gdb.set_convenience_variable("string_variable", gdb.parse_and_eval("(char *)0x555555556011").string())
(gdb) ptype $string_variable
type = char [12]
(gdb) p $string_variable
$3 = "hello_world"

Resolving memory address in gdb indirection

After compiling with -g to get debug info in a program and running in gdb, I can do the following to print the argument vector:
>>> p __libc_argv
$2 = (char **) 0x7fffffffe9f8
>>> p __libc_argv[0]
$3 = 0x7fffffffec63 "./sample.out"
My question is two-fold:
Why doesn't __libc_argv[0] and __libgc_argv produce the same memory address? Does gdb do some sort of interpretation in the background?
How could I get the memory address of 0x7fffffffec63 from the above? For example:
>>> p __libc_argv
$2 = (char **) 0x7fffffffe9f8
>>> x/s 0x7fffffffec63 <-- how do figure out this memory address value?
0x7fffffffec63: "./sample.out"
__libc_argv is a pointer to an array of pointers. __libc_argv[0] is the contents of the first element of that array. There's no reason why they should be the same, unless you first did __libc_argv[0] = __libc_argv for some reason. But that wouldn't be reasonable, since the elements of __libc_argv should be pointers to strings, not pointers to arrays.
On the other hand, __libc_argv == &__libc_argv[0] and *__libc_argv == __libc_argv[0].
To get the address you want, just indirect through __libc_argv.
>>> x/s *__libc_argv

GDB debugger : char array type examine and print command

In C program i have declared a buffer of characters: char buffer_in[500];
When i run this program step by step on GDB i test the buffer reference with this commands:
(gdb) ptype buffer_in
type = char [500]
(gdb) ptype &buffer_in
type = char (*)[500]
(gdb) p &buffer_in
$9 = (char (*)[500]) 0x7fffffffdb60
(gdb) x buffer_in
0x7fffffffdb60: 0x2e
(gdb) x &buffer_in
0x7fffffffdb60: 0x2e
In C if I declared and array of characters the object is referenced like a pointer. I &buffer_in it is the address of first element of the array why the output of command x buffer_in is the same than x &buffer_in ?. I think that x buffer_in must trie to examine 0x2e address and so it is wrong referenced.
Thanks
So, gdb's x command expects a memory address - the command's purpose is to dump some memory in hex. If you give it an array variable, it will assume you mean you want it to dump starting at the address the array is stored at. If you give it a pointer to an array variable, it will assume you mean you want it to dump starting at that pointer. Those two are the same - this is much like the way C is actually compiled.
To put a finer point on it,
printf("0x%8.8lX 0x%8.8lX\n", (unsigned long)buffer_in, (unsigned long)&buffer_in);
prints the same number twice. So you'd expect gdb to dump the same byte from memory when asked to dump each address expression.

Understand pointers in C

I'm reviewing my C skills, and I'm struggling to understand some bits.
Here's my understanding of C and pointers.
Every time I declare a variable, C stores the value in memory.
int num = 12; // The 12 is stored somewhere in memory, let's say has address 0x54
To get the memory address of variable "num" we do:
printf("%p", &num); // this returns the 0x54
if I want to create a pointer, that points to the same value of "num", I do:
int *ptr = &num; // create a pointer and point him to 0x54
If I check both address:
printf("%p\n", &num); // prints 0x54
printf("%p\n", ptr); // prints 0x54
printf("%p\n", &ptr); // prints 0x94 is the address of the pointer itself
After the above...
I don't understand the output of my program.
I'm reading this book, and the author says that we can treat pointers as arrays and vice versa (except in some cases [if I understood correctly]).
int ages[] = { 23, 43, 12, 89, 2 };
printf("1-%d\n", ages[0]);
printf("1-%d\n", ages[1]);
printf("2-%p\n", &ages[0]);
printf("2-%p\n", ages);
printf("2-%p\n", &ages);
printf("3-%d\n", *(&ages[1]));
printf("4-%p\n", *(&ages));
printf("5-%p\n", &ages[1]);
printf("6-%p\n", &ages+1);
printf("7-%d\n", *(*(&ages)+1));
printf("8-%ld\n", sizeof(1));
Output with questions in comments:
1-23 // value of position 0, OK
1-43 // value of position 1, OK
2-0x7fff1fd500f0 // adress of the beginning of array, OK
2-0x7fff1fd500f0 // same as above, OK
2-0x7fff1fd500f0 // because ages is not a pointer, same as above, OK
3-43 // get address of ages, advance 4 bytes and then give me the value that is in that address, OK
4-0x7fff1fd500f0 // give me the address of ages, and then give the value that is in that address. The address I have in the print number 2, why doesn't return the value and show me the address? **NOT OK**
5-0x7fff1fd500f4 // give me the address of the position 1 of the array, the address that contains the number 43, OK
6-0x7fff1fd50104 // why I don't get the same number of the print 5? How I jump from f0 to 104? **NOT OK**
7-43 // why I need pointer of pointer, **NOT OK**
8-4 // this was just trying to understand print 6, OK
Can someone explain me prints 4, 6 and 7, and let me know if I'm thinking correctly on the other prints.
Your confusions all boil down to two things: how operator precedence works and what &ages means.
Let's look at the latter first. Obviously &ages is a pointer. But what is it a pointer to? It's not a pointer to int. Instead, it's a pointer to the type int[5].
So let's look at this:
printf("4-%p\n", *(&ages));
If you have a pointer to int[5], and you use * on it, you get what it points to: int[5]. This then decays to a pointer when being passed to printf. Specifically, a pointer to the first element of the array.
This:
printf("5-%p\n", &ages[1]);
Is a matter of operator precedence. Using explicit parenthesis, this is &(ages[1]); [] has higher precedence than &. Well, we know that ages[1] is the second int in the array. Using & on it will return a pointer to the second element in the array.
In a similar way:
printf("6-%p\n", &ages+1);
Operator precedence tells us that this is really (&ages) + 1. And remember, what is &ages? That's right, a pointer to int[5].
When we perform pointer arithmetic, we add the size of the object being pointed to to the address. That object is int[5], whose size is 20. Or in hex, 0x14. Therefore, you get an address 0x14 bytes from the start of the array.
As for:
printf("7-%d\n", *(*(&ages)+1));
Operator precedence tells us that this expression is really *((*(&ages)) + 1). So you get a pointer to int[5], turn it back into an int[5], then add 1 to it. That requires decaying the int[5] into an int*, then using pointer arithmetic. Then you access the value at that address.
A pointer is not just an address, it's an address with an associated type, which has a size.
Thus when you increment a pointer to array type, it skips the whole array.
Another issue in the code is array decay, where an expression that denotes an array, such as a or *&a, decays to a pointer to the first item of the array.
It's an unfortunate implicit conversion that made sense at the time of early C.
In C++ it causes much trouble.
arrays are too much efficient but the overhead of an array is the size which cannot be changed at runtime.
pointer is a variable of some type which has its address and type of data it points to eg:
//int* iPtr = 7; error pointers stores addresses not values
int* iPtr = 0x00000000 //(NULL) points to this address (correct);
above a pointer points to an integer is initialized to point to 0x00000000 which is NULL
int a = 7;
int* iPtr = &a;
cout << "a: " << a << endl; // printing value of a; result is a: 7
cout << "&a: " << &a << endl; // printing address of a: result is: &a: 0x0018FF44
cout << "iPtr: " << iPtr << endl; // printing the address iPtr points to as you guess it is the address of a so the result: iPtr: 0x0018FF44
cout << "*iPtr: " << *iPtr << endl; // printing the value stored in the address the iPtr points to so the result is as you guess: *iPtr: 7
the powerful use of pointers: they are too much flexible but dangerous they can point to an array, variable, changing the address, size at runtime...
they are used by linked-list, oop (polymorphism...)
*** don't mess with pointers
For #4, it's likely the result of compiler optimization. Taking the address and then immediately dereferencing the resulting pointer is effectively a no-op, so the optimizer's likely simply eliding those operations leaving just ages as the argument and that's the value you're seeing.
For #6, you're finding the address of the ages array and adding 1 to it, which in pointer arithmetic means "add 1 * the size of the variable pointed at". A 5-element array, assuming 4-byte integers, is 20 bytes long and if you check 0x7FFF1FD500F0 + 0x14 you get the result 0x7FFF1FD50104 that you see.
An array isn't a pointer, exactly. It acts a lot like one, but &(ages) isn't identical to &(ages[0]). Both have the same apparent value, but the former is a pointer to a 4-byte integer and the latter is a pointer to a 20-byte array of 4-byte integers. You have to keep that in mind when working with pointers to array elements, remembering to take the address of an element when you want to work within the array and need eg. the address of element 0 of the array and not the address of the array itself.

Get address of a string-constant in C

I would like to get the address of an string-constant in C.
char * const MYCONST = "StringString";
As far as I know consts are "saved" in the Text/Code Segment of the memory.
When I try to get the address of the first element in MYCONSt:
printf("%p\n",&(MYCONST));
As result I get 0x7fff15342e28, which is in the stack and not in the Text/Code segement.
Can anybody please help me get the address of a string-constant in C?
//edit
I can't find the correct answer so far: When I write
char * const MYCONST1 = "StringString";
printf("Address of MYCONST1: %p\n",MYCONST1);
char * const MYCONST2 = "StringString";
printf("Address of MYCONST2: %p\n",(void*)MYCONST2);
this is the output:
Address of MYCONST1: 0x400b91
Address of MYCONST2: 0x400b91
But they should have different addresses, because the are different constants.
Can anybody explain me while the result has a length of seven and not 0x7fffa5dd398c like a locale variable.
Thanks!
Since MYCONST is already a pointer, you do not need an ampersand. All you need is a cast to void* for the %p:
printf("%p\n",(void*)MYCONST);
With an ampersand, you print the address of the MYCONST local variable (you need a void* cast there as well, otherwise the address may print incorrectly), which is indeed located on the stack.
printf("%p\n",(void *) &MYCONST);
prints the address of the MYCONST pointer variable.
printf("%p\n", (void *) MYCONST);
prints the value of the MYCONST pointer variable.
Q: //edit I can't find the correct answer so far: When I write
char * const MYCONST1 = "StringString";
printf("Address of MYCONST1: %p\n",MYCONST1);
char * const MYCONST2 = "StringString";
printf("Address of MYCONST2: %p\n",(void*)MYCONST2);
this is the output:
Address of MYCONST1: 0x400b91
Address of MYCONST2: 0x400b91
But they should have different addresses, because the are different constants.
A: Since both the pointers point to same string literal. Compiler optimizes and let them share the same data and hence same address. Try compiling your code with
gcc program_name.c -O
and see. You will see the addresses different.
Relative: Addresses of two pointers are same
Address of the first character of a C string is in the variable of the string itself, i.e. MYCONST in your case.
char * const MYCONST = "StringString";
initializes a pointer MYCONST, making it point to the memory where this string literal is stored.
To print an address of this string, use the pointer's value:
printf("%p\n", (void*) MYCONST);
instead of
printf("%p\n", (void*) &MYCONST);
which prints the address of pointer itself.
printf("%p\n",(void*)MYCONST);
Will print the address of the first element of string MYCONST points to.
The reason I didn't put & before MYCONST is because MYCONST is already a pointer.
If you need to print the address of Pointer, then you need to do like &MYCONST.

Resources