I am trying to debug a C program and gdb is telling me there is a segfault on line 329 of a certain function. So I set a break point for that function and I am trying to step through it. However, whenever I hit line 68 I get this complaint from gdb:
(gdb) step
68 next_bb = (basic_block *)malloc(sizeof(basic_block));
(gdb) step
*__GI___libc_malloc (bytes=40) at malloc.c:3621
3621 malloc.c: No such file or directory.
in malloc.c
I don't know what this means. The program runs perfectly on all but one set of inputs so this call to malloc clearly succeeds during other executions of the program. And, of course, I have:
#include <stdlib.h>.
Here is the source code:
// Block currently being built.
basic_block *next_bb = NULL;
// Traverse the list of instructions in the procedure.
while (curr_instr != NULL)
{
simple_op opcode = curr_instr->opcode;
// If we are not currently building a basic_block then we must start a new one.
// A new block can be started with any kind of instruction.
if (!in_block)
{
// Create a new basic_block.
next_bb = (basic_block *)malloc(sizeof(basic_block));
You can safely ignore this. gdb is complaining that it doesn't have the source for malloc - and it's almost certain you don't want to step through the source.
Two easy solutions:
Use next instead of step - it won't descend into functions
If you've accidentally steped into a function already, use finish to run to the return statement of the function.
And an alternative approach:
You could also break a bit before the segfault, rather than stepping through the whole code.
You can do this by putting a breakpoint on a particular line with break <source file>:<line num> (for example break foo.c:320 to break on line 320 of foo.c).
Or you can break on a particular function with break <function name> (for example break foo will break at the top of the foo() function).
Related
As mentioned in the title, gdb behaves weirdly when I try to set a breakpoint at linux socket functions such as send etc. I've read through similar threads where it's been suggested to use the debug argument, but I can't set it as I'm just messing around with different Linux programs/video games and I've noticed the same behaviour - for the most part, send can't be backtraced. Only the familiar "< memory address > in ??" messages are shown, and the addresses themselves don't point to anything (can't be retrieved). At the same time, the message buffer in send (or sendto etc) is stuck at one value and not updating (while all the other values such as len are, in real time). I suppose these are simply limitations of gdb, but I'd appreciate it if someone more knowledgeable could shed some light on the issue.
EDIT:
First I'll list my steps:
As an example, I'm trying to backtrace the sendto in openarena (free linux quake-based game). Openarena in particular is not ELF readable, but I get the same results with other ELF-readable files. Because it isn't ELF-readable, I can only attach to a running process. So I type gdb /usr/games/openarena -p < process name > , though I'm pretty sure the binary path is redundant in this case
(it still says "0x7ffc8a81ebe0s": not in executable format: file format not recognized, but I'm able to list functions and everything anyway) As a side note, attaching produces this bug:
((( https://forum.manjaro.org/t/critical-bug-gdb-broken-with-last-stable-update/53155
"Error while reading shared library symbols for /lib/x86_64-linux-gnu/libpthread.so.0:"
However, in my case, I'm still able to attach, but the program eventually crashes after complaining about not being able to find a thread. This also often happens when joining a server from a lobby, but this is a side note, as I've tested programs by running them directly from gdb as well which doesn't produce the error, but still led to this weird socket behaviour. )))
So after attaching to the process, I type source script, the script containing:
break sendto
commands 1
backtrace -raw-frame-arguments on
continue
end
I then resume the program and it's firing backtraces in realtime. This is sample output after joining a server:
Thread 1 "ioquake3" hit Breakpoint 1, __libc_sendto (fd=43, buf=0x7ffefc5028f0, len=32, flags=0, addr=..., addrlen=16) at ../sysdeps/unix/sysv/linux/sendto.c:25
25 in ../sysdeps/unix/sysv/linux/sendto.c
#0 __libc_sendto (fd=43, buf=0x7ffefc5028f0, len=32, flags=0, addr=..., addrlen=16) at ../sysdeps/unix/sysv/linux/sendto.c:25
#1 0x00005642f88bc5fc in ?? ()
#2 0x00005642f88baf94 in ?? ()
#3 0x00005642f888b1ee in ?? ()
#4 0x00005642f88779cf in ?? ()
#5 0x00005642f8886572 in ?? ()
#6 0x00005642f88a58bf in ?? ()
#7 0x00005642f886e3f5 in main ()
Thread 1 "ioquake3" hit Breakpoint 1, __libc_sendto (fd=43, buf=0x7ffefc5028f0, len=34, flags=0, addr=..., addrlen=16) at ../sysdeps/unix/sysv/linux/sendto.c:25
25 in ../sysdeps/unix/sysv/linux/sendto.c
#0 __libc_sendto (fd=43, buf=0x7ffefc5028f0, len=34, flags=0, addr=..., addrlen=16) at ../sysdeps/unix/sysv/linux/sendto.c:25
#1 0x00005642f88bc5fc in ?? ()
#2 0x00005642f88baf94 in ?? ()
#3 0x00005642f888b1ee in ?? ()
#4 0x00005642f88779cf in ?? ()
#5 0x00005642f8886572 in ?? ()
#6 0x00005642f88a58bf in ?? ()
#7 0x00005642f886e3f5 in main ()
As you can see, there is nothing between main and the send, the socket buffer is stuck at the same message, while len is updating correctly. I can perform any kind of actions, jump, shoot, and the output still stays the same. As I mentioned, I get pretty much the same output with other applications. There's some main function/loop, then nothing and then just the send function.
As for my system specs, I'm on Kubuntu 21.04,
GDB version is: GNU gdb (Ubuntu 10.1-2ubuntu2) 10.1.90.20210411-git
Glibc: Ubuntu GLIBC 2.33-0ubuntu5
I've migrated recently from an earlier LTS release, the upgrade might not have been entirely clean, I suppose...
As you can see, there is nothing between main and the send, the socket buffer is stuck at the same message, while len is updating correctly.
A few points:
There are no function names (which isn't the same as "nothing"). That is expected IF there is no symbol table. GDB uses symbol table(s) from loaded binaries to translate addresses into function names.
If the binary is fully stripped, or if the code generated into memory directly, or if the binary is decompressed or decrypted into memory, then you would need to teach GDB where it can get the symbol table from (if the symbol table exists at all, which isn't a given).
The socket buffer being "stuck" is not necessarily unexpected either: the program is very likely to be doing repeated sendto calls using the same stack buffer. Like this:
while (!error) {
char buf[4096];
int n = copy_to(buf); // fill buf[] with data
if (sendto(fd, buf, n, ...) != n) // handle error
}
Update:
I still don't quite understand why I can't see buffer values change.
You are not looking at the buffer contents, you are looking at the buffer address (i.e. &buf[0] given the code above).
If you want to look at the buffer contents, you need to print / examine it. E.g. to examine the first 8 bytes being sent, add this to your breakpoint command: x/8cx buf. But also note that it is common to have a fixed prefix on all the packets being sent, and it's not guaranteed that the 8 leading bytes will change on every packet either.
We're learning to use GDB in my Computer Architecture class. To do this we do most of our work by using SSH to connect to a raspberry pi. When running GDB on some code he gave us to debug though it ends with an error message on how it can't find raise.c
I've tried:
installing libc6, libc6-dbg (says they're already up-to-date)
apt-get source glibc (gives me: "You must put some 'source' URIs in your sources.list")
https://stackoverflow.com/a/48287761/12015458 (apt source returns same thing as the apt-get source above, the "find $PWD" command the user gave returns nothing)
I've tried looking for it manually where told it may be? (/lib/libc doesn't exist for me)
This is the code he gave us to try debugging on GDB:
#include <stdio.h>
main()
{
int x,y;
y=54389;
for (x=10; x>=0; x--)
y=y/x;
printf("%d\n",y);
}
However, whenever I run the code in GDB I get the following error:
Program received signal SIGFPE, Arithmetic exception.
__GI_raise (sig=8) at ../sysdeps/unix/sysv/linux/raise.c:50
50 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
I asked him about it and he didn't really have any ideas on how to fix it.
It does not really matter that the source for raise() is not found. It would only show you the line where the exception is finally raised, but not the place where the error is triggered.
Run the erroneous program again in GDB. And when the exception is raised, investigate the call stack and the stackframes with GBDs commands. This is the point in your task, so I won't give you more than this hint.
If you're clever you can see the error in the given source just by looking at it. ;-)
When GDB does not know any symbol, you need to compile with the option -g to get debugger support.
EDIT
Now on a Windows system this is my log (please excuse the colouring, I didn't found a language selector for pure text):
D:\tmp\StackOverflow\so_027 > type crash1.c
#include <stdio.h>
main()
{
int x,y;
y=54389;
for (x=10; x>=0; x--)
y=y/x;
printf("%d\n",y);
}
D:\tmp\StackOverflow\so_027 > gcc crash1.c -g -o crash1.out
crash1.c:2:1: warning: return type defaults to 'int' [-Wimplicit-int]
main()
^~~~
D:\tmp\StackOverflow\so_027 > dir
[...cut...]
04.09.2019 08:33 144 crash1.c
04.09.2019 08:40 54.716 crash1.out
D:\tmp\StackOverflow\so_027 > gdb crash1.out
GNU gdb (GDB) 8.1
[...cut...]
This GDB was configured as "x86_64-w64-mingw32".
[...cut...]
Reading symbols from crash1.out...done.
(gdb) run
Starting program: D:\tmp\StackOverflow\so_027\crash1.out
[New Thread 4520.0x28b8]
[New Thread 4520.0x33f0]
Thread 1 received signal SIGFPE, Arithmetic exception.
0x0000000000401571 in main () at crash1.c:7
7 y=y/x;
(gdb) backtrace
#0 0x0000000000401571 in main () at crash1.c:7
(gdb) help stack
Examining the stack.
The stack is made up of stack frames. Gdb assigns numbers to stack frames
counting from zero for the innermost (currently executing) frame.
At any time gdb identifies one frame as the "selected" frame.
Variable lookups are done with respect to the selected frame.
When the program being debugged stops, gdb selects the innermost frame.
The commands below can be used to select other frames by number or address.
List of commands:
backtrace -- Print backtrace of all stack frames
bt -- Print backtrace of all stack frames
down -- Select and print stack frame called by this one
frame -- Select and print a stack frame
return -- Make selected stack frame return to its caller
select-frame -- Select a stack frame without printing anything
up -- Select and print stack frame that called this one
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Command name abbreviations are allowed if unambiguous.
(gdb) next
Thread 1 received signal SIGFPE, Arithmetic exception.
0x0000000000401571 in main () at crash1.c:7
7 y=y/x;
(gdb) next
[Inferior 1 (process 4520) exited with code 030000000224]
(gdb) next
The program is not being run.
(gdb) quit
D:\tmp\StackOverflow\so_027 >
Well, it marks directly the erroneous source line. That is different to your environment as you use a Raspi. However, it shows you some GDB commands to try.
Concerning your video:
It is clear that inside raise() you can't access x. That's why GDB moans about it.
If an exception is raised usually the program is about to quit. So there is no value in stepping forward.
Instead, as shown in my log, use GDB commands to investigate the stack frames. I think this is the issue you are about to learn.
BTW, do you know that you should be able to copy the screen content? This will make reading so much easier for us.
From a practical standpoint the other answer is correct, but if you do want the libc sources:
apt-get source is the right way to get the sources of libc, but yes, you do need to have source repositories configured in /etc/apt/sources.list.
If you're using Ubuntu, see the deb-src lines in https://help.ubuntu.com/community/Repositories/CommandLine
For debian, see https://wiki.debian.org/SourcesList#Example_sources.list
Then apt-get source should work. Remember to tell GDB where those sources are using the "directory" command.
I'm trying to find a segmentation fault in my program that doesn't happen all the time. I'm trying to run my program in a loop in gdb until the segmentation fault happens.
My problem is that the gdb continues the while loop after receiving the seg fault and doesn't prompt me with the gdb shell.
when I run my gdb I use:
set $i=0
while($i<100)
set $i = $i+1
r
end
Anybody know how to make the gdb stop at first segfault and not run 100 times??
Thanks!
The gdb documentation is huge and it's difficult to find what you want but I could make that happen, and just by tweaking your script slightly.
Upon completion, gdb sets $_exitcode to the exit code value.
If segv occurs, the value isn't changed. So my idea was to set it to some stupid value (I chose 244) and run. But if return code is still 244 after the run command, then exit the loop (maybe there's another way to do it)
Warning: hack ahead (but that works)
set $i=0
while($i<100)
set $i = $i+1
set $_exitcode = 244
r
if $_exitcode==244
set $i = 200
end
end
I tested that with an interactive program. Type n for normal execution, and y to trigger segfault (well it would not trigger it, but there's a good chance for that to happen)
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("want segfault?\n");
char c = getchar();
if (c=='y')
{
printf("%s", 'a'); // this is broken on purpose, to trigger segfault
}
return 0;
}
testing in a gdb session:
(gdb) source gdbloop.txt
[New Thread 6216.0x1d2c]
want segfault?
n
[Inferior 1 (process 6216) exited normally]
[New Thread 7008.0x1264]
want segfault?
n
[Inferior 1 (process 7008) exited normally]
[New Thread 8000.0x2754]
want segfault?
y
Breakpoint 1, 0x76b2d193 in wtoi () from C:\windows\syswow64\msvcrt.dll
(gdb)
so I get the prompt back when a segfault is triggered.
You can script GDB interaction using expect.
But the solution from this answer should really be all you need here.
break on exit didn't work for me
It's possible that your program calls _exit instead of exit, so you may need to set a breakpoint there.
It's also possible that your program executes direct SYS_exit system call without going through either exit or _exit.
On Linux, you can catch this with:
catch syscall exit
catch syscall exit_group
At least one the four variants should fire (just run a program by hand). Once you know which variant actually fires, attach commands to the corresponding breakpoint, and use the solution above.
Is there a way to step into standard functions like printf() or atof(), and then execute finish to get back to the main program to get the return value?
With GDB I can do it like this:
(gdb) step
14 float di = atof(argv[1]);
(gdb) step
atof (nptr=0x7fffffffe0c6 "5.8") at atof.c:27
27 atof.c: No such file or directory.
(gdb) finish
Run till exit from #0 atof (nptr=0x7fffffffe0c6 "5.8") at
atof.c:27
0x00005555555547d1 in main (argc=2, argv=0x7fffffffdd18) at
circumf.c:14
14 float di = atof(argv[1]);
Value returned is $1 = 5.7999999999999998
But when I try this with LLDB it steps "over" all standard function. It works with functions inside the program, those I can step into, but not with standard functions. I guess this is a feature, but is there a way around it? I use step with LLDB also.
Is there maybe some other way to get the return value from standard functions inside LLDB?
Like gdb, lldb will step into any function that you have debug information for. It will skip over any function that does not have debug information. The difference in behavior that you're describing sounds more like lldb doesn't have/hasn't found debug information for your standard library solibs.
I tried to use buffer overflow to rewrite my function's return address,and it worked.but when i try to step through the function(stored in the char array),I get the message:
"Single stepping until exit from function shellcode,
which has no line number information."
I've compiled my C program using gcc using the flag -g,and i just have one file.
so here is my diffrence:i want to execute the function which is not "real code".It's stored in the char array ,looks like this:
char shellcode[]="\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0"
"\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d"
"\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73"
"\x68";
My system is Kali linux, is this concern?
Here is debug session:
this problem upset me very much,if someone can help,it would be very awesome!