I have a code which has hit a seg fault with strncmp() and I have this info below:
#7 0x00007f3662e5d4e7 in __strncmp_sse42 () from /lib64/libc.so.6
(gdb) info locals
No symbol table info available.
(gdb) info args
No symbol table info available.
(gdb) info frame
Stack level 7, frame at 0x7f35f4413b70:
rip = 0x7f3662e5d4e7 in __strncmp_sse42; saved rip = 0x7f35f64f5d6d
called by frame at 0x7f35f4413cc0, caller of frame at 0x7f35f4413b68
Arglist at 0x7f35f4413b60, args:
Locals at 0x7f35f4413b60, Previous frame's sp is 0x7f35f4413b70
Saved registers:
rip at 0x7f35f4413b68
Is there a way to check the args passed into this function? Any explanation will help me relate what is going on.
Appreciate the help in advance.
One way to trace args passed into system calls is to use ltrace. Not always guaranteed to be helpful, but quick and painless to try. Here's example of using ltrace to trace the calls made by particular invocation of grep command:
$ ltrace -s 200 grep XYZ hello.cc 2>&1 | grep XYZ
memcpy(0xe7f030, "XYZ\0", 4) = 0xe7f030
memchr("XYZ", '\n', 3) = nil
memcpy(0xe7f6b0, "XYZ", 3) = 0xe7f6b0
strlen("XYZ") = 3
strncmp("Y", "XYZ", 3) = 1
strncmp("XYZ", "Y", 1) = -1
strlen("XYZ") = 3
strcmp("XYZ", "XYZ") = 0
strlen("XYZ") = 3
memcpy(0xe7f630, "XYZ\0", 4) = 0xe7f630
strlen("XYZ") = 3
memcpy(0xe7f840, "XYZ", 3) = 0xe7f840
You're not specifying which operating system you're using, but try installing debug symbols for libc. E.g. libc6-dbg on Ubuntu/Debian.
Related
(This is possibly related to Pass arguments with space in GDB?, which did not get resolved.)
Witness the following:
zlaski#RUMCAJS /cygdrive/d/music/wurlitzer/Drum And Bass
$ ls Wen\ -\ Commotion.backup.mp3
'Wen - Commotion.backup.mp3'
zlaski#RUMCAJS /cygdrive/d/music/wurlitzer/Drum And Bass
$ gdb -q -ex start --args ls Wen\ -\ Commotion.backup.mp3
Reading symbols from ls...
Reading symbols from /usr/bin/ls.exe.dbg...
Temporary breakpoint 1 at 0x1004181e0: file /usr/src/debug/coreutils-9.0-1/src/ls.c, line 1658.
Starting program: /usr/bin/ls Wen\ -\ Commotion.backup.mp3
[New Thread 34524.0x4edc]
[New Thread 34524.0x2abc]
[New Thread 34524.0x7dd4]
[New Thread 34524.0x7aa0]
Thread 1 "ls" hit Temporary breakpoint 1, main (argc=4, argv=0x7ffffcc20) at /usr/src/debug/coreutils-9.0-1/src/ls.c:1658
We are passing a single argument, Wen\ -\ Commotion.backup.mp3, to the ls program. However, gdb chops it into 3 pieces, which is why we wind up with an argc of 4 instead of 2:
(gdb) print argv[0]
$1 = 0xa00003380 "/usr/bin/ls"
(gdb) print argv[1]
$2 = 0x7ffffcc67 "Wen\\"
(gdb) print argv[2]
$3 = 0x7ffffcc6c "-\\"
(gdb) print argv[3]
$4 = 0x7ffffcc6f "Commotion.backup.mp3"
I have also tried the following incantations of the argument:
'Wen - Commotion.backup.mp3'
"Wen - Commotion.backup.mp3"
Wen\\ -\\ Commotion.backup.mp3
"Wen\\ -\\ Commotion.backup.mp3"
'Wen\\ -\\ Commotion.backup.mp3'
'Wen\ -\ Commotion.backup.mp3'
"Wen\ -\ Commotion.backup.mp3"
In all cases, the argument is chopped into 3 pieces.
I have an eerie feeling that I must be doing something wrong as it seems implausible that gdb would have such a glaring defect for all these years. Anyhoo, I hope that you gentlefolk can enlighten me here.
My configuration is as follows:
MACHTYPE=x86_64-unknown-cygwin
bash-4.4.12-3
coreutils-9.0-1
cygwin-3.4.3-1
gdb-11.2-1
Thanks!
I stumbled upon the auto-display functionality of gdb, which is pretty powerful and convenient. After calling
(gdb) display/i $pc
(gdb) display $rax
the watched values are displayed automatically after every step:
(gdb) si
0x0804805e in print_loop_start ()
2: $rax = 0
1: x/i $pc
=> 0x804805e <print_loop_start+6>: mov 0x4(%ebp,%eax,4),%ecx
But how can I "unwatch" the value in $rax, if it is no longer of interest?
Gdb help for display says:
"Use undisplay to cancel display requests previously made."
So if you do display a, then display b, and display c gdb will give numbers to this requests (which you can see by issuing replay with no arguments). Then you can use this numbers with undisplay.
Example:
(gdb) display a
1: a = 32767
(gdb) display b
2: b = 0
(gdb) display c
3: c = 0
(gdb) undisplay 2
(gdb) step
6 b = 2;
1: a = 1
3: c = 0
Details in gdb documentation.
Note that you can also temporarily hide a disp output using:
disable display dnums…
And re-enable with:
enable display dnums…
What does <> angle bracket indicate? Here
(gdb) info local
agent = 0x8049ea3 <__libc_csu_init+35>
stun_addr = 0xbffff249 "stun.stprotocol.org"
stun_port = 3478
controlling = 1
It shows the location of the instruction and its offset.
So, in this example, agent points to the specific instruction located 35 bytes after the start of the __libc_csu_init function.
I have this script of GDB commands:
$ cat gdb_commands.txt
set pagination off
set logging file output.txt
set logging on
file stuff
b *0x80000014
run
echo ***DIFF THIS***\n
echo eax:
print $eax
echo ebx:
print $ebx
echo ecx:
print $ecx
echo edx:
print $edx
echo ***DIFF THIS END***\n
quit
If I run it in GDB I get this:
$ gdb -q -x gdb_commands.txt
Breakpoint 1 at 0x80000014
Breakpoint 1, 0x80000014 in _start ()
***DIFF THIS***
eax:$1 = 1
ebx:$2 = 2
ecx:$3 = 3
edx:$4 = 4
***DIFF THIS END***
A debugging session is active.
Inferior 1 [process 8947] will be killed.
Quit anyway? (y or n) [answered Y; input not from terminal]
So there is that ugly dollar sign thing. I can sed it out, but I would like to have GDB to do that. Is it possible?
(The reason I'm use GDB like this is because we are writing an emulator and want to test if it behaves correctly.)
ugly dollar sign thing ... I would like to have gdb to do that
You can control GDB's output precisely with printf command:
(gdb) print/x $rax
$1 = 0x7ffff7ffe2a0
(gdb) printf "0x%lx\n", $rax
0x7ffff7ffe2a0
There is a command that does exactly that:
(gdb) help output
Like "print" but don't put in value history and don't print newline.
This is useful in user-defined commands.
output prints the variables without the $1 = and the newline.
I have an OpenGL library bug I'm trying to trace, and the bug prints out something that looks like C code into stdout. This is the program, and the bug occurs as soon as glutMainLoop() is called, but I suspect that it's not that function that is faulty. How would I go tracing what function wrote to stdout?
As per request, the output:
arc_ccw_turn, p = 0
case b
arc_ccw_turn, p = 0
case d
arc_ccw_turn, p = 0
case a
arc_ccw_turn, p = 0
case c
I've reported the bug already, but I'd try and provide a GDB backtrace for the issue too.
If you are using Linux then set a breakpoint on write(), all output to stdout and stderr eventually goes through this function. The following is for x86-64, for other architectures you would need to change register names:
$ gdb /usr/bin/cat
Reading symbols from /usr/bin/cat...(no debugging symbols found)...done.
(gdb) set args /proc/cpuinfo
(gdb) b write
Breakpoint 1 at 0x401740
(gdb) condition 1 ($rdi == 1 || $rdi == 2)
(gdb) display $rdi
(gdb) display $rsi
(gdb) display $rdx
(gdb) r
Starting program: /usr/bin/cat /proc/cpuinfo
3: $rdx = 3368
2: $rsi = 6348800
1: $rdi = 1
(gdb) p (char*)$rsi
$4 = 0x60e000 "processor\t: 0\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 30\nmodel name\t: Intel(R) Core(TM) i7 CPU 870 # 2.93GHz\nstepping\t: 5\nmicrocode\t: 0x5\ncpu MHz\t\t: 1199.000\ncache size\t: 8192 KB\nphy"...
Put breakpoints on std::streambuf::sputc and std::streambuf::sputn. If necessary, do print std::cin::rdbuf() once you're in main, and condition the break point on this being equal to the value use get back from this expression.