Some basic questions about debugging core files C++/linux? - c++

Debugging files of C++ applications/linux have always been a mystery to me and some basic understanding is lacking.
(1) Do we need to necessarily compile applications with -g flag without which core files are unable to give any useful information whatsoever? But I see that even when we don't compile with -g flag, core files are generated -- so they must be serving some purpose apart from occupying space on disk.
Wikipedia says : "In computing, a core dump, memory dump, or storage dump consists of the recorded state of the working memory of a computer program at a specific time, generally when the program has terminated abnormally (crashed)".
This should mean that irrespective of if we compiled with -g flag, we still have state. and if we have stack track, we should still be able to know what function caused the error.

The -g option has nothing to do with the core files, but with putting debug information in the program. That is, the generated executable file will contain all symbols (e.g. function and variable names) as well as line number information (so you can find out which line a crash occurs in).
The actual core dump only contains a memory dump. Yes you can, together with the program, get a stack trace, but unless the program has debug information you can not see function names or line numbers, only their addresses.

so they must be serving some purpose apart from occupying space on disk
You can limit size of core files with ulimit -c $limit command and your core files won't occupy your disk space.
And, as Joachim already said -g option just includes debug symbols and checks to your program.

Related

Why does c++ code create a new exe file when it is run isn vscode and why is it so big?

I am newly learning c++. I ran a c++ code on vscode and it creates an exe file. Why is it?
Why the exe file is so big whereas the main file is small? Is there any way to shorten the size of this file?
Because you ask for one.
g++ Sample.cpp -o Sample
And then you run it
./Sample
This is the ordinary behaviour for creating programs in C++. Doing it this way means that you can send Sample.exe to another computer (of the same operating system and processor architecture), and it will run with no other files needed.
There's maybe tens of bytes of your program, and the rest of the size is the C++ runtime environment.
Your CPU cannot understand what's written inside Sample.cpp, therefore you need to compile it with:
g++ Sample.cpp -o Sample.exe
Now Sample.exe has a lot of information that you, as a human, cannot read or understad, but your computer can! You can ask to execute it with:
./Sample.exe
To reduce Sample.exe size you need to optimize it. There are many flags you can add to the g++ compiler. For example:
g++ Sample.cpp -o Sample.exe -Os -s
Please note that reducing the final .exe size means that the compilation is going to take more time (nothing is free unluckly).
When experimenting with some code ("debug" or "development" mode) it's unusual to reduce the .exe size, as you are just focussing on the result.
Reducing the .exe size is only done when in "production" mode (when the file is going to get published and shared).
Googling g++ reduce exe size leads to many interesting stackoverflow Q&A and many other sites as well! But, remember, this should be done only when publishing the executable online.
A tool that I use for a final size optimization is UPX: the Ultimate Packer for eXecutables.

What is section ".debug_info" in an elf file?

I have an elf file, while analysing the mapfile and elf using elfparser, I saw a section called .Debug_info, which is taking largest memory.
I am compiling for xtensa DSP, using xt-xc++, I haven't used -g option also given -o2 optimization level.
is it possible to remove this for release builds?
section called .debug_info, which is taking largest memory.
Note that this section does not have SHF_ALLOC flag, and therefore does not take any RAM at runtime (it only takes space in the filesystem). Of course if you use ramdisk, then that section still does cost you RAM in the end.
is it possible to remove this for release builds?
Yes: none of the .debug* sections are necessary at runtime, and all of them can be safely stripped.
-g0 and -s option didn't work.
It's likely that you are getting .debug_* sections from libraries that you are linking in, and not from your own code. The -g was present when the libraries were compiled, so building with -g0 doesn't have any effect.
It's surprising that -s didn't work, but maybe your compiler interprets this flag differently.
In any case, you should use strip --strip-debug to get rid of .debug_* sections (note: this does not remove the symbol table).
The best practice is actually to compile all your code with full debug info (-g), save the full debug binary for post-mortem analysis, use strip --strip-debug to make a release binary, and use that binary for actual distribution.
If/when the release binary crashes and leaves a core dump, having (saved) full-debug exactly matching binary greatly improves post-mortem analysis you can do.

Not able to set gdb breakpoint

I work on program with multiple C++ files. I have run the executable through gdb for debugging segmentation fault. Later, gdb backtrace provided the list of functions before segmentation fault. Later, I tried to set a break point in a file on a particular line-number. (The path specified is absolute path)
(gdb) break /aia/r015/home/sathish/zfs_amr/src/zfslbminterfaced2q9.cpp:100
However, gdb gives the following message:
No source file named /aia/r015/home/sathish/zfs_amr/src/zfslbminterfaced2q9.cpp.
However, this particular does exist in the location. What really the message means?
What really the message means?
The message means that GDB does not know about any source file named /aia/r015/home/sathish/zfs_amr/src/zfslbminterfaced2q9.cpp.
There are multiple reasons this could be the case:
The debug info for this file is missing, either because that file is compiled without -g, or because the debug info was (possibly inadvertantly) stripped later on,
There are some symbolic links in the above path, and GDB knows that file by fully-resolved pathname instead,
The file is actually not linked into the executable at all,
The file part of a shared library, and symbols for that shared library haven't been loaded yet,
Etc.
As Pat suggested, setting breakpoint on zfslbminterfaced2q9.cpp:100 is more likely to work.
If that doesn't work, info sources will tell you which files GDB does know about.
Update:
info sources gives blank
This means that the application doesn't have any debug info at all.
Usually this happens for one of two reasons:
You neglected to specify -g on the link line (some platforms require -g both at compile and link time),
You have a "stray" -s somewhere on your link line (which strips the final executable).

call stack for code compiled without -g option (gcc compiler)

How do I analyze the core dump (using gdb)
which is not compiled with -g GCC option ?
Generate a map file. The map file will tell you the address that each function starts at (as an offset from the start of the exe so you will need to know the base address its loaded too). So you then look at the instruction pointer and look up where it falls in the map file. This gives you a good idea of the location in a given function.
Manually unwinding a stack is a bit of a black art, however, as you have no idea what optimisations the compiler has performed. When you know, roughly, where you are in the code you can generally work out what ought to be on the stack and scan through memory to find the return pointer. its quite involved however. You effectively spend a lot of time reading memory data and looking for numbers that look like memory addresses and then checking that to see if its logical. Its perfectly doable and I, and I'm sure many others, have done it lots of times :)
With ELF binaries it is possible to separate the debug symbols into a separate file. Quoting from objcopy man pages:
Link the executable as normal (using the -g flag). Assuming that is is called foo then...
Run objcopy --only-keep-debug foo foo.dbg to create a file containing the debugging info.
Run objcopy --strip-debug foo to create a stripped executable.
Run objcopy --add-gnu-debuglink=foo.dbg foo to add a link to the debugging info into the stripped executable.
that should not be a problem , you can compile the source again with -g option and pass gdb the core and the new compiled debug binary, it should work without any problem.
BTW You can generate a map file with the below command in gcc
gcc -Wl,-Map=system.map file.c
The above line should generate the map file system.map, Once the map file is generated you can map the address as mentioned above but i am not sure how are you going to map the share library, this is very difficult

How to change source path in executable g++

I compile my programs in a compiler machine. Later I run and test the programs in a different environment. If I compile with -fprofile-arcs on then the program tries to write a file in a folder which does not exist in the running environment. Is there a work-around for this problem?
Thanks
Further to RP's answer, I think this would be useful.
if the object file /user/build/foo.o
was built with -fprofile-arcs, the
final executable will try to create
the data file /user/build/foo.gcda
when running on the target system.
This will fail if the corresponding
directory does not exist and it is
unable to create it. This can be
overcome by, for example, setting the
environment as
GCOV_PREFIX=/target/run' and
GCOV_PREFIX_STRIP=1'. Such a setting
will name the data file
/target/run/build/foo.gcda.
Nakiya, According to this
"-fprofile-arcs
Add code so that program flow arcs are instrumented. During execution the program records how many times each branch and call is executed and how many times it is taken or returns. When the compiled program exits it saves this data to a file called auxname.gcda for each source file. The data may be used for profile-directed optimizations (-fbranch-probabilities), or for test coverage analysis (-ftest-coverage). Each object file's auxname is generated from the name of the output file, if explicitly specified and it is not the final executable, otherwise it is the basename of the source file. In both cases any suffix is removed (e.g. foo.gcda for input file dir/foo.c, or dir/foo.gcda for output file specified as -o dir/foo.o)."