Where are GDB symbols coming from?
TL;DR:
- There is a special
.gnu_debugdata
compressed section in Fedora binaries that GDB reads, and which contains mini-symbols. - Contents of that section can be conveniently printed with
eu-readelf -Ws --elf-section /usr/bin/ls
readelf -S /usr/bin/ls | grep abformat
That command is dumping sections. You want symbols instead:
readelf -s /usr/bin/ls | grep abformat
readelf --all /usr/bin/ls | grep abformat
strings /usr/bin/ls | grep abformat
Strings tries to guess what you want, and doesn't output all strings found in the binary. See this blog post and try:
strings -a /usr/bin/ls | grep abformat
Update: I confirmed the results you've observed: abformat
does not appear anywhere, yet GDB knows about it.
Turns out, there is a .gnu_debugdata
compressed section (described here), which has mini-symbols.
To extract this data, normally you would do:
objcopy -O binary -j .gnu_debugdata /usr/bin/ls ls.mini.xz
However, that is broken on my system (produces empty output), so instead I used dd
:
# You may need to adjust the numbers below from "readelf -WS /usr/bin/ls"
dd if=/usr/bin/ls of=ls.mini.xz bs=1 skip=151896 count=3764
xz -d ls.mini.xz
nm ls.mini | grep abformat
This produced:
00000000000005db0 t abformat_init
QED.
Additional info:
- Confusing GDB
no debugging symbols
is addressed in this bug. objcopy
refusing to copy.gnu_debugdata
is the subject of this bug.There is a tool that can conveniently dump this info:
eu-readelf -Ws --elf-section /usr/bin/ls | grep abformat
37: 0000000000005db0 593 FUNC LOCAL DEFAULT 14 abformat_init
no debugging symbols found when using gdb
Some Linux distributions don't use the gdb
style debugging symbols. (IIRC they prefer dwarf2
.)
In general, gcc
and gdb
will be in sync as to what kind of debugging symbols they use, and forcing a particular style will just cause problems; unless you know that you need something else, use just -g
.
Why is gdb not finding any debugging symbols, even though I have -g at every stage of compilation and linkage in my Makefile?
place the source code, the object file, and the executable file in the same directory as where you are running gdb
There are other ways, which require some simple commands into gdb
before entering run
, however; they are a nuisance to redo over and over.
How to know the name and/or path of the debug symbol file which is linked to a binary executable?
how can we know same without actually running gdb?
Either of these commands will tell you:
readelf -x.gnu_debuglink foo
objdump -sj.gnu_debuglink foo
The objcopy --add-gnu-debuglink
simply adds .gnu_debuglink
section containing the given path, and a checksum of the debug file.
More info here.
gdb behaves differently for symbols in the .bss, vs. symbols in .data
glibc includes a symbol named buf
, as well.
(gdb) info variables ^buf$
All variables matching regular expression "^buf$":
File strerror.c:
static char *buf;
Non-debugging symbols:
0x000000000060108b buf <-- this is our buf
0x00007ffff7dd6400 buf <-- this is glibc's buf
gdb happens to choose the symbol from glibc over the symbol from the executable. This is why ptype buf
shows char *
.
Using a different name for the buffer avoids the problem, and so does a global buf
to make it a global symbol. You also wouldn't have a problem if you wrote a stand-alone program that didn't link libc (i.e. define _start
and make an exit system call instead of running a ret
)
Note that 0x00007ffff7dd6400
(address of buf
on my system; different from yours) is not actually a stack address. It visually looks like a stack address, but it's not: it has a different number of f
digits after the 7
. Sorry for that confusion in comments and an earlier edit of the question.
Shared libraries are also loaded near the top of the low 47 bits of virtual address space, near where the stack is mapped. They're position-independent, but a library's BSS space has to be in the right place relative to its code. Checking /proc/PID/maps
again more carefully, gdb's &buf
is in fact in the rwx block of anonymous memory (not mapped to any file) right next to the mapping for libc-2.21.so
.
7ffff7a0f000-7ffff7bcf000 r-xp 00000000 09:7f 17031175 /lib/x86_64-linux-gnu/libc-2.21.so
7ffff7bcf000-7ffff7dcf000 ---p 001c0000 09:7f 17031175 /lib/x86_64-linux-gnu/libc-2.21.so
7ffff7dcf000-7ffff7dd3000 r-xp 001c0000 09:7f 17031175 /lib/x86_64-linux-gnu/libc-2.21.so
7ffff7dd3000-7ffff7dd5000 rwxp 001c4000 09:7f 17031175 /lib/x86_64-linux-gnu/libc-2.21.so
7ffff7dd5000-7ffff7dd9000 rwxp 00000000 00:00 0 <--- &buf is in this mapping
...
7ffffffdd000-7ffffffff000 rwxp 00000000 00:00 0 [stack] <---- more FFs before the first non-FF than in &buf.
A normal call
instruction with a rel32 encoding can't reach a library function, but it doesn't need to because GNU/Linux shared libraries have to support symbol interposition, so call
s to library functions actually jump to the PLT, where an indirect jmp
(with a pointer from the GOT) goes to the final destination.
gdb symbols loaded but no symbols shown for seg fault
Is the problem the fact that the core was created on another system?
Yes, exactly.
See this answer for possible solutions.
Update:
So does this mean I can only debug the program on the system where it is both built and crashes?
It is certainly not true that you can only debug a core on the system where the binary was both built and crashed -- I debug core dumps from different systems every day, and in my case the build host, the host where the program crashed, and the host on which I debug are all separate.
One thing I just noticed: your style of loading the core
: gdb -c core
followed by symbol-file
, doesn't work for PIE executables (at least when using GDB 10.0) -- this may be a bug in GDB.
The "regular" way of loading the core is:
gdb ./ovcc core
See if that gives you better results. (You still need to arrange for matching DSOs, as linked answer shows how to do.)
Debugging: my symbols don't get loaded in gdb?
but none of any help (most of these relate to a forgotten -g flag, or an added -s, stripping down the symbols).
It is almost certain that you either have a stray -s
somewhere on your link line, or you run stip
on the binary during installation.
Look at your link command line and install command carefully, there is strip somewhere in there.
P.S. As Tom Tromey already said, GDB is rarely effective in helping with a problem like this. Using Valgrind or Address Sanitizer will likely get you to the root cause much faster.
Related Topics
Bash: Get List of Commands Starting with a Given String
200,000 Images in Single Folder in Linux, Performance Issue or Not
Why Can't We Use C Standard Library Functions in Kernel Development
The Address Where Filename Has Been Loaded Is Missing [Gdb]
Getting Exit Status Code from 'Ftp' Command in Linux Shell
Shifting from Windows to *Nix Programming Platform
"Cd" Does Not Work in Shell Script
Extract List of File Names in a Zip Archive When 'Unzip -L'
Source Code of Pthread Library
Remove Occurrences of String in Text File
Check If File Is Open with Lsof
Undefined Reference to Symbol 'Dlsym@@Glibc_2.4'
Bumping Version Numbers for New Releases in Associated Files (Documentation)
Checkpoint/Restart Using Core Dump in Linux
How to Read Data from Excel Sheet in Linux Using Shell Script
How to Use Cx_Freeze in Linux to Create a Package to Be Used in Windows