I have been asked in an interview how can you debug segmentation fault in C program using GDB.
I told them we can compile our program with -g option so as it add debugging information to binary file and can read core dump file but then interviewer told me if he we have 3 to 4 files compiled together but one of them causing segmentation fault then how do we debug in GDB?
$ gcc -ggdb s1.c s2.c s3.c -o myprog
$ gdb myprog
(gdb) run --arg1 --arg2
GDB will run the program as normal, when the segmentation fault occurs GDB will drop back to its prompt and it will be almost the same as running GDB with a core file. The major difference is there are some things you cannot do/print with a core file that you can when the program has crashed inside of GDB. (You can use print to call some functions inside the program, for example.)
You can also attach to an already running program using gdb --pid <the programs pid>.
Either with a core file or with one of the methods above, when you have the GDB prompt after the crash, type backtrace (or bt for short) and GDB will show you the stack at the time of the crash, including the file names and line numbers of each call and the currently executing line.
If you are working under Linux the easier way to find segmentation fault is by using the tool named VALGRIND: http://valgrind.org/ .
You just need to compile your code with -g flag and then run ./valgrind .
Then you will know exactly in which function and in which line of code there is an error-uninitialized memory/memory read out of allocated space or sth.
You just run the program under gdb, and the debugger with catch the SIGSEGV and show you the line and instruction that faulted. Then you just examine the variable and/or register values to see what's wrong. Usually it's a rogue pointer value, and trying to access it with GDB will give and error, so it's easy.
And yes, recompiling everything with -g would be helpful. The interviewer probably wanted you to describe how you'd figure out which file had the fault (gdb just tells you when it catches the signal) and just recompile that one with debug info. If there's 20,000 source files that might be useful, but with 3 or 4 files, what's the point? Even with larger projects, you usually end up chasing the bad pointer through 10 functions and 5 files anyway, so again, what's the point? Debug info doesn't cost anything at run time, although it costs disk space in an installation.
compile the code in normal way by giving gcc filename
you will get a .out file, start running that and get the process id by giving ps -aef | grep filename.out
in a another window type gdb and enter,inside gdb prompt give attach processid (processid you will get from above command),give c to continue.once the execution finishes give "bt" inside gdb.you will get the place where the segmentation is occurring.
Sounds like they are looking to set it up so that you can step through the code as it is running, you can do this with the command line version or I think you can get a GUI for GDB.
one can use the following steps to debug segmentation fault using gdb
$ gdb <exec name >
$ r //run the pgm
$ where
$ f <1> <0> //to view the function n variables
$ list
$ p <variable>
Related
I am working on an automated testing tool which has found bugs that are usually manifested as segmentation faults. I am trying to find out how many of these detected bugs are unique. Uniqueness is a special term used in my study: If two segmentation faults are triggered by different statements, the two are considered different. My current approach to tell if two segmentation faults are triggered by different statements or not is to use GDB. For example:
(gdb) r
Program received signal SIGSEGV, Segmentation fault.
0x00007f050c9efac2 in gsl_stats_quantile_from_sorted_data (sorted_data=sorted_data#entry=0x7fffe1477c40, stride=stride#entry=1,
n=n#entry=5, f=675) at quantiles_source.c:37
37 result = sorted_data[lhs * stride]
As you can see, GDB stops at where the segmentation fault arises (line 37 of the C program quantiles_source.c as shown above). I am wondering how to get that piece of information by a command line or script, non-interactively?
You can run gdb non-interactive on the binary by executing the commands specified in file with -x file, or you can specify a command with -ex command (used multiple times if needed). In either case when combined with --batch it subsequently exit. Another option configure your shell to allow a core file to dumped with ulimit -c ulimited then run gdb on the binary and resulting core file using the arguments mentioned above.
I am having trouble getting the debugger to work properly when setting up clang on my Windows 10 machine. Compilation seems to work OK, at least for the simple "hello, world" program I tried. However, when I try to run the lldb or gdb debuggers on this test program (or any other program I tried), it does not recognize function names.
Here's my C program code:
#include <stdio.h>
int main(void) {
puts("Hello, world!");
return 0;
}
Nothing too spectacular here, I know. I'm compiling with the following command:
> clang -g -O0 hello.c -o hello.exe
I then try to run the debugger:
> lldb hello
(lldb) target create "hello"
Current executable set to 'hello' (x86_64).
(lldb) b main
Breakpoint 1: no locations (pending).
WARNING: Unable to resolve breakpoint to any actual locations.
(lldb) r
Process 12156 launched: 'C:\Users\********\Projects\clang-test\hello.exe' (x86_64)
Process 12156 exited with status = 0 (0x00000000)
(lldb)
Apparently the symbol "main" was not recognized, and the program did not halt at the start of the "main" function but ran to completion (in a different console window, hence no program output here).
How do I get debugging symbols to work? In a different stackoverflow answer I found that adding compiler options "-g -O0" should do the trick, but as you can see that does not solve the problem for me. I also found a different stackoverflow answer about how to set up debugging if the code is not in the same directory as the executable, but that is not relevant to my case: the current working directory is the same as the directory with the code and executable in them.
Some version information:
> clang --version
clang version 9.0.0 (tags/RELEASE_900/final)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
> lldb --version
lldb version 9.0.0
The "-g -O0" options you provided should indeed let the debugger know all the symbols it needs from the executable.
Therefore, I suspect the problem is elsewhere, perhaps with your terminal, or your version/implementation of LLDB.
Are you using the windows cmd.exe commandline ? or something else, like Powershell ?
I've never managed to get debuggers working properly in those environments, but it was much easier with Cygwin, which is a bash shell for windows (it creates a "simulated" linux environment within its install folder, so you have all the /usr,/bin,/etc folders a bash shell needs)
This way you can actually use gdb the way you would on a UNIX system.
If the above method sounds like more of a hassle than a time-gain, then yeah I would recommend another debugger altogether, like the Visual Studio debugger.
In fact, maybe a memory-analysis tool like Dr.Memory can give you what you need
I've never used a debugger and the time has come to give them a try. MinGW appears to come with GDB which I've been trying to use. Supposdly running gdb from the command line and typing run myprog.exe starts the debugger but when I do this I get
Starting program: C:\MinGW\bin\myprog.exe MyProg.exe
[New Thread 1828.0xd8c]
Error opening file.
[Inferior 1 (process 1828) exited with code 02]
How to proceed or what's an easier way?
In particular I'm trying to flush out undefined behavior.
Since your program terminates, you'll need to set a breakpoint to see anything. Try break main before the run line. Then you can do commands line next (next line), step (step into/outof function calls), print expression (where expression can be a variable name or a function-call or a calculation), display expression (same as print, but prints just before each prompt). At any given point you can type backtrace to get a call stack. You can even type up and down to move up the callstack, so you can print higher local variables.
Well, the easiest way would be to use an IDE, actually. You might want to give code::blocks a try - very easy to use, configures everything for you on installation (just make sure to pick a compiler - don't worry, it'll prompt you) and there, you're all set and ready to go. As it's multi-platform, it doesn't really lock you into windows either, and gives you very powerful (and, I guess more importantly, convenient) possibilities of graphical debugging.
pass the binary with gdb
gdb <binary>
then set breakpoint to main
gdb) break main
Then run your program in gdb
gdb) run
then break point hits use 'n' or 'next' to step to different lines
gdb) n
Use 's' for stepping into function and 'p' printing var value
Example :
gdb) s <fun_name>
gdb) p x
I would suggest , as a beginner start off with Visual Studio. It has a very good and easy to use debugger. Just create a break point in the line from which you want to start debugging (click on the left bar beside the line or right click and create a break point). Once your break points are set you can just simply run the program in debug mode and the execution of the program will halt in the point where the break was created.
At this point you should be able to view all valuable information about the execution of the program. You can use F10 to continue the execution step or F11 to step inside the execution tree.
The debugger as many other advanced features like break on condition , hit count etc but you can start off with it's basic functionality.
If I compiled a program like this:
gcc -o my-prog -g myprog.c
I could then debug the executable my-prog it like this:
gdb my-prog
The -g option tells gcc to generate full debugging info. Other compilers will have their own versions of this option (e.g. the MSVC cl command has the /Zi option).
Since you're having issues running the gdb on your program, it might be worth checking if it was compiled with debugging info in the first place. The debugging info is usually generated in the same location as where you compiled your program.
I am trying to write a plugin for a daemon, and right now I am in the last stages. So I've thought of mtrace to look for memory leaks, as I don't see any possible way of starting a valgrind instance (I am not running the actual daemon, I run a starter process which checks some config files, and after that starts the daemon).
So, as I am looking through the logs from mtrace, I see a lot of very inaccurate info. For example it says that index += UNIT is a memory alloc that is never freed, and a lot of similar stuff.
I am running the following command for mtrace:
mtrace ./a.out memory > raw.log; cat raw.log | tr -s " " " " | cut -d" " -f4 > err.log; cat err.log | addr2line -e a.out > fin.log
Any ideas on why I get the totally not useful output?
P.S.: a.out is compiled with all the debug flags on
I believe the problem is with addr2line.
You should try to read the original raw.log and see if it makes sense.
Take one suspicious allocation, find it in the raw log, run objdump -lrd a.out and find the assembly line. It should be a call to malloc. If it is the fault is with addr2line, if it isn't, the fault is with mtrace.
Some possible pitfalls:
1. Compiling a.out without -g.
2. Running one a.out and giving another a.out to addr2line.
3. Searching for the line number you got in an incorrect version of the source.
P.S. You don't have something like #define UNIT (malloc(1000),7), do you?
I'm having some problems with a program causing a segmentation fault when run on a Mac. I'm putting together an entry for the IOCCC, which means the following things are true about my program:
It's a very small C program in a single file called prog.c
I won't post it here, because it won't help (and would probably render the contest entry invalid)
It compiles cleanly under gcc using "cc -o prog prog.c -Wall"
Despite (or, more accurately, because of) the fact it contains a bunch of really bizarre uses of C, it has been constructed extremely carefully. I don't know of any part of it which is careless with memory (which is not to say that there can't possibly be bugs, just that if there are they're not likely to be obvious ones)
I'm primarily a Windows user, but several years ago I successfully compiled and ran it on several windows machines, a couple of Macs and a Linux box, with no problems. The code hasn't changed since then, but I no longer have access to those machines.
I don't have a Linux machine to re-test on, but as one final test, I tried compiling and running it on a MacBook Pro - Mac OSX 10.6.7, Xcode 4.2 (i.e. GCC 4.2.1). Again, it compiles cleanly from the command line. It seems that on a Mac typing "prog" won't make the compiled program run, but "open prog" seems to. Nothing happens for about 10 seconds (my program takes about a minute to run when it's successful), but then it just says "Segmentation fault", and ends.
Here is what I've tried, to track down the problem, using answers mostly gleaned from this useful StackOverflow thread:
On Windows, peppered the code with _ASSERTE(_CrtCheckMemory()); - The code ran dog-slow, but ran successfully. None of the asserts fired (they do when I deliberately add horrible code to ensure that _CrtCheckMemory and _ASSERTE are working as expected, but not otherwise)
On the Mac, I tried Mudflap. I tried to build the code using variations of "g++ -fmudflap -fstack-protector-all -lmudflap -Wall -o prog prog.c", which just produces the error "cc1plus: error: mf-runtime.h: No such file or directory". Googling the matter didn't bring up anything conclusive, but there does seem to be a feeling that Mudflap just doesn't work on Macs.
Also on the Mac, I tried Valgrind. I installed and built it, and built my code using "cc -o prog -g -O0 prog.c". Running Valgrind with the command "valgrind --leak-check=yes prog" produces the error "valgrind: prog: command not found". Remembering you have you "open" an exectable on a Mac I tried "valgrind --leak-check=yes open prog", which appears to run the program, and also runs Valgrind, which finds no problems. However, Valgrind is failing to find problems for me even when I run it with programs which are designed specifically to make it trigger error messages. I this also broken on Macs?
I tried running the program in Xcode, with all the Diagnostics checkboxes ticked in the Product->Edit Scheme... menu, and with a symbolic breakpoint set in malloc_error_break. The breakpoint doesn't get hit, the code stops with a callstack containing one thing ("dlopen"), and the only thing of note that shows up in the output window is the following:
Warning: Unable to restore previously selected frame.
No memory available to program now: unsafe to call malloc
I'm out of ideas. I'm trying to get Cygwin set up (it's taking hours though) to see if any of the tools will work that way, but if that fails then I'm at a loss. Surely there must be SOME tools which are capable of tracking down the causes of Segmentation faults on a Mac?
For the more modern lldb flavor
$ lldb --file /path/to/program
...
(lldb) r
Process 89510 launched
...
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x726f00)
* frame #0: 0x00007fff73856e52 libsystem_platform.dylib`_platform_strlen + 18
...
Have you compiled with -g and run it inside gdb? Once the app crashes, you can get a backtrace with bt that should show you where the crash occurs
In many cases, macOS stores the recent program crash logs under ~/Library/Logs/DiagnosticReports/ folder.
Usually I will try the following steps when doing troubleshooting on macOS:
Clean the existing crash logs under the ~/Library/Logs/DiagnosticReports/
Run the program again to reproduce the issue
Wait for a few seconds, the crash log will appear under the folder. The crash log is named like {your_program}_{crashing_date}_{id}_{your_host}.crash
Open the crash log with your text editor, search for the keyword Crashed to locate the thread causing the crash. It will show you the stack trace during crash, and in many cases, the exact line of source code causing the crash will be recorded as well.
Some links:
[1] https://mac-optimization.bestreviews.net/analyze-mac-crash-reports/