This question already has answers here:
Where are GDB symbols coming from?
(2 answers)
Closed 3 years ago.
On Fedora 31, I see that gdb knows the symbols of some system binaries, e.g. main of /usr/bin/true:
$ gdb -ex 'set height 0' -ex 'disas main' -ex q /bin/true
Reading symbols from /bin/true...
Reading symbols from .gnu_debugdata for /usr/bin/true...
(No debugging symbols found in .gnu_debugdata for /usr/bin/true)
Dump of assembler code for function main:
0x0000000000002550 <+0>: endbr64
0x0000000000002554 <+4>: cmp edi,0x2
[..]
But main doesn't show up in objdump -d nor `nm output:
$ objdump -d /usr/bin/true | grep '\<main\>'
$ nm /usr/bin/true | grep main
nm: /usr/bin/true: no symbols
$ nm -D /usr/bin/true | grep '\<main\>'
$
How come? Is gdb able to read the main symbol from some additional symbol table?
When I compile my own binaries with gcc, nm/objdump show the main symbol as expected. Also, when I strip such a binary, gdb can't find the main symbol, as well.
I assume that rpmbuild calls gcc/strip with some special flags that cause the above behavior. What are those?
Is gdb able to read the main symbol from some additional symbol table?
Yes: the one contained in the .gnu_debugdata section. More info here.
gdb also prints: No debugging symbols found in .gnu_debugdata for /usr/bin/true
GDB says: there are no debugging symbols (i.e. ones with file/line info, variable info, etc.). It doesn't say "there are no symbols" (i.e. things you would see in nm output). In fact, symbols are raison d'etre for .gnu_debugdata in the first place.
Related
When debugging my big rust project, I face a problem that gdb set break point at incorrect line number.
When I type command to set break point at line 406
break <absolute-path-of-my-file>/lib.rs:406
it return that break point is created at line 432
Breakpoint 2 at 0x5555570b9395: file <absolute-path-of-my-file>/lib.rs, line 432.
When I check code at line number 406
list <absolute-path-of-my-file>/lib.rs:406
It return
file: "<absolute-path-of-my-file>/lib.rs", line number: 406, symbol: "???"
My question is:
Why did it set break at line 432 when I created break at line 406?
What does symbol: "???" mean in the list command return? Thanks for any help!
PS: Size of binary file (after build without optimization) is 22 GB, larger than my memory (16GB)
#Phùng Hưng Thịnh
When I compile C/C++ program, I used to use following to debug my program.
g++ -g -Wall source.C
g++ -g -Wall source.CPP
g++ -g -Wall source.c
g++ -g -Wall source.cpp
For debugging I never use the following during compilation:
-O0
Also I used to use:
ulimit -c unlimited
to know if program creating any core dump or not?
If we are using dynamic library(.dll/.so/.sl on any platform windows/Linux/AIX/SunOS/HP-UX/OSF1/IRIX/UNIX) and providing break point to a function inside that external library, that may show ??? output.
If you are providing break to a function inside dynamic library the line numbers will provide the line number where you are invoking that external function from external library.
I have given the sample usage of gdb using C C++ program, related compilation options and external dependencies at any operating systems.
I tried following commands at Linux and "CYGWIN_NT" at windows using gdb:
$ gdb
(gdb) !ls -d .
.
(gdb) quit
Hence can you provide the output for:
(gdb) !ls "<absolute-path-of-my-file>/lib.rs"
GNU DEBUGGER(GDB) usage at Rust
Make sure there is a rust-gdb executable
Use rust-gdb to debug rustc executable.
All my previous comments based only on C and C++ programming not at rust-gdb.
Actually I don't have rust/... debugger at my system.
I have only C C++ compiler and debugger here.
Example C Code:
#include <stdio.h>
void fun()
{
printf( "fun\n");
}
int main()
{
fun();
return 0;
}
Example gdb.exe usage:
$ gcc.exe -g -Wall sample.c -o ./a.out
Exampe gdb
$ gdb.exe -q ./a.out
Reading symbols from ./a.out...
(gdb) break fun
Breakpoint 1 at 0x100401088: file sample.c, line 4.
(gdb) run
Starting program: /cygdrive/c/home/murugesan_openssl/a.out
[New Thread 6108.0xc88]
[New Thread 6108.0x2428]
[New Thread 6108.0x12b8]
Thread 1 "a.out" hit Breakpoint 1, fun () at sample.c:4
4 printf( "fun\n");
(gdb) list
1 #include <stdio.h>
2 void fun()
3 {
4 printf( "fun\n");
5 }
6 int main()
7 {
8 fun();
9 return 0;
10 }
(gdb) quit
A debugging session is active.
Inferior 1 [process 6108] will be killed.
Quit anyway? (y or n) y
Example to print code:
$ gdb -q ./a.out
Reading symbols from ./a.out...
(gdb) break fun
Breakpoint 1 at 0x100401088: file sample.c, line 4.
(gdb) list sample.c:4
1 #include <stdio.h>
2 void fun()
3 {
4 printf( "fun\n");
5 }
6 int main()
7 {
8 fun();
9 return 0;
10 }
(gdb) quit
I have the following assembly file test which I want to debug,
How can I do that?
Note I am working with x86-64 and att syntax, plus I don't have access to c code.
I want to stop after each line and being able to see the registers in a table (I remember there is such an option).
I tried:
gdb test
r
but I get:
Starting program:
No executable file specified.
Use the "file" or "exec-file" command.
After running GDB on the executable1:
Use start or starti to set a breakpoint in main or _start respectively and run the program.
Or set breakpoints yourself with b 12 to set a breakpoint on source line 12 (if you built with enough debug info for this to work), or b *0x00401007 to set a breakpoint on an address you copy/pasted from disas output.
layout asm / layout reg puts GDB into text-UI mode with "windows" in your terminal for disassembly and registers. (This can be a bit flaky, you sometimes need control-L to redraw the screen, and sometimes GDB crashes when your process exits although I'm not sure if that's specifically from TUI.)
Otherwise without TUI mode, info reg and disas can be useful.
See the bottom of https://stackoverflow.com/tags/x86/info for more asm debugging tips.
Especially strace ./test is highly useful to see the system calls your program makes, decoded into C style. In toy programs you're playing with for your own experimentation, this basically works as an alternative to checking for error return values.
Footnote 1: You're not doing that part correctly:
No executable file specified.
That means no file called test existed in the directory where you ran gdb test.
You have to assemble + link test.S into an executable called test before you can run GDB on that file. If ls -l test shows it, then gdb test can debug it. (And ./test can run it.)
Often gcc -no-pie foo.S is a good choice to make debugging easier: addresses will be fixed at link time, so objdump -drwC -Mintel test output will match the addresses you see at run-time. And the addresses will be numerically smaller, so it's easier to visually spot a code (.text) address vs. .rodata (modern ld puts it in a separate page so it can avoid exec permission) vs. .data / .bss.
Either way, stack addresses are still easy to distinguish from code either way, 0x555... or 0x0000...XXXXXX is in the executable, 0x7fffff... is in the stack, other addresses from mmap are randomized. (But libc also gets mapped to a high address near the stack, with or without PIE.)
(Or if you're writing _start instead of main, gcc -nostdlib -static foo.S implies -no-pie)
I am trying to follow the exercise in the book PC Assembly by Paul Carter. http://pacman128.github.io/pcasm/
I'm trying to run the program from 1.4 page 23 on Ubuntu 18. The files are all available on the github site above.
Since original code is for 32bit I compile using
nasm -f elf32
for first.asm and asm_io.asm to get the object files. I also compile driver.c
I use the linker from gcc and run
gcc -m32 -o first first.o asm_io.o driver.o
but it keeps giving me a bun of errors like
undefined reference to '_scanf'
undefined reference to '_printf'
(note _printf appears instead of printf because some conversion is done in the file asm_io.asm to maintain compatibility between windows and linux OS's)
I don't know why these errors are appearing. I also try running using linker directly
ld -m elf_i386 -e main -o first -first.o driver.o asm_io.o -I /lib/i386-linux-gnu/ld-linux.so.2
and many variations since it seems that its not linking with the C libraries.
Any help? Stuck on this for a while and couldn't find a solution on similar questions
Linux doesn't prepend _ to names when mapping from C to asm symbol names in ELF object files1.
So call printf, not _printf, because there is no _printf in libc.
Whatever "compatibility" code did that is doing it wrong. Only Windows and OS X use _printf, Linux uses printf.
So either you've misconfigured something or defined the wrong setting, or it requires updating / porting to Linux.
Footnote 1: In ancient history (like over 20 years ago), Linux with the a.out file format did use leading underscores on symbol names.
Update: the library uses the NASM preprocessor to %define _scanf scanf and so on, but it requires you to manually define ELF_TYPE by assembling with nasm -d ELF_TYPE.
They could have detected ELF32 or ELF64 output formats on their own, because NASM pre-defines __OUTPUT_FORMAT__. Someone should submit a pull-request to make this detection automatic with code something like this:
%ifidn __OUTPUT_FORMAT__, elf32
%define ELF_TYPE 32
%elifidn __OUTPUT_FORMAT__, elf64
%define ELF_TYPE 64
%endif
%ifdef ELF_TYPE
...
%endif
I am disassembling a very simple ELF program (Linux x86).
With IDA PRO software I see stdout and stderr in .bss-section.
And I haven't found anything that sets the values of stdout or stderr.
How does it work?
Сan stdout and stderr be null?
So you mean stdout and stderr should always be at the same memory address in .bss
The offset from start of .bss to stdout and stderr is determined at static link time.
The address of start of .bss is subject to ASLR (heap placement randomization). Thus, for a given binary, the address of stdout may change from run to run.
how IDA pro knows this item in .bss is stdout or stderr
The only way it can know is via the symbol table. You should see it in output from:
readelf -Ws ./a.out | egrep 'stdout|stderr'
nm ./a.out | egrep 'stdout|stderr'
nm -D ./a.out | egrep 'stdout|stderr'
Update:
but what happens if symbol table is stripped
There are two cases to consider: fully-static link, and dynamic link.
In the fully-static case, all references to stderr can be completely removed, and IDA pro will not know where stderr is.
In the dynamically-linked case, there are two symbol tables: the "regular" one (displayed by nm) and the dynamic one (displayed by nm -D). Strip will remove only the regular symbol table (because removing dynamic symbol table makes no sense -- the executable will not run without it). IDA pro can then use the dynamic symbol table entry for stderr to tell where that symbol is.
I want to debug a process running on Linux 2.6 using GDB. attach PID (where PID is the process ID), print main, print sin, print gzopen and print dlopen work (i.e. they find the respective symbols). But print myfoo doesn't work, where myfoo is a function loaded by the process from an .so file using dlopen. Here is what I get:
(gdb) print main
$3 = {int (int, char **)} 0x805ba90 <main>
(gdb) print sin
$4 = {<text variable, no debug info>} 0xb7701230 <sin>
(gdb) print gzopen
$5 = {<text variable, no debug info>} 0xb720df50 <gzopen>
(gdb) print dlopen
$6 = {<text variable, no debug info>} 0xb77248e0 <__dlopen_nocheck>
(gdb) print myfoo
No symbol "myfoo" in current context.
How do I get GDB to find myfoo?
The function myfoo does indeed exist, because in the program I managed to get its address using dlsym (after dlopen), and I managed to call it. Only after that I attached GDB to the process.
It turned out that there was a mydir/mylib.so: No such file or directory error message printed by the attach $PID command of GDB. Apparently GDB was started in the wrong directory. Doing the proper cd before starting GDB fixed the problem, and print myfoo started working.
I'd like to automate this: I want GDB figure out where my .so files (loaded with dlopen) are. An approximation I can think of is examining /proc/$PID/maps (on Linux), finding possible directories, and adding all of them to the GDB library search path before starting GDB. Extending LD_LIBRARY_PATH and doing a set solib-search-path /tmp/parent didn't work (ls -l /tmp/parent/mydir/myfoo.so does work), GDB still reported the No such file or directory. How do I tell GDB where to look for mydir/myfoo.so?
My other question is how do I get the list of possible directories? On Linux, /proc/$PID/maps contains them -- but what about other operating systems like FreeBSD and the Mac OS X?
"info target" command in gdb will show a list of all sections in all loaded shared objects (including dlopen()ed libraries). At least this works on Linux -- I don't know how it behaves on other operating systems.
I maintain a program that loads a shared library via dlopen() and have successfully accessed symbols in the shared library using GDB. This will only work, however, if the shared library has a symbol table.
It looks like there is no easy way to automate finding finding .so files in GDB.