How can gdb on a remote host read source files from the host machine? - gdb

I would like to debug a C++ program on a remote embedded device.
I have gdb on the remote machine, as well as an adb connection. I can obviously copy there my source files. The problem is that the source path that is stored in the .debug_info section of the compiled binary refer to the host machine paths, which differ from the location the files are stored on the remote machine, and I cannot change the filesystem so that the paths match. For example, here is the .debug_info section
Compilation Unit # offset 0x0:
Length: 0x33aea (32-bit)
Version: 4
Abbrev Offset: 0x0
Pointer Size: 4
<0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
<c> DW_AT_producer : (indirect string, offset: 0x1ec94): GNU C++ 4.9.3 -march=armv7-a -mfloat-abi=softfp -mfpu=neon -mtls-dialect=gnu -g -O2 -std=gnu++1y -fexpensive-optimizations -frename-registers -fomit-frame-pointer -ftree-vectorize -finline-functions -finline-limit=64 -fPIC
<10> DW_AT_language : 4 (C++)
<11> DW_AT_name : (indirect string, offset: 0x23eae): /home/david/main.cpp
<15> DW_AT_comp_dir : (indirect string, offset: 0x321ad): /home/david/cmake-build-debug
<19> DW_AT_ranges : 0x1f68
<1d> DW_AT_low_pc : 0x0
<21> DW_AT_stmt_list : 0x0
Here, /home/david/main.cpp is the location of the source file on the host machine. The same file on the remote device will have a different path.
I discovered that I can change the DW_AT_comp_dir using -fdebug-prefix-map, or using the directory command on gdb, but this does not solve the problem because the DW_AT_name is an absolute path and not a relative one.
The reason why DW_AT_name is absolute is that the project is compiled using cmake, which uses absolute paths, and I could not find a way to make it use relative paths.
How do you suggest I solve this? My end goal is obviously to be able to see the source code from gdb on the remote machine

Related

From where does gdb take the code lines?

When I compile a program with -g and get a core dump I can use gdb to read the executable and the core dump to debug the situation the program run into before it crashed. One of the features gdb offers is the list option, it is possible to list the source code which was compiled using the executable and the core dump. I used strings -a with the executable and the core dump and I couldn't find even one if or for statements while I'm sure the code has plenty of them. So where does the code is coming from? I compile the code on one computer and run it on different one, so the source code is not available on the computer where the core dump is generated, and it doesn't seem to be inside the executable or the core dump. Any suggestions? I really want to print all the source code from the executable and from the core dump, is it possible? I mean without running gdb, I'm sure it is possible to write a script which uses gdb and that can list the entire code but I'm interested in doing it myself without gdb because I want to understand from where the source code is taken how it is formatted, I want o know as much as possible about it.
The line information is located in the .debug_line DWARF sections of the executable:
$readelf -wL ./a.out
Decoded dump of debug contents of section .debug_line:
CU: bla.c:
File name Line number Starting address
bla.c 2 0x4004b6
bla.c 3 0x4004ba
bla.c 4 0x4004bf
This sections maps instruction pointer addresses to line numbers in a given file.
In order to find the content of the file, you need to be able to finds the relevant source file. If you move/rename the source file, GDB will not be able to print the source code:
mv bla.c bla2.c
gdb ./a.out
(gdb) break main
(gdb) run
(gdb) list
1 in bla.c
The .debug_info DWARF sections has some information on the path where the source file was when it was compiled which may be used to find the relevant file:
$objdump -Wi -wa ./a.out
./a.out: file format elf64-x86-64
./a.out
Contents of the .debug_info section:
Compilation Unit # offset 0x0:
Length: 0x4e (32-bit)
Version: 4
Abbrev Offset: 0x0
Pointer Size: 8
: Abbrev Number: 1 (DW_TAG_compile_unit)
DW_AT_producer : (indirect string, offset: 0x0): GNU C 4.9.1 -mtune=generic -march=x86-64 -g
DW_AT_language : 1 (ANSI C)
DW_AT_name : (indirect string, offset: 0x59): bla.c
DW_AT_comp_dir : (indirect string, offset: 0x31): /home/myself/temp/bla
DW_AT_low_pc : 0x4004b6
DW_AT_high_pc : 0xb
DW_AT_stmt_list : 0x0
: Abbrev Number: 2 (DW_TAG_subprogram)
DW_AT_external : 1
DW_AT_name : (indirect string, offset: 0x2c): main
DW_AT_decl_file : 1
DW_AT_decl_line : 2
DW_AT_type :
DW_AT_low_pc : 0x4004b6
DW_AT_high_pc : 0xb
DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa)
DW_AT_GNU_all_call_sites: 1
: Abbrev Number: 3 (DW_TAG_base_type)
DW_AT_byte_size : 4
DW_AT_encoding : 5 (signed)
DW_AT_name : int
: Abbrev Number: 0
Each DW_TAG_compile_unit has information about the source file name and path which is used to find the relevant source file.
I you want to do it all by yourself, you should probably read some relevant parts of the DWARF specifications and use a library such as libdw (which is a part of elfutils).

C++ use a linux library on a mac (elf64-x86-64 on x86_64-apple-darwin)

I'm currently trying to compile a program on a Mac OS X (10.9) using a library initially compiled for Linux.
Is there a way to use this library? Here is the output of objdump -f libmylib.a:
Hour.o: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x0000000000000000
Menu.o: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x0000000000000000
Tools.o: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x0000000000000000
I know my current architecture is x86_64-apple-darwin13.0.0, and I wonder if, with the appropriate compiler flags, there is a way to make this compile.
One more thing, here is the error when trying to compile:
g++ -L /Users/gustavemonod/Desktop/ -o Parking Mother.o Keyboard.o -lncurses -ltcl -lmylib
ld: warning: ignoring file /Users/gustavemonod/lib/libmylib.a, file was built for archive which is not the architecture being linked (x86_64): /Users/gustavemonod/lib/libmylib.a
Linux uses a library format called ELF. Mac does not use ELF (instead, Mac uses a format called Mach-O), so I suspect that's going to be very difficult (if not actually impossible). You might be able to make the Linux Binary Compatibility from FreeBSD work.
You cannot link ELF objects (or archives or shared libraries) with Mach-O. You can try using Agner Fog's objconv utility, to convert x86-64 ELF to x86-64 Mach-O, which use the same (ELF) calling conventions. I wouldn't recommend this approach if you can compile from source.

symbols not showing up when debugging under clang 3.3/3.4 vs gcc 4.8

Situation:
I have an autotools project, written in c++11, that I can compile using either clang 3.3/3.4 or gcc 4.8.
My autotools project builds a shared library, and an executable.
If I use gcc 4.8, and debug the executable, I can add a watchpoint to inspect the value of a global variable that exists in the shared library.
When I use QT creator or CDT or other debugger, or even when I look at the output of gdb 7.6.2: when compiled with clang, it says "no such value" in the debugging output, whereas with gcc I can inspect the values of the global variable in the debugger.
I'm sending essentially the same switches to gcc and clang, -O0 -g. With both compilers, I can inspect and see values on the stack, but just with clang 3.3 or clang 3.4 generated output I cannot inspect global variables that exist in the shared library. My environment is Ubuntu 12.04, with self-compiled clang and gdb.
I have confirmed that the global symbols I'm inspecting do exist in the shared library generated by either compilers.
Is there some particular compiler switch or something that I should be sending to clang in order to be able to debug the symbols in the shared library? Or is this possibly a bug with clang?
According to my experience clang 3.3 messes up debug information. Let's consider for example a simple program:
#include <string>
int main()
{
std::string s("foo");
s.size();
return 0;
}
Compile:
$ clang++ -O0 -ggdb -c t.cpp -o t.o
Now let's check the debug symbols:
$ objdump --dwarf=info t.o | grep -A2 -B1 _Rep
<3><3c3>: Abbrev Number: 29 (DW_TAG_structure_type)
<3c4> DW_AT_name : (indirect string, offset: 0x2ff): _Rep
<3c8> DW_AT_declaration : 1
<3><3c8>: Abbrev Number: 28 (DW_TAG_subprogram)
As you can see _Rep (it's a part of std::string) is marked with the DW_AT_declaration attribute, which means _Rep is declared, but not defined. This is the reason why when debugging with gdb if you try print s for the program above you will see No type named std::basic_string<char>::_Rep.
This is how the debug information for _Rep really has to look like:
$ objdump --dwarf=info t.o | grep -P -A4 -B1 '\b_Rep\b'
<3><119>: Abbrev Number: 16 (DW_TAG_structure_type)
<11a> DW_AT_name : (indirect string, offset: 0x578): _Rep
<11e> DW_AT_byte_size : 24
<11f> DW_AT_decl_file : 7
<120> DW_AT_decl_line : 155
<4><121>: Abbrev Number: 11 (DW_TAG_inheritance)
I bet you faced this or similar situation with your clang.

no debugging symbols found when using gdb

GNU gdb Fedora (6.8-37.el5)
Kernal 2.6.18-164.el5
I am trying to debug my application. However, everytime I pass the binary to the gdb it says:
(no debugging symbols found)
Here is the file output of the binary, and as you can see it is not stripped:
vid: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped
I am compiling with the following CFLAGS:
CFLAGS = -Wall -Wextra -ggdb -O0 -Wunreachable-code
Can anyone tell me if I am missing some simple here?
The most frequent cause of "no debugging symbols found" when -g is present is that there is some "stray" -s or -S argument somewhere on the link line.
From man ld:
-s
--strip-all
Omit all symbol information from the output file.
-S
--strip-debug
Omit debugger symbol information (but not all symbols) from the output file.
The application has to be both compiled and linked with -g option. I.e. you need to put -g in both CPPFLAGS and LDFLAGS.
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.
You should also try -ggdb instead of -g if you're compiling for Android!
Replace -ggdb with -g and make sure you aren't stripping the binary with the strip command.
I know this was answered a long time ago, but I've recently spent hours trying to solve a similar problem. The setup is local PC running Debian 8 using Eclipse CDT Neon.2, remote ARM7 board (Olimex) running Debian 7. Tool chain is Linaro 4.9 using gdbserver on the remote board and the Linaro GDB on the local PC. My issue was that the debug session would start and the program would execute, but breakpoints did not work and when manually paused "no source could be found" would result. My compile line options (Linaro gcc) included -ggdb -O0 as many have suggested but still the same problem. Ultimately I tried gdb proper on the remote board and it complained of no symbols. The curious thing was that 'file' reported debug not stripped on the target executable.
I ultimately solved the problem by adding -g to the linker options. I won't claim to fully understand why this helped, but I wanted to pass this on for others just in case it helps. In this case Linux did indeed need -g on the linker options.
Hope the sytem you compiled on and the system you are debugging on have the same architecture. I ran into an issue where debugging symbols of 32 bit binary refused to load up on my 64 bit machine. Switching to a 32 bit system worked for me.
Bazel can strip binaries by default without warning, if that's your build manager. I had to add --strip=never to my bazel build command to get gdb to work, --compilation_mode=dbg may also work.
$ bazel build -s :mithral_wrapped
...
#even with -s option, no '-s' was printed in gcc command
...
$ file bazel-bin/mithral_wrapped.so
../cpp/bazel-bin/mithral_wrapped.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=4528622fb089b579627507876ff14991179a1138, not stripped
$ objdump -h bazel-bin/mithral_wrapped.so | grep debug
$ bazel build -s :mithral_wrapped --strip=never
...
$ file bazel-bin/mithral_wrapped.so
bazel-bin/mithral_wrapped.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=28bd192b145477c2a7d9b058f1e722a29e92a545, not stripped
$ objdump -h bazel-bin/mithral_wrapped.so | grep debug
30 .debug_info 002c8e0e 0000000000000000 0000000000000000 0006b11e 2**0
31 .debug_abbrev 000030f6 0000000000000000 0000000000000000 00333f2c 2**0
32 .debug_loc 0013cfc3 0000000000000000 0000000000000000 00337022 2**0
33 .debug_aranges 00002950 0000000000000000 0000000000000000 00473fe5 2**0
34 .debug_ranges 00011c80 0000000000000000 0000000000000000 00476935 2**0
35 .debug_line 0001e523 0000000000000000 0000000000000000 004885b5 2**0
36 .debug_str 0033dd10 0000000000000000 0000000000000000 004a6ad8 2**0
For those that came here with this question and who are using Qt: in the release config there is a step where the binary is stripped as part of doing the make install. You can pass the configuration option CONFIG+=nostrip to tell it not to:
Instead of:
qmake <your options here, e.g. CONFIG=whatever>
you add CONFIG+=nostrip, so:
qmake <your options here, e.g. CONFIG=whatever> CONFIG+=nostrip
The solutions I've seen so far are good:
must compile with the -g debugging flag to tell the compiler to generate debugging symbols
make sure there is no stray -s in the compiler flags, which strips the output of all symbols.
Just adding on here, since the solution that worked for me wasn't listed anywhere. The order of the compiler flags matters. I was including multiple header files from many locations (-I/usr/local/include -Iutil -I. And I was compiling with all warnings on (-Wall).
The correct recipe for me was:
gcc -I/usr/local/include -Iutil -I -Wall -g -c main.c -o main.o
Notice:
include flags are at the beginning
-Wall is after include flags and before -g
-g is at the end
Any other ordering of the flags would cause no debug symbols to be generated.
I'm using gcc version 11.3.0 on Ubuntu 22.04 on WSL2.

File format not recognized with GNU gdb 6.4 on Solaris 10

Below details are from a session in a Sun machine running Solaris 10.
$ file devli
devli: ELF 32-bit MSB executable SPARC Version 1, dynamically linked, stripped
$ file a
a: ELF 32-bit MSB executable SPARC Version 1, dynamically linked, not stripped
$ gdb
GNU gdb 6.4
Copyright 2005 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "sparc-sun-solaris2.10".
(gdb) file a
Reading symbols from /tmp/tnmy/a...(no debugging symbols found)...done.
(gdb) file devli
"/tmp/tnmy/devli": not in executable format: File format not recognized
(gdb) q
$ ls -l a devlisrvr
-rwxr-xr-x 1 test2 dba 1480 Dec 23 18:23 a
-rwxr-xr-x 1 test2 dba 633088 Dec 23 18:26 devli
$ uname -a ;
SunOS myhost 5.10 Generic_127111-11 sun4v sparc SUNW,SPARC-Enterprise-T5220
$ cat a.c
int main() {return 0;}
$ /opt/SUNONE8/SUNWspro/bin/CC -V
CC: Sun C++ 5.5 2003/03/12
$ file `which gdb`
/usr/local/bin/gdb: ELF 32-bit MSB executable SPARC Version 1, dynamically linked, not stripped
$
Any details on why would not gdb recognize the file format for devli? I searched over the Internet but could not find anything related to this particular issue. Any pointers would be helpful.
a.c goes into a, built using gcc; devli using Sun ONE Studio 8.
Note that GDB 6.4 is 4 years old. You might get better luck with (current) GDB 7.0.
It is also possible that the devli executable is corrupt (file just looks at the first few bytes of the executable, but GDB requires much more of the file contents to be self-consistent). Does readelf --all > /dev/null report any warnings?