I used gdb generate-core-file to generate a core file for a process (mongod), but the process mmap many data files and the Res of this process is up to 36.1G.
after the core file consumed 34G space, no more space are available on disk, so I got:
warning: writing note section (No space left on device)
Saved corefile core.12038
I want to know if all the mmap data will be dump to core file? What can I do if I only want to see some local variables?
background:
we had an issue on production, and the binary on production don't have symbol info in it. so I want to generate core file and do some analyse offline.
I want to know if all the mmap data will be dump to core file?
Usually the kernel only dumps writable mmaps, but not read-only ones. However, this is configurable: see core(5) man page (the "Controlling which mappings are written to the core dump" part).
background: we had an issue on production, and the binary on production don't have symbol info in it.
The "standard" approach is to debug such binaries remotely with gdbserver and connect to it with gdb that does have access to full-debug binary.
What can I do if I only want to see some local variables?
background: we had an issue on production, and the binary on production don't have symbol info in it.
You have not mention OS in your question so if you on Linux
1) Install on a production server your program with debugging information
2) If you cannot do this analyze assembler code of a function you are intrested in and get values of local variables from assembler
And then use SystemTap to trace your program.
Let me illustrate both approaches with a simple example.
First, C++ program to analyze:
>cat main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int f(int arg)
{
int a = arg+1;
int b = arg+2;
int c = a + b;
printf ("printf in program: f, c: %d\n", c);
return c;
}
int main(int argc, char *argv[])
{
printf ("f: %p\n", &f);
int sum = 0;
while (true) {
for (int i= atoi(argv[1]); i < atoi(argv[2]); ++i) {
sum += f(i);
}
sleep(5);
}
printf("Sum: %d\n", sum);
return 0;
}
So I want to get value of the local variable "c" in the function f().
1) If symbol information is available
>cat measure_f.stp
probe process("a.out").statement("*#main.cpp:10")
{
printf("SystemTap, time: %s, the local variable c :%d\n", ctime(gettimeofday_s()), $c)
}
>sudo stap measure_f.stp -c "./a.out 21 23"
f: 0x400634
printf in program: f, c: 45
printf in program: f, c: 47
SystemTap, time: Fri Dec 27 12:59:31 2013, the local variable c :45
SystemTap, time: Fri Dec 27 12:59:31 2013, the local variable c :47
printf in program: f, c: 45
printf in program: f, c: 47
SystemTap, time: Fri Dec 27 12:59:36 2013, the local variable c :45
SystemTap, time: Fri Dec 27 12:59:36 2013, the local variable c :47
1) If symbol information is not available then use assembler
First disassemble your function and find what address you will monitor
(gdb) disassemble /m f
Dump of assembler code for function f(int):
6 {
0x0000000000400634 <+0>: push %rbp
0x0000000000400635 <+1>: mov %rsp,%rbp
0x0000000000400638 <+4>: sub $0x20,%rsp
0x000000000040063c <+8>: mov %edi,-0x14(%rbp)
7 int a = arg+1;
0x000000000040063f <+11>: mov -0x14(%rbp),%eax
0x0000000000400642 <+14>: add $0x1,%eax
0x0000000000400645 <+17>: mov %eax,-0xc(%rbp)
8 int b = arg+2;
0x0000000000400648 <+20>: mov -0x14(%rbp),%eax
0x000000000040064b <+23>: add $0x2,%eax
0x000000000040064e <+26>: mov %eax,-0x8(%rbp)
9 int c = a + b;
0x0000000000400651 <+29>: mov -0x8(%rbp),%eax
0x0000000000400654 <+32>: mov -0xc(%rbp),%edx
0x0000000000400657 <+35>: lea (%rdx,%rax,1),%eax
0x000000000040065a <+38>: mov %eax,-0x4(%rbp)
10 printf ("printf in program: f, c: %d\n", c);
0x000000000040065d <+41>: mov -0x4(%rbp),%eax
0x0000000000400660 <+44>: mov %eax,%esi
0x0000000000400662 <+46>: mov $0x4007f8,%edi
0x0000000000400667 <+51>: mov $0x0,%eax
0x000000000040066c <+56>: callq 0x4004f8 <printf#plt>
11 return c;
0x0000000000400671 <+61>: mov -0x4(%rbp),%eax
12 }
0x0000000000400674 <+64>: leaveq
0x0000000000400675 <+65>: retq
As you can see in order to get the local variable c it is necessary on 0x000000000040065a to get the register %eax
> cat measure_f_2.stp
probe begin
{
printf("Monitoring process %d\n", $1)
}
probe process($1).statement(0x000000000040065a).absolute
{
printf("SystemTap (2), time: %s, the local variable c (rax):%d\n", ctime(gettimeofday_s()), register("rax"))
}
So I started "./a.out 21 23" and then run my SystemTap script
>sudo stap measure_f_2.stp 11564
Monitoring process 11564
SystemTap (2), time: Fri Dec 27 13:15:09 2013, the local variable c (rax):45
SystemTap (2), time: Fri Dec 27 13:15:09 2013, the local variable c (rax):47
SystemTap (2), time: Fri Dec 27 13:15:14 2013, the local variable c (rax):45
SystemTap (2), time: Fri Dec 27 13:15:14 2013, the local variable c (rax):47
Related
C++ standard says that it is unspecified whether or not a reference requires storage (3.7).. However, as far as I understand, gcc implements C++ references as pointers and as such they can be corrupted.
Is it possible to get an address of a reference in gdb and put a hardware breakpoint on that address in order to find out what corrupts the memory where the reference resides? How can one set such a breakpoint?
GDB may does hardware watchpointing. You can use command watch for this. Example:
main.cpp:
int main(int argc, char **argv)
{
int a = 0;
int& b = a;
int* c = &a;
*c = 1;
return 0;
}
Start debugging and set breakpoint on start main function and end main function:
(gdb) b main
Breakpoint 1 at 0x401bc8: file /../main.cpp, line 60.
(gdb) b main.cpp:65
Breakpoint 2 at 0x401be9: file /../main.cpp, line 65.
(gdb) r
Get address of reference b:
Breakpoint 1, main (argc=1, argv=0x7fffffffddd8) at /../main.cpp:60
60 int a = 0;
(gdb) disas /m
Dump of assembler code for function main(int, char**):
59 {
... Something code
60 int a = 0;
=> 0x0000000000401bc8 <+11>: movl $0x0,-0x14(%rbp)
61 int& b = a;
0x0000000000401bcf <+18>: lea -0x14(%rbp),%rax
0x0000000000401bd3 <+22>: mov %rax,-0x10(%rbp)
62 int* c = &a;
0x0000000000401bd7 <+26>: lea -0x14(%rbp),%rax
0x0000000000401bdb <+30>: mov %rax,-0x8(%rbp)
63 *c = 1;
0x0000000000401bdf <+34>: mov -0x8(%rbp),%rax
0x0000000000401be3 <+38>: movl $0x1,(%rax)
64
65 return 0;
0x0000000000401be9 <+44>: mov $0x0,%eax
66 }
0x0000000000401bee <+49>: pop %rbp
0x0000000000401bef <+50>: retq
End of assembler dump.
(gdb) p $rbp-0x10
$1 = (void *) 0x7fffffffdce0
p $rbp-0x10 is printing address of reference b. It is 0x7fffffffdce0.
Set this address for watching:
(gdb) watch *0x7fffffffdce0
Hardware watchpoint 3: *0x7fffffffdce0
(gdb) c
GDB break only if value is changed:
(gdb) c
Continuing.
Hardware watchpoint 3: *0x7fffffffdce0
Old value = -8752
New value = -8996
main (argc=1, argv=0x7fffffffddd8) at /../main.cpp:62
62 int* c = &a;
Sorry for my english!
According to https://www.ethicalhacker.net/columns/heffner/intro-to-assembly-and-reverse-engineering
mov 0xffffffb4,0x1
moves the number 1 into 0xffffffb4.
So, I decided to test this on my own.
In GDB, x is the command to print the value of memory address.
However, when I run
x 0x00000000004004fc
I'm not getting the value of 133 (decimal) or 85 (hexadecimal)
Instead, I'm getting 0x85f445c7. Any idea what is this?
me#box:~/c$ gdb -q test
Reading symbols from test...done.
(gdb) l
1 #include <stdio.h>
2
3 int main(){
4 int a = 1;
5 int b = 13;
6 int c = 133;
7 printf("Value of C : %d\n",c);
8 return 0;
9 }
(gdb) b 7
Breakpoint 1 at 0x400503: file test.c, line 7.
(gdb) r
Starting program: /home/me/c/test
Breakpoint 1, main () at test.c:7
7 printf("Value of C : %d\n",c);
(gdb)
Disassemble
(gdb) disas
Dump of assembler code for function main:
0x00000000004004e6 <+0>: push %rbp
0x00000000004004e7 <+1>: mov %rsp,%rbp
0x00000000004004ea <+4>: sub $0x10,%rsp
0x00000000004004ee <+8>: movl $0x1,-0x4(%rbp)
0x00000000004004f5 <+15>: movl $0xd,-0x8(%rbp)
0x00000000004004fc <+22>: movl $0x85,-0xc(%rbp)
=> 0x0000000000400503 <+29>: mov -0xc(%rbp),%eax
0x0000000000400506 <+32>: mov %eax,%esi
0x0000000000400508 <+34>: mov $0x4005a4,%edi
0x000000000040050d <+39>: mov $0x0,%eax
0x0000000000400512 <+44>: callq 0x4003c0 <printf#plt>
0x0000000000400517 <+49>: mov $0x0,%eax
0x000000000040051c <+54>: leaveq
0x000000000040051d <+55>: retq
End of assembler dump.
(gdb) x 0x00000000004004fc
0x4004fc <main+22>: 0x85f445c7
(gdb)
;DRTL
To print a value in GDB use print or (p in short form) command.
in your command
x 0x00000000004004fc
You have missed p command. You have to use x with p command pair to print value as hexadecimal format, like below:
(gdb) p/x 0x00000000004004fc
If the memory address is some pointer to some structure then you have to cast the memory location before using the pointer. For example,
struct node {
int data;
struct node *next
};
is some structure and you have the address of that structure pointer, then to view the contents of that memory location you have to use
(gdb) p *(struct node *) 0x00000000004004fc
Notable:
The command
x 0x00000000004004fc
Will look at the instruction and related data for this instruction:
0x00000000004004fc <+22>: movl $0x85,-0xc(%rbp)
... as you can see that the left column (address) is equal to the value used for the command (the address to read)
In the instruction 0x85 is clearly the destination address for the mov, and reflected in the printed value; 0x85f445c7 - which stored as MSB (most significant byte) at the address.
This question/answer on SO shows how to use GDB to change a value in memory, but in the example given, it chooses an address to set the value that wasn't previously being used
For example, to change the return value to 22, the author does
set {unsigned char}0x00000000004004b9 = 22
However, why would this address 0x00000000004004b9 be the address to change? If you look at the output of disas/r the address 0x00000000004004b9 isn't being used, so why use this one to set to 22? I'm trying to understand how to know which address needs to be changed to (in this example) change the return value, if the output of disas/r doesn't show it.
code
$ cat t.c
int main()
{
return 42;
}
$ gcc t.c && ./a.out; echo $?
42
$ gdb --write -q ./a.out
(gdb) disas/r main
Dump of assembler code for function main:
0x00000000004004b4 <+0>: 55 push %rbp
0x00000000004004b5 <+1>: 48 89 e5 mov %rsp,%rbp
0x00000000004004b8 <+4>: b8 2a 00 00 00 mov $0x2a,%eax
0x00000000004004bd <+9>: 5d pop %rbp
0x00000000004004be <+10>: c3 retq
End of assembler dump.
(gdb) set {unsigned char}0x00000000004004b9 = 22
(gdb) disas/r main
Dump of assembler code for function main:
0x00000000004004b4 <+0>: 55 push %rbp
0x00000000004004b5 <+1>: 48 89 e5 mov %rsp,%rbp
0x00000000004004b8 <+4>: b8 16 00 00 00 mov $0x16,%eax <<< ---changed
0x00000000004004bd <+9>: 5d pop %rbp
0x00000000004004be <+10>: c3 retq
End of assembler dump.
(gdb) q
$ ./a.out; echo $?
22 <<<--- Just as desired
I'm trying to understand how to know which address needs to be changed to (in this example) change the return value, if the output of disas/r doesn't show it.
To understand this, you need to understand instruction encoding. The instruction here is "move immediate 32-bit constant to register". The constant is part of the instruction (that's what "immediate" means). It may be helpful to compile this instead:
int foo() { return 0x41424344; }
int bar() { return 0x45464748; }
int main() { return foo() + bar(); }
When you do compile it, you should see something similar to:
(gdb) disas/r foo
Dump of assembler code for function foo:
0x00000000004004ed <+0>: 55 push %rbp
0x00000000004004ee <+1>: 48 89 e5 mov %rsp,%rbp
0x00000000004004f1 <+4>: b8 44 43 42 41 mov $0x41424344,%eax
0x00000000004004f6 <+9>: 5d pop %rbp
0x00000000004004f7 <+10>: c3 retq
End of assembler dump.
(gdb) disas/r bar
Dump of assembler code for function bar:
0x00000000004004f8 <+0>: 55 push %rbp
0x00000000004004f9 <+1>: 48 89 e5 mov %rsp,%rbp
0x00000000004004fc <+4>: b8 48 47 46 45 mov $0x45464748,%eax
0x0000000000400501 <+9>: 5d pop %rbp
0x0000000000400502 <+10>: c3 retq
End of assembler dump.
Now you can clearly see where in the instruction stream each byte of the immediate constant resides (and also that x86 uses little-endian encoding for them).
The standard reference on instruction encoding for x86 is Intel instruction set reference. You can find 0xB8 instruction on page 3-528.
I'm currently reading a very informative and good-to-follow book about C-Security and currently there is a chapter about Assembly.
Considering the following C-Code:
1 void funktion (int a, int b, int c)
2 {
3 int buff1[5];
4 char buff2[10];
5 buff1[0] = '6';
6 buff2[0] = 'A';
7 buff2[1] = 'B';
8 }
9
10 int main (void)
11 {
12 int i = 1;
13 funktion (1, 2, 3);
14 return 0;
15 }
When I debug the executable in gdb and disassemble main, I get the following output:
# -----------FUNC_PROLOG----------
24 0x00000000004004d4 <+0>: push %rbp
28 0x00000000004004d5 <+1>: mov %rsp,%rbp
33 0x00000000004004d8 <+4>: sub $0x10,%rsp
34
#----------FUNC_OPERATIONS----------
39 0x00000000004004dc <+8>: movl $0x1,-0x4(%rbp)
43 0x00000000004004e3 <+15>: mov $0x3,%edx
44 0x00000000004004e8 <+20>: mov $0x2,%esi
45 0x00000000004004ed <+25>: mov $0x1,%edi
The book I'm reading is from 2003, so I know that my compilation doesn't look exactly the same as like in the book, so I interpret this instruction (line 33) as the enlargement of the current stack-frame. In the book, there's a decrementation (= enlargement of the stack-frame) by 4 bytes, and I have a dec by 16 bytes: I think this is an optimation they made, so that the size of local var's (int i = 4 bytes) + the size of the parameters (int a, int b, int c = 12 bytes) = 16 bytes are allocated directly at the stack, and not pushing the stack each time, which is less efficient. However this could be a misinterpretation of mine which is relevant for the real question I have:
From line 43-45 the parameters are stored in reversed order, but they are stored in registers, not at the stack, how you can see there.
So why is there memory allocated for the parameters at the stack, although they are not stored at the stack?
Btw-Questions:
At line 28 you can see a mov instruction. Why? I thought AT&T needs a size-suffix.
Is it possible to adjust gdb so, that I see direct values in decimal, not in hexadecimal base?
Is that <cstdio> header in C++ contains just the same functions as <stdio.h> but put in std namespace?
I experienced strange efficiency problems in my program compiled with mingw-w64, which is more than ten times slower then on linux. After some test I found that the problem is in sprintf.
Then I did the following test:
#include <stdio.h>
// #include <cstdio>
// using std::sprintf;
int main () {
int i;
for (i = 0; i < 500000; i++){
char x[100];
sprintf(x, "x%dx%dx", i, i<<2);
}
}
When compiled with <stdio.h> it is 15 times faster then using <cstdio>. Here is the timing:
$ time ./stdio
real 0m0.557s
user 0m0.046s
sys 0m0.046s
$ time ./cstdio
real 0m7.465s
user 0m0.031s
sys 0m0.077s
$ g++ --version
g++.exe (rubenvb-4.8-stdthread) 4.8.1 20130324 (prerelease)
Copyright (C) 2013 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.
UPDATE 1:
I further timed with different mingw-w64 build (rubenvb, drangon, and mingw-build), and find that all 32bit version using <cstdio> timed 4.x seconds and 64bit versions 7.x~8.x seconds. And all versions using <stdio.h> timed around 0.4~0.6 second.
UPDATE 2:
I disassembled the main function in gdb and find only one line differs: the <stdio.h> version calls callq 0x4077c0 <sprintf> but the <cstdio> version calls callq 0x407990 <_Z7sprintfPcPKcz>.
sprintf contains:
0x00000000004077c0 <+0>: jmpq *0x7c6e(%rip) # 0x40f434 <__imp_sprintf>
0x00000000004077c6 <+6>: nop
0x00000000004077c7 <+7>: nop
Following __imp_sprintf I reached the sprinf inside msvcrt.dll.
_Z7sprintfPcPKcz contains some mingw codes:
0x0000000000407990 <+0>: push %rbp
0x0000000000407991 <+1>: push %rbx
0x0000000000407992 <+2>: sub $0x38,%rsp
0x0000000000407996 <+6>: lea 0x80(%rsp),%rbp
0x000000000040799e <+14>: mov %rcx,-0x30(%rbp)
0x00000000004079a2 <+18>: mov %r8,-0x20(%rbp)
0x00000000004079a6 <+22>: mov %r9,-0x18(%rbp)
0x00000000004079aa <+26>: mov %rdx,-0x28(%rbp)
0x00000000004079ae <+30>: lea -0x20(%rbp),%rax
0x00000000004079b2 <+34>: mov %rax,-0x58(%rbp)
0x00000000004079b6 <+38>: mov -0x58(%rbp),%rdx
0x00000000004079ba <+42>: mov -0x28(%rbp),%rax
0x00000000004079be <+46>: mov %rdx,%r8
0x00000000004079c1 <+49>: mov %rax,%rdx
0x00000000004079c4 <+52>: mov -0x30(%rbp),%rcx
0x00000000004079c8 <+56>: callq 0x402c40 <__mingw_vsprintf>
0x00000000004079cd <+61>: mov %eax,%ebx
0x00000000004079cf <+63>: mov %ebx,%eax
0x00000000004079d1 <+65>: add $0x38,%rsp
0x00000000004079d5 <+69>: pop %rbx
0x00000000004079d6 <+70>: pop %rbp
Why does cstdio use a different (and much slower) function?
libstdc++ does define __USE_MINGW_ANSI_STDIO during build (config/os/mingw32-w64/os_defines.h), which will turn on the mingw sprintf wrapper. As #Michael Burr pointed out, these wrappers exist for C99/GNU99 compatibility.
Your test does not define __USE_MINGW_ANSI_STDIO, hence you'll not get the wrapper with stdio.h. But since it was defined when building libstdc++, you'll get it with cstdio.
If you however define it yourself before including stdio.h, you will get the wrapper again.
So you do get in fact different implementations, and cstdio std::sprintf is not necessarily the same as stdio.h sprintf, at least not when it comes to mingw.
Here is a test. First the source:
#ifdef USE_STDIO
#include <stdio.h>
#else
#include <cstdio>
using std::sprintf;
#endif
int main () {
int i;
for (i = 0; i < 500000; i++){
char x[100];
sprintf(x, "x%dx%dx", i, i<<2);
}
}
Results:
$ g++ -o test_cstdio.exe test.cc
$ g++ -o test_stdio.exe -DUSE_STDIO test.cc
$ g++ -o test_stdio_wrap.exe -DUSE_STDIO -D__USE_MINGW_ANSI_STDIO test.cc
$ for x in test_*.exe; do ( echo $x; objdump -d $x | grep sprintf; echo ); done
test_cstdio.exe
40154a: e8 41 64 00 00 callq 407990 <_Z7sprintfPcPKcz>
0000000000402c40 <__mingw_vsprintf>:
0000000000407990 <_Z7sprintfPcPKcz>:
4079c8: e8 73 b2 ff ff callq 402c40 <__mingw_vsprintf>
test_stdio.exe
40154a: e8 71 62 00 00 callq 4077c0 <sprintf>
00000000004077c0 <sprintf>:
4077c0: ff 25 6e 6c 00 00 jmpq *0x6c6e(%rip) # 40e434 <__imp_sprintf>
test_stdio_wrap.exe
40154a: e8 41 64 00 00 callq 407990 <_Z7sprintfPcPKcz>
0000000000402c40 <__mingw_vsprintf>:
0000000000407990 <_Z7sprintfPcPKcz>:
4079c8: e8 73 b2 ff ff callq 402c40 <__mingw_vsprintf>