Some things were taken from this post, be sure to check it out.
Prepare pretty printers for GDB
The first thing you should always do is to get the pretty printers and use them to print the variables in gdb. To do this you will need to find the install path of thec gcc that was used to build the executable that has generated a coredump, and inside that path there should be some pretty printers. Usually, this path can be found here(on ubuntu): /usr/share/gcc-10/python/
.
In my case it was in /opt/gcc/9.2.0/share/gcc-9.2.0/python/
, because the gcc that I was using was built from sources.
That folder contains a folder called: libstdcxx
which contains some python scripts that are used to print the variables nicer.
If you are investigating a coredump on a different server, you can copy that folder to the server using scp: scp -r /usr/share/gcc-10/python/ user@server:/path/to/server/
.
Activate the pretty printers from the gdb config file
Pretty printers, added this in ~/.gdbinit
:
python
import sys
# gcc-9
sys.path.insert(0, '/usr/share/gcc/python')
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)
end
# Will print the whoile object
set pagination off
set print array on
# It will format the output
set print pretty on
Open the coredump using GDB
gdb executable coredump
Activate the pretty printers inside gdb console
Inside the gdb console you should paste the following code(after you change the path):
set detach-on-fork
set auto-load safe-path /
python
import sys
# !!CHANGE!!
sys.path.insert(0, '/PATH/TO/PRETTY/PRINTERS') # The one from above, ex: `/usr/share/gcc-10/python/`
from libstdcxx.v6.printers import register_libstdcxx_printers
try:
register_libstdcxx_printers(None)
except:
pass
end
This enables pretty printers, which means that this:
high_priority_msgs = {<std::_Vector_base<types::interf>, std::allocator<std::shared_ptr<types::interf> > >> = {
_M_impl = {
<std::allocator<std::shared_ptr<types::interf> >> = {<__gnu_cxx::new_allocator<std::shared_ptr<types::interf> >> = {<No data fields>},
<No data fields>},
<std::_Vector_base<std::shared_ptr<types::interf>, std::allocator<std::shared_ptr<types::interf> > >::_Vector_impl_data> = {
_M_start = 0x7f7498007290, _M_finish = 0x7f74980072e0, _M_end_of_storage = 0x7f74980072e0},
<No data fields>}}, <No data fields>}
Becomes this:
high_priority_msgs = std::vector of length 5, capacity 5 = {
std::shared_ptr<types::interf> (use count 1, weak count 0) = {get() = 0x7f7498006d60},
std::shared_ptr<types::interf> (use count 1, weak count 0) = {get() = 0x7f74980071a0},
std::shared_ptr<types::interf> (use count 1, weak count 0) = {get() = 0x7f749802c8b0},
std::shared_ptr<types::interf> (use count 1, weak count 0) = {get() = 0x7f7498022dd0},
std::shared_ptr<types::interf> (use count 2, weak count 0) = {get() = 0x7f749801c770}}
Investigating the coredump
Show the full backtrace:
bt full
Go to a specific frame:
frame 1
Print the args and the locals from that frame:
print args
print locals
Print a variable:
print high_priority_msgs
Tip 1: If an argument is optimized out, go one frame back, that arg might not be optimized in the previous frame.
Other tips can be found here