Reputation: 1513
Using a very simple sample that uses an int pointer to point to a structure with longs. Granted it isn't the preferred method but it is being done to mimic other code. The objective is to view the data in the register before the free call.
This is the code.
#include <stdio.h>
#include <stdlib.h>
//#include <unistd.h>
typedef struct
{
unsigned long x;
unsigned long y;
unsigned long z;
}
myStruct;
int main () {
int *p_Struct = (int *)0;
int size = sizeof (myStruct);
printf("Size of (bytes)...\n");
printf(" myStruct : %d\n", sizeof (myStruct));
p_Struct = ( int*) malloc(size);
memset((int *)p_Struct, 0, size);
((myStruct *)p_Struct)->x = 111;
((myStruct *)p_Struct)->y = 222;
((myStruct *)p_Struct)->z = 333;
free(p_Struct);
return(0);
}
Using the following gdb version to step through the code.
Using > gdb GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-94.el7
Gdb is used to start the application then disassembled to acquire the line of code for the free command.
(gdb) disassemble main
Dump of assembler code for function main:
0x000000000040064d <+0>: push %rbp
0x000000000040064e <+1>: mov %rsp,%rbp
0x0000000000400651 <+4>: sub $0x10,%rsp
=> 0x0000000000400655 <+8>: movq $0x0,-0x8(%rbp)
0x000000000040065d <+16>: movl $0x18,-0xc(%rbp)
0x0000000000400664 <+23>: mov $0x400770,%edi
0x0000000000400669 <+28>: callq 0x400500 <puts@plt>
0x000000000040066e <+33>: mov $0x18,%esi
0x0000000000400673 <+38>: mov $0x400783,%edi
0x0000000000400678 <+43>: mov $0x0,%eax
0x000000000040067d <+48>: callq 0x400510 <printf@plt>
0x0000000000400682 <+53>: mov -0xc(%rbp),%eax
0x0000000000400685 <+56>: cltq
0x0000000000400687 <+58>: mov %rax,%rdi
0x000000000040068a <+61>: callq 0x400550 <malloc@plt>
0x000000000040068f <+66>: mov %rax,-0x8(%rbp)
0x0000000000400693 <+70>: mov -0xc(%rbp),%eax
0x0000000000400696 <+73>: movslq %eax,%rdx
0x0000000000400699 <+76>: mov -0x8(%rbp),%rax
0x000000000040069d <+80>: mov $0x0,%esi
0x00000000004006a2 <+85>: mov %rax,%rdi
0x00000000004006a5 <+88>: callq 0x400520 <memset@plt>
0x00000000004006aa <+93>: mov -0x8(%rbp),%rax
0x00000000004006ae <+97>: movq $0x6f,(%rax)
0x00000000004006b5 <+104>: mov -0x8(%rbp),%rax
0x00000000004006b9 <+108>: movq $0xde,0x8(%rax)
0x00000000004006c1 <+116>: mov -0x8(%rbp),%rax
0x00000000004006c5 <+120>: movq $0x14d,0x10(%rax)
0x00000000004006cd <+128>: mov -0x8(%rbp),%rax
0x00000000004006d1 <+132>: mov %rax,%rdi
0x00000000004006d4 <+135>: callq 0x4004f0 <free@plt>
0x00000000004006d9 <+140>: mov $0x0,%eax
0x00000000004006de <+145>: leaveq
0x00000000004006df <+146>: retq
End of assembler dump.
Using the specific line of code, a break point is set on free.
(gdb) break *0x00000000004006d4
Continue until the code breaks on the free command.
(gdb) continue
Continuing.
Size of (bytes)...
myStruct : 24
Breakpoint 2, 0x00000000004006d4 in main () at freeQuestion.c:28
28 free(p_Struct);
Display the available registers.
(gdb) info reg
rax 0x602010 6299664
rbx 0x0 0
rcx 0x602010 6299664
rdx 0x18 24
rsi 0x0 0
rdi 0x602010 6299664
rbp 0x7fffffffc160 0x7fffffffc160
rsp 0x7fffffffc150 0x7fffffffc150
r8 0x602000 6299648
r9 0x18 24
r10 0x7fffffffbed0 140737488338640
r11 0x2aaaaad56700 46912498919168
r12 0x400560 4195680
r13 0x7fffffffc240 140737488339520
r14 0x0 0
r15 0x0 0
rip 0x4006d4 0x4006d4 <main+135>
eflags 0x283 [ CF SF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb)
I assume that rdi register will house the data that is being freed at address 0x602010. To be sure all the data will be visible the examine command is executed to display 80 bytes of data starting 16 bytes prior.
(gdb) x/80d 0x602000
0x602000: 0 0 0 0 0 0 0 0
0x602008: 33 0 0 0 0 0 0 0
0x602010: 111 0 0 0 0 0 0 0
0x602018: -34 0 0 0 0 0 0 0
0x602020: 77 1 0 0 0 0 0 0
0x602028: -31 15 2 0 0 0 0 0
0x602030: 0 0 0 0 0 0 0 0
0x602038: 0 0 0 0 0 0 0 0
0x602040: 0 0 0 0 0 0 0 0
0x602048: 0 0 0 0 0 0 0 0
(gdb)
From the above, 111 is visible but not 222, or 333.
How can all the data (111,222,333) be viewed prior to the free command being executed?
Upvotes: 0
Views: 845
Reputation: 213516
From the above, 111 is visible but not 222, or 333.
There is no way that you could have observed this output while stopped before the CALL free
instruction. We clearly see that values 0x6f == 111
, 0xde == 222
and 0x14d == 333
are loaded at offset 0, 8 and 16 from $RAX
:
0x00000000004006ae <+97>: movq $0x6f,(%rax)
0x00000000004006b9 <+108>: movq $0xde,0x8(%rax)
0x00000000004006c5 <+120>: movq $0x14d,0x10(%rax)
and then $RAX
is copied to $RDI
just before the call to free
:
0x00000000004006d1 <+132>: mov %rax,%rdi
0x00000000004006d4 <+135>: callq 0x4004f0 <free@plt>
Here is the expected output (that I observe with your program):
(gdb) p/x $rdi
$1 = 0x602420
(gdb) x/6d $rdi
0x602420: 111 0 222 0
0x602430: 333 0
But if you execute nexti
(to step over the call to free
), then the values can be overwritten (you can't expect the contents of now free
d memory to be anything in particular).
After nexti
, I observe:
(gdb) x/6d 0x602420
0x602420: 0 0 222 0
0x602430: 333 0
but it could just as easily be 111 0 0 0 0 0
that you observed.
Upvotes: 2