How to GDB step debug a dynamically linked executable in QEMU user mode? - gdb

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.

Related

debuginfod-find work, but gdb can not find the symbols?

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

Cross-compile wxGtk

I have to cross-compile wxGtk (an old version: 2.8.11) and managed to setup the environment so that configure runs successfully.
$ export CC=/opt/my_toolchain/toolchain_base/bin/i686-pc-linux-gnu-gcc
$ export CXX=/opt/my_toolchain/toolchain_base/bin/i686-pc-linux-gnu-g++
$ export CPPFLAGS=-I/opt/my_toolchain/additional_libs/usr/include/
$ export PKG_CONFIG_SYSROOT_DIR=/opt/my_toolchain/additional_libs/
$ export PKG_CONFIG_PATH=/opt/my_toolchain/additional_libs/usr/lib/pkgconfig
$ export PKG_CONFIG_DIR=/opt/my_toolchain/additional_libs/usr/lib/pkgconfig
$ export PKG_CONFIG_LIBDIR=/opt/my_toolchain/additional_libs/sysroot/usr/lib/
// LDFLAGS evtl falsch?? nicht ueberschreiben!?
$ export LDFLAGS="-L/opt/my_toolchain/additional_libs/lib/ -L/opt/my_toolchain/additional_libs/usr/lib/"
$ export CFLAGS="-Wl,-rpath-link=/opt/my_toolchain/additional_libs/lib/ -Wl,-rpath-link=/opt/my_toolchain/additional_libs/usr/lib/"
$ export CXXFLAGS="-Wl,-rpath-link=/opt/my_toolchain/additional_libs/lib/ -Wl,-rpath-link=/opt/my_toolchain/additional_libs/usr/lib/"
$ export LD_LIBRARY_PATH=/opt/my_toolchain/additional_libs/lib/:/opt/my_toolchain/additional_libs/usr/lib/:/opt/my_toolchain/additional_libs/usr/lib/:/opt/my_toolchain/additional_libs/lib/
$ pkg-config --define-variable=pc_path=/opt/my_toolchain/additional_libs/usr/lib/pkgconfig pkg-config
wxGTK-2.8.11 $ ./configure --enable-unicode --disable-shared --prefix=/usr/local/<targetname>
[...]
Configured wxWidgets 2.8.11 for `x86_64-unknown-linux-gnu'
Which GUI toolkit should wxWidgets use? GTK+ 2
Should wxWidgets be compiled into single library? no
Should wxWidgets be compiled in debug mode? no
Should wxWidgets be linked as a shared library? no
Should wxWidgets be compiled in Unicode mode? yes
What level of wxWidgets compatibility should be enabled?
wxWidgets 2.4 no
wxWidgets 2.6 yes
Which libraries should wxWidgets use?
jpeg sys
png sys
regex builtin
tiff sys
zlib sys
odbc no
expat sys
libmspack no
sdl no
However the subsequent make reports an error:
wxGTK-2.8.11 $ make
[...]
bk-make-pch ./.pch/wxprec_netlib/wx/wxprec.h.gch wx/wxprec.h /opt/my_toolchain/toolchain_base/bin/i686-pc-linux-gnu-g++ -I./.pch/wxprec_netlib -D__WXGTK__ -DWXBUILDING -I./src/regex -DwxUSE_GUI=0 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -I/mnt/cifs/osb_m/10_Competence_Centers/21_CC_IE/22_Kunden_Technik_Aktiv/Holmer/Software/Holmer_VT-Server/wxGTK-2.8.11/lib/wx/include/gtk2-unicode-release-static-2.8 -I./include -pthread -I/opt/my_toolchain/additional_libs//usr/include/gtk-2.0 -I/opt/my_toolchain/additional_libs//usr/lib/gtk-2.0/include -I/opt/my_toolchain/additional_libs//usr/include/pango-1.0 -I/opt/my_toolchain/additional_libs//usr/include/atk-1.0 -I/opt/my_toolchain/additional_libs//usr/include/cairo -I/opt/my_toolchain/additional_libs//usr/include/pixman-1 -I/opt/my_toolchain/additional_libs//usr/include/libpng16 -I/opt/my_toolchain/additional_libs//usr/include/gdk-pixbuf-2.0 -I/opt/my_toolchain/additional_libs//usr/include/libpng16 -I/opt/my_toolchain/additional_libs//usr/include/pango-1.0 -I/opt/my_toolchain/additional_libs//usr/include/harfbuzz -I/opt/my_toolchain/additional_libs//usr/include/pango-1.0 -I/opt/my_toolchain/additional_libs//usr/include/freetype2 -I/opt/my_toolchain/additional_libs//usr/include/glib-2.0 -I/opt/my_toolchain/additional_libs//usr/lib/glib-2.0/include -I/opt/my_toolchain/additional_libs/usr/include/ -DWX_PRECOMP -pthread -Wall -Wundef -Wno-ctor-dtor-privacy -O2 -fno-strict-aliasing -Wl,-rpath-link=/opt/my_toolchain/additional_libs/lib/ -Wl,-rpath-link=/opt/my_toolchain/additional_libs/usr/lib/
In file included from /opt/my_toolchain/additional_libs/usr/include/math.h:46:0,
from ./include/wx/math.h:19,
from ./include/wx/wx.h:30,
from ./include/wx/wxprec.h:68:
/opt/my_toolchain/additional_libs/usr/include/bits/mathdef.h:47:6: warning: "__FP_FAST_FMA" is not defined [-Wundef]
/opt/my_toolchain/additional_libs/usr/include/bits/mathdef.h:51:6: warning: "__FP_FAST_FMAF" is not defined [-Wundef]
/opt/my_toolchain/additional_libs/usr/include/bits/mathdef.h:55:6: warning: "__FP_FAST_FMAL" is not defined [-Wundef]
/opt/my_toolchain/toolchain_base/bin/../i686-pc-linux-gnu/libc/usr/lib/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: error: ld returned 1 exit status
Makefile:12022: recipe for target '.pch/wxprec_netlib/wx/wxprec.h.gch' failed
make: *** [.pch/wxprec_netlib/wx/wxprec.h.gch] Error 1
I've printed the compiler command which reports the issue:
/opt/my_toolchain/toolchain_base/bin/i686-pc-linux-gnu-g++ \
-I./.pch/wxprec_baselib -D__WXGTK__ -DWXBUILDING \
-I./src/regex \
-DwxUSE_GUI=0 -DwxUSE_BASE=1 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES \
-I/path/to/wxGTK-2.8.11/lib/wx/include/gtk2-unicode-release-static-2.8 \
-I./include \
-pthread \
-I/opt/my_toolchain/additional_libs//usr/include/gtk-2.0 \
-I/opt/my_toolchain/additional_libs//usr/lib/gtk-2.0/include \
-I/opt/my_toolchain/additional_libs//usr/include/pango-1.0 \
-I/opt/my_toolchain/additional_libs//usr/include/atk-1.0 \
-I/opt/my_toolchain/additional_libs//usr/include/cairo \
-I/opt/my_toolchain/additional_libs//usr/include/pixman-1 \
-I/opt/my_toolchain/additional_libs//usr/include/libpng16 \
-I/opt/my_toolchain/additional_libs//usr/include/gdk-pixbuf-2.0 \
-I/opt/my_toolchain/additional_libs//usr/include/libpng16 \
-I/opt/my_toolchain/additional_libs//usr/include/pango-1.0 \
-I/opt/my_toolchain/additional_libs//usr/include/harfbuzz \
-I/opt/my_toolchain/additional_libs//usr/include/pango-1.0 \
-I/opt/my_toolchain/additional_libs//usr/include/freetype2 \
-I/opt/my_toolchain/additional_libs//usr/include/glib-2.0 \
-I/opt/my_toolchain/additional_libs//usr/lib/glib-2.0/include \
-I/opt/my_toolchain/additional_libs/usr/include/ \
-DWX_PRECOMP -pthread -Wall -Wundef -Wno-ctor-dtor-privacy -O2 -fno-strict-aliasing \
-Wl,-rpath-link=/opt/my_toolchain/additional_libs/lib/ \
-Wl,-rpath-link=/opt/my_toolchain/additional_libs/usr/lib/ \
-o ./.pch/wxprec_baselib/wx/wxprec.h.gch \
-MMD -MF \
./.deps/___pch_wxprec_baselib_wx_wxprec_h_gch.d \
./include/wx/wxprec.h
If I remove the two the -Wl,-rpath-link= statements from this compiler command and invoke it manually, the command succeeds.
It seems the additional -Wl statements make the compiler miss the source file with the main()-function (which seems to be provided via ./include/wx/wxprec.h), but I don't really see how that could happen.
I'd be grateful about any advice how I can address this problem.
Update
The configure-Script has the usual options (no --source)
--build=BUILD configure for building on BUILD [guessed]
--host=HOST cross-compile to build programs to run on HOST [BUILD]
--target=TARGET configure for building compilers for TARGET [HOST]
where --target is of no interest. The other options I'll have to check. As I mentioned in the comments, I've so far only seen them being used with prefixes e.g. aarch64-linux-gnu for toolchains from package repositories which are in the $PATH, and with according libraries etc.
So I've added the folder for toolchain binaries to path and configured with
./configure --enable-unicode --disable-shared --prefix=/usr/local/<target> --host=i686-pc-linux-gnu
configure: WARNING: If you wanted to set the --build type, don't use --host.
If a cross compiler is detected then cross compile mode will be used.
checking build system type... x86_64-unknown-linux-gnu
checking host system type... i686-pc-linux-gnu
checking target system type... i686-pc-linux-gnu
That looks correct. I want to build on my local machine for another target.
But:
checking for GTK+ - version >= 2.0.0... no
*** Could not run GTK+ test program, checking why...
*** The test program failed to compile or link. See the file config.log for the
*** exact error that occured. This usually means GTK+ is incorrectly installed.
configure: error:
The development files for GTK+ were not found. For GTK+ 2, please
ensure that pkg-config is in the path and that gtk+-2.0.pc is
installed. For GTK+ 1.2 please check that gtk-config is in the path,
and that the version is 1.2.3 or above. Also check that the
libraries returned by 'pkg-config gtk+-2.0 --libs' or 'gtk-config
--libs' are in the LD_LIBRARY_PATH or equivalent.
Unfortunately that makes sense. The toolchain itself only has some libraries, but does not have the GTK-libraries.
/opt/my_toolchain/toolchain_base/
The GTK libraries and other libraries are in a separate folder:
/opt/my_toolchain/additional_libs/
And the toolchain's binaries don't know about this folder.
I think the whole issue arises because wxGtk builds libraries for the host = i686-pc-linux-gnu, but also builds executables (e.g. wx-config) for the build-system = x86_64-unknown-linux-gnu.
The wxGtk 2.8.11 cross-build is finally working with the following setup:
export PATH=/opt/my_toolchain/toolchain_base/bin/:${PATH}
export PKG_CONFIG_SYSROOT_DIR=/opt/my_toolchain/additional_libs
export PKG_CONFIG_PATH=/opt/my_toolchain/additional_libs/usr/lib/pkgconfig
export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1
# make sure those env vars are not left from previous setup
unset CC
unset CXX
unset CPPFLAGS
unset CFLAGS
unset CXXFLAGS
unset LD_LIBRARY_PATH
unset LDFLAGS
unset PKG_CONFIG_DIR
unset PKG_CONFIG_LIBDIR
./configure --enable-unicode --disable-shared --prefix=/usr/local/<target> --host=i686-pc-linux-gnu --build=x86_64-linux-gnu
make
sudo make install

how to compile dlib and its examples in debug mode (in ubuntu)?

I'm trying to use ddd (a kind of graphic debugger, using gdb inside) to analyze the dlib , a c++ machine learning library running the dnn_face_recognition_ex example program.
Under the example directory, I did
# mkdir build
# cd build
# cmake ..
# cmake --build . --config Debug
but when I run ddd --args dnn_face_recoginition ../faces/bald_guys.jpg
I see no debugging symbols found message from the ddd.
What should I do? I'm doing it on a ubuntu 16.04 machine.
(But the example program runs ok without debugging.)
I found http://devdoc.net/c/dlib-19.7/compile.html and tried (under examples/build)
g++ -std=c++11 -O2 -g -I../.. ../../dlib/all/source.cpp -lpthread -lX11 ../dnn_face_recognition_ex.cpp -o dnn_face_recognition_ex
and now I can run it in debug mode by
ddd --args dnn_face_recognition_ex ../faces/bald_guys.jpg

Strange behavior with gdb printf

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

No access to environment variables while remote compiling using Code::Blocks, plink and makefiles

I'm trying to set up Code::Blocks under Windows 7 Professional SP1 to work for remote compilation (using PuTTY link -> plink) on a linux server, but I am not much familiar with that topic. This is the manual I used:
http://wiki.codeblocks.org/index.php?title=Using_Xming_for_remote_compilation
I configured Code blocks as follows:
Settings->Compiler and debugger->Global compiler settings->Toolchain executabes:
Program Files->Make program: plink.exe
Project->Properties->Project Settings:
Makefile: makefile_name
[checked] This is a custom makefile
Execution direction: Z:\Path\to\Samba\Share
Project's build options->Debug->"Make" commands:
Build project/target:
$make -X -ssh user#linux_server -pw my_great_password make -f $makefile -C /path/to/my/makefile
Compile single file:
$make -X -ssh user#linux_server -pw my_great_password make -f $makefile -C /path/to/my/makefile $file
Clean project/target:
$make -X -ssh user#linux_server -pw my_great_password make -f $makefile clean -C /path/to/my/makefile
Ask if rebuild is needed:
$make -X -ssh user#linux_server -pw my_great_password make -q -f $makefile -C /path/to/my/makefile
Silent build:
$make -X -ssh user#linux_server -pw my_great_password make -s -f $makefile -C /path/to/my/makefile
By the way, do I invoke the compiler/linker on the linux server or is Code::Blocks itself compiling and linkung the source on the linux server? Excuse my nescience.
The problem I am facing now, is that I can not access environment variables in the makefile:
include $(MY_ENV_VAR)/path/to/another/makefile
The error I receive let's me assume, that MY_ENV_VAR remains empty:
/path/to/another/makefile: No such file or directory
I checked if Code::Blocks tries to resolve the environment variable of my windows computer but that is not the case.
Additional information:
Code::Blocks version:
Version: 10.05, Build: May 27 2010, 19:10:05 - wx2.8.10 (Windows, unicode) - 32 bit
Linux server:
Linux linux_server 2.6.18-238.el5 #1 SMP Sun Dec 19 14:22:44 EST 2010 x86_64 x86_64 x86_64 GNU/Linux
I can provide more information if needed. I also welcome other suggestions to realize a remote compilation on a linux machine from windows. Or is another IDE more suitable for doing remote compilation?
Thanks for reading/helping.
Edit:
I found someone having a similar problem with NetBeans IDE:
http://forums.netbeans.org/topic37974.html
According to this stackoverflow post and this fixunix post I could figure out, that plink doesn't execute startup scripts as it is the case, when you connect via putty. So I realized that Code::Blocks was innocent concerning my difficulties while trying to remote compile.
In my case, I had to explicitly source the login script ~/.login to have access to my environment variables. For the make command this would for example mean:
$make -X -ssh user#linux_server -pw my_great_password "source ~/.login;make -f $makefile" -C /path/to/my/makefile
This way a managed to remote compile my software. To start the application, I added a post-build step:
cmd /c "C:\Program^ Files\PuTTY\putty.exe -load my_session -pw my_great_password"
In the password, I had to escape an ampersand character: ^& (by the way, there are many reasons to use a private key instead of a hardcoded password). This loads a stored PuTTY session, which has the following remote command(s):
source ~/.login;/path/to/my/application/my_application;$<
I'm using the C shell. Therefore I used $< to wait for an user input (enter key). Now I can compile and run my application by hitting the build button. Hope this helps others to configure Code::Blocks for remote compilation. Just leave a comment if you're facing further problems or if you want to provide additional information/advice.