I use this process to build & setup debuginfod
gcc -g foo.c -o foo
objcopy --only-keep-debug foo foo.dbg
strip foo
objcopy --add-gnu-debuglink=foo.dbg foo
mkdir srv
mv foo.dbg srv
debuginfod -F srv/foo.dbg > debuginfod.log 2>&1 &
DEBUGINFOD_URLS=http://localhost:8002
gdb foo
output of debuginfod-find -v debuginfo foo workable
debuginfod_find_debuginfo b4c57580d6dbd0a19d0e41b38ec33cc7b992bfc8
server urls "http://localhost:8002"
checking build-id
checking cache dir /home/example/.cache/debuginfod_client
found /home/example/.cache/debuginfod_client/b4c57580d6dbd0a19d0e41b38ec33cc7b992bfc8/debuginfo (fd=4)
/home/example/.cache/debuginfod_client/b4c57580d6dbd0a19d0e41b38ec33cc7b992bfc8/debuginfo
output of gdb foo
Reading symbols from foo...Missing separate debuginfo for /home/example/tmp/foo/foo
Try: yum --enablerepo='*debug*' install /usr/lib/debug/.build-id/b4/c57580d6dbd0a19d0e41b38ec33cc7b992bfc8.debug
(no debugging symbols found)...done.
About the version
gdb --version # 8.2-18.el8
debuginfod_client --version # 0.186.
Related rpm(Rocky Linux)
gdb-8.2-18.el8.x86_64
elfutils-debuginfod-client-0.186-1.el8.x86_64
elfutils-debuginfod-0.186-1.el8.x86_64
gcc-8.5.0-10.1.el8_6.x86_64
My current workaround is
(gdb) add-symbol-file /home/example/.cache/debuginfod_client/b4c57580d6dbd0a19d0e41b38ec33cc7b992bfc8/debuginfo
Related
The context
Consider the following file
$ cat main.cpp
int main() {return 0;}
I can list all the available functions by executing
$ g++ -g main.cpp && gdb -q -batch -ex 'info functions -n' a.out
All defined functions:
File main.cpp:
1: int main();
When executing start before executing info functions more than 1000 functions are listed (see below)
g++ -g main.cpp && \
gdb -q -batch -ex 'start' -ex 'info functions -n' a.out | \
head -n 10
Temporary breakpoint 1 at 0x111d: file main.cpp, line 1.
Temporary breakpoint 1, main () at main.cpp:1
1 int main() {return 0;}
All defined functions:
File /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/allocated_ptr.h:
70: void std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<std::filesystem::__cxx11::filesystem_error::_Impl, std::allocator<std::filesystem::__cxx11::filesystem_error::_Impl>, (__gnu_cxx::_Lock_policy)2> > >::~__allocated_ptr();
70: void std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<std::filesystem::filesystem_error::_Impl, std::allocator<std::filesystem::filesystem_error::_Impl>, (__gnu_cxx::_Lock_policy)2> > >::~__allocated_ptr();
As seen below, the total number of lines printed is so, apparently, more than 1000 functions are being listed
g++ -g main.cpp && gdb -q -batch -ex 'start' -ex 'info functions -n' a.out | wc -l
4436
The question
As we can see above, the main.cpp file does not contain any function, so why is gdb listing those functions when the start command has been executed before but not when start hasn't been executed?
Additional context
As suggested in one of the comments of this question, here's the output of executing info shared after start has been executed
g++ -g main.cpp && gdb -q -batch -ex 'start' -ex 'info shared' a.out
Temporary breakpoint 1 at 0x111d: file main.cpp, line 1.
Temporary breakpoint 1, main () at main.cpp:1
1 int main() {return 0;}
From To Syms Read Shared Object Library
0x00007ffff7fd2090 0x00007ffff7ff2746 Yes (*) /lib64/ld-linux-x86-64.so.2
0x00007ffff7e4c040 0x00007ffff7f37b52 Yes /usr/lib/libstdc++.so.6
0x00007ffff7c7f3b0 0x00007ffff7d1a658 Yes (*) /usr/lib/libm.so.6
0x00007ffff7c59020 0x00007ffff7c69ca5 Yes /usr/lib/libgcc_s.so.1
0x00007ffff7ab3650 0x00007ffff7bfe6bd Yes (*) /usr/lib/libc.so.6
(*): Shared library is missing debugging information.
main.cpp file does not contain any function, so why is gdb listing those functions when the start command has been executed before but not when start hasn't been executed?
Before start, GDB reads symbols (and debug info) only for the main executable.
After start, a dynamically linked executable loads shared libraries (seen in info shared), and GDB (by default) reads symbol tables and debug info for each of them. And since these libraries contain hundreds of functions, GDB knows about all of them.
You can prevent this with set auto-solib-add off, but usually you don't want to do that. If you do, and your program crashes in e.g. abort, GDB will not know where you crashed unless you manually add the symbols back using sharedlibrary or add-symbol-file command.
I have a issue with gdb printf in version 9.1
echo -e '#include<stdio.h> \n int main(){ \n printf("Hello"); \n }' > test.c
gcc -g test.c -o test
echo 'break test.c:4' > test.gdb
echo 'run' >> test.gdb
echo 'set $aux = (char*)malloc(256)' >> test.gdb
echo 'set $e = strcpy($aux, "abc")' >> test.gdb
echo 'printf "%s", $aux' >> test.gdb
gdb --batch --command=test.gdb test
Output with gdb 9.1:
Breakpoint 1 at 0x1167: file test.c, line 4.
Breakpoint 1, main () at test.c:4
4 }
�e���
Expected output (same as gdb v8):
Breakpoint 1 at 0x1167: file test.c, line 4.
Breakpoint 1, main () at test.c:4
4 }
abc
I've checked charset, but it seems ok.
Any idea about that?
This is Bug 25650 - GDB can't 'printf' a convenience variable holding an inferior address, fixed in gdb 9.2.
If you can't upgrade to gdb 9.2 but can recompile your existing distro's gdb 9.1, there is a two-line patch.
On Ubuntu 20.04, which comes with gdb 9.1-0ubuntu1:
run apt build-dep gdb to haul in the packages needed to build gdb from source
run apt install dpkg-dev (to get /usr/bin/dpkg-source)
uncomment the deb-src lines in /etc/apt/sources.list
run apt update
cd to an empty directory and run apt source gdb . Doing this in a fresh new directory will make it easier to clean things up after the compilation.
cd to gdb-9.1 and apply the patch to gdb/printcmd.c
build and install gdb. For example, to put it in /usr/local/bin, the default, you'd run
mkdir build
cd build
../configure
make
make install
For example for ARM, if I compile statically, all works fine:
sudo apt-get install gdb-multiarch gcc-arm-linux-gnueabihf qemu-user
printf '
#include <stdio.h>
#include <stdlib.h>
int main() {
puts("hello world");
return EXIT_SUCCESS;
}
' > hello_world.c
arm-linux-gnueabihf-gcc -ggdb3 -static -o hello_world hello_world.c
qemu-arm -L /usr/arm-linux-gnueabihf -g 1234 ./hello_world
On another terminal:
gdb-multiarch -q --nh \
-ex 'set architecture arm' \
-ex 'set sysroot /usr/arm-linux-gnueabihf' \
-ex 'file hello_world' \
-ex 'target remote localhost:1234' \
-ex 'break main' \
-ex continue \
;
This leaves me at main, and I can see the source and step debug as usual.
However, if I remove the -static, and keep everything else unchanged, my breakpoint never gets hit, and the program runs until completion:
The target architecture is assumed to be arm
Reading symbols from hello_world...done.
Remote debugging using localhost:1234
Reading symbols from /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3...(no debugging symbols found)...done.
0xff7b3b80 in ?? () from /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3
Breakpoint 1 at 0x50c: file hello_world.c, line 5.
Continuing.
[Inferior 1 (Remote target) exited normally]
The executable itself does work fine however:
qemu-arm -L /usr/arm-linux-gnueabihf ./hello_world
prints:
hello world
I have seen: How to single step ARM assembler in GDB on Qemu? but it didn't cover the case of dynamically linked executables specifically.
Tested on Ubuntu 18.04, gdb-multiarch 8.1-0ubuntu3, gcc-arm-linux-gnueabihf 4:7.3.0-3ubuntu2, qemu-user 1:2.11+dfsg-1ubuntu7.3.
Edit: working pristine crosstool-ng setup
As a sanity check, I tried to get a clean toolchain with crosstool-ng, and it worked:
git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
git checkout d5900debd397b8909d9cafeb9a1093fb7a5dc6e6
export CT_PREFIX="$(pwd)/.build/ct_prefix"
./bootstrap
./configure --enable-local
./ct-ng arm-cortex_a15-linux-gnueabihf
# Has to be older than host kernel, which is 4.15.
printf "
CT_LINUX_V_4_14=y
CT_LINUX_VERSION=\"4.14.0\"
" >> .config
./ct-ng oldconfig
env -u LD_LIBRARY_PATH time ./ct-ng build -j`nproc`
cd ..
crosstool-ng/.build/ct_prefix/arm-cortex_a15-linux-gnueabihf/bin/arm-cortex_a15-linux-gnueabihf-gcc -ggdb3 -o hello_world hello_world.c -ggdb3 -static -o hello_world hello_world.c
qemu-arm -L crosstool-ng/.build/ct_prefix/arm-cortex_a15-linux-gnueabihf/arm-cortex_a15-linux-gnueabihf/sysroot -g 1234 ./hello_world
And on another shell:
./.build/ct_prefix/arm-cortex_a15-linux-gnueabihf/bin/arm-cortex_a15-linux-gnueabihf-gdb \
-q --nh \
-ex 'set architecture arm' \
-ex 'set sysroot crosstool-ng/.build/ct_prefix/arm-cortex_a15-linux-gnueabihf/arm-cortex_a15-linux-gnueabihf/sysroot' \
-ex 'file hello_world' \
-ex 'target remote localhost:1234' \
-ex 'break main' \
-ex continue \
;
And it also works with the distro provided gdb-multiarch.
The failure is due to -pie -fpie, and there is a bug report for it at: https://bugs.launchpad.net/qemu/+bug/1528239
Explicitly setting -no-pie -fno-pie makes it work on both crosstool-ng and Ubuntu host.
The difference is that the Ubuntu one has GCC built to use -fpie by default, while my crosstool-ng build did not.
This can be checked with:
gcc -v
which on the host GCC contains:
--enable-default-pie
but not in the crosstool-ng build.
How I found this out: the other day I was playing around with -fpie and I noticed that the .text addresses were really small in that case: What is the -fPIE option for position-independent executables in gcc and ld?
Then I saw that the break address was very small with the packaged toolchain, and made the link.
I'm building the dnstracer application from source with this script:
#!/bin/bash
#########
# FILES #
#########
PACKAGE_NAME=dnstracer-1.6
PACKAGE_TAR_FILE=${PACKAGE_NAME}.tar.gz
PACKAGE_FTP_SITE=http://ftp.iij.ad.jp/pub/linux/momonga/1/PKGS/SOURCES/
####################################
# REMOVE OLD STUFF JUST TO BE SURE #
####################################
rm -rf build
rm -rf ${PACKAGE_NAME}
rm -rf ${PACKAGE_TAR_FILE}
#####################################
# Get source code for buggy package #
#####################################
wget ${PACKAGE_FTP_SITE}/${PACKAGE_TAR_FILE}
######################
# Unpack it here ... #
######################
tar xf ${PACKAGE_TAR_FILE}
##########################################
# Prepare an out of tree build directory #
##########################################
mkdir build
##############################
# Get inside build directory #
##############################
cd build
#################
# Configure ... #
#################
../${PACKAGE_NAME}/configure
###############
# Make it !!! #
###############
make -j
And I see it ships with its own getopt, which is good for me because I need to debug it:
$ ls -l ./dnstracer-1.6/getopt.*
./dnstracer-1.6/getopt.c
./dnstracer-1.6/getopt.h
However when I try to step inside getopt from gdb, I realize that it probably has some other getopt (maybe without debug symbols?) and it doesn't let me step inside:
$ cd build
$ gdb --args ./dnstracer -v aaaaaa
$ (gdb) break main
$ (gdb) run
$ (gdb) next
$ 1304 while ((ch=getopt(argc,argv,"coq:r:s:t:v"))!=-1) {
$ step
$ 1305 switch (ch) {
How can I configure the build process to use the shipped getopt version rather than some hidden default? Thanks!
And I see it ships with its own getopt, which is good for me because I
need to debug it:
Since you are on Ubuntu this is not the case for you, see in shipped getopt.h:
// Only used in the win32-version of dnstracer.
// Supplied by Mike Black <mblack#csihq.com>
Therefore you are using system getopt which is part of glibc. In order to step into getopt you need glibc debug symbols installed. See https://stackoverflow.com/a/48287761/72178 on how to debug glibc on Ubuntu.
I've built GCC 4.9.3 from sources and installed into my home directory with some prefix, e.g. gcc4.9.
Now I want to use a newer version of binutils along with GCC 4.9.3. I've built them and installed separately in my home directory, with prefix binutils2.26.
How I can force gcc-ar from gcc4.9 to use ar from binutils2.26 instead of system one? It always calls /usr/bin/ar and looks like there is no options to specify. Replacing /usr/bin/ar somehow is not an option - I don't have root access on this machine.
Use GCC's -B flag and point it at the directory that contains the ar you want to execute. See the GCC manual for more details on this flag.
gcc-ar -B/path/to/your/dir ...
It seems to work for me:
$ strace -f -eexecve gcc-ar rc foo.a /dev/null |& grep /ar
[pid 14485] execve("/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/../../../../x86_64-pc-linux-gnu/bin/ar", [...]) = 0
$ strace -f -eexecve gcc-ar rc foo.a /dev/null -B/usr/bin |& grep /ar
[pid 14493] execve("/usr/bin/ar", [...]) = 0
$ strace -f -eexecve gcc-ar rc foo.a /dev/null -B/usr/x86_64-pc-linux-gnu/binutils-bin/2.26/ |& grep /ar
[pid 14500] execve("/usr/x86_64-pc-linux-gnu/binutils-bin/2.26/ar", [...]) = 0
I managed to fix this issue.
Using strace, I found that gcc-ar looks for ar in several directories, including <gcc install dir>/libexec/gcc/x86_64-redhat-linux/4.9.3.
So the obvious solution is to create links in this directory targeting corresponding binutils2.26 executables:
cd "<gcc install dir>/libexec/gcc/x86_64-redhat-linux/4.9.3"
for file in ~/binutils2.26/bin/* ; do ln -s "${file}" ; done
After that all, executables in ~/binutils2.26/bin will be replicated as links in the GCC 4.9.3 directory and will be used automatically when building by that GCC version.