There are many questions related to specific errors why stepping into a shared library with gdb isn't working. None of them provide a systematic answer on how to confirm where the the cause is. This questions is about the ways to diagnose the setup.
Setup example
main.c
#include <stdio.h>
#include "myshared.h"
int main(void)
{
int a = 3;
print_from_lib();
return 0;
}
myshared.h
void print_from_lib();
myshared.c
#include <stdio.h>
void print_from_lib()
{
printf("Printed from shared library\n");
}
Place all the files in the same directory.
export LIBRARY_PATH=$PWD:$LIBRARY_PATH
export LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH
gcc -ggdb -c -Wall -Werror -fpic myshared.c -o myshared-ggdb.o
gcc -ggdb -shared -o libmyshared-ggdb.so myshared-ggdb.o
gcc -ggdb main.c -lmyshared-ggdb -o app-ggdb
Getting the error
$ gdb ./app-ggdb
GNU gdb (Ubuntu 7.12.50.20170314-0ubuntu1) 7.12.50.20170314-git
...### GDB STARTING TEXT
Reading symbols from app-ggdb...done.
(gdb) break 7
Breakpoint 1 at 0x78f: file main.c, line 7.
(gdb) run
Starting program: /home/user/share-lib-example/app-ggdb
Breakpoint 1, main () at main.c:7
7 print_from_lib();
(gdb) s
Printed from shared library
8 return 0;
gdb is not stepping inside of the function
Necessary but not sufficient checks
Debug symbols in the binaries
$ objdump --syms libmyshared-ggdb.so | grep debug
0000000000000000 l d .debug_aranges 0000000000000000 .debug_aranges
0000000000000000 l d .debug_info 0000000000000000 .debug_info
0000000000000000 l d .debug_abbrev 0000000000000000 .debug_abbrev
0000000000000000 l d .debug_line 0000000000000000 .debug_line
0000000000000000 l d .debug_str 0000000000000000 .debug_str
Symbols recognized by gdb
$ gdb ./app-ggdb
...### GDB STARTING TEXT
Reading symbols from app-ggdb...done.
(gdb) break 7
Breakpoint 1 at 0x78f: file main.c, line 7.
(gdb) run
Starting program: /home/user/share-lib-example/app-ggdb
Breakpoint 1, main () at main.c:7
7 print_from_lib();
(gdb)(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x00007ffff7dd7aa0 0x00007ffff7df55c0 Yes /lib64/ld-linux-x86-64.so.2
0x00007ffff7bd5580 0x00007ffff7bd5693 Yes /home/user/share-lib-example/libmyshared-ggdb.so
0x00007ffff782d9c0 0x00007ffff797ed43 Yes /lib/x86_64-linux-gnu/libc.so.6
Confirm .gdbinit isn't the cause
~/.gdbinit contains commands automatically executed upon starting gdb. ref.
Running gdb with the -nx flags can exclude .gdbinit as the source of the problem.
Question
Am looking for suggestions to complete the list of Necessary but not sufficient checks.
Current issue [Update from Mark Plotnick]
This step bug is reproducible on Ubuntu 17.04 amd64 with both a 64- and 32-bit executable and library.
The bug isn't reproducible on Ubuntu 17.04 i386. (gcc 6.3.0-12ubuntu2, gdb 7.12.50 and 8.0, no .gdbinit.).
Possibly relevant: gcc on 17.04 amd64 has been built (by Canonical) to generate pie executables by default.
Question
Can flags with which gcc was build with interfere with debugging? How can you identify if your gcc is the cause?
Your problem is self-imposed: don't do this: set step-mode on, and step will work as you expect.
From the GDB manual:
set step-mode
set step-mode on
The set step-mode on command causes the step command to stop at the first
instruction of a function which contains no debug line information
rather than stepping over it.
This is useful in cases where you may be interested in inspecting the machine
instructions of a function which has no symbolic info and do not want
GDB to automatically skip over this function.
You are interested in the opposite of the above -- you want to step into the print_from_lib function and avoid stopping inside the PLT jump stub and the dynamic loader's symbol resolution function.
GDB 7.11 can't reproduce this problem.
This is my steps. I hope this will help you:
1.gcc -ggdb -c -Wall -Werror -fpic myshared.c -o myshared-ggdb.o
2.gcc -ggdb -shared -o libmyshared-ggdb.so myshared-ggdb.o
3.gcc -ggdb main.c -lmyshared-ggdb -o app-ggdb -L.
4.gdb ./app-ggdb
In GDB,
(gdb) set env LD_LIBRARY_PATH=.
(gdb) b main.c:7
Breakpoint 1 at 0x4006a5: file main.c, line 7.
(gdb) r
Starting program: /home/haolee/tmp/app-ggdb
Breakpoint 1, main () at main.c:7
7 print_from_lib();
(gdb) s
print_from_lib () at myshared.c:5
5 printf("Printed from shared library\n");
(gdb)
I step into the function print_from_lib successfully.
Some more tests you can do on built shared library:
file libmyshared-ggdb.so should report that library has debug info and not stripped.
nm libmyshared-ggdb.so | grep print_from_lib should find the symbol for print_from_lib function.
If all above tests passed try to load the library directly in gdb and find the function:
gdb libmyshared-ggdb.so
(gdb) info functions print_from_lib
Function print_from_lib name should be printed. If not, something is wrong with gdb or gcc.
Related
Here is my program:
#include <stdio.h>
int main(void) {
printf("Hello world\n");
return 0;
}
That's how I compile it
aarch64-linux-gnu-gcc -O0 -g3 main.c
I started the a.out like this:
qemu-aarch64-static -L /usr/aarch64-linux-gnu -singlestep -g 1234 ./a.out
And then I started gdb
$ gdb-multiarch -q ./a.out
Reading symbols from ./a.out...done.
(gdb) set sysroot /usr/aarch64-linux-gnu/
(gdb) target remote :1234
Remote debugging using :1234
Reading symbols from /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1...(no debugging symbols found)...done.
0x0000004000814040 in ?? ()
from /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1
(gdb) break main
Breakpoint 1 at 0x76c: file main.c, line 4.
(gdb) c
Continuing.
[Inferior 1 (Remote target) exited normally]
My question: why gdb didn't stop on main entrance and program just finished without any break? What am I do wrong?
I've repeated these steps on Ubuntu 20.04 and everything works fine. To be fair, I use ubuntu for a long time and could just forget what I did before, but Debian is fresh.
Versions info:
OS: Debian GNU/Linux 10 (buster)
QEMU: qemu-aarch64 version 3.1.0 (Debian 1:3.1+dfsg-8+deb10u8)
GDB: GNU gdb (Debian 8.2.1-2+b3) 8.2.1
GCC: aarch64-linux-gnu-gcc (Debian 8.3.0-2) 8.3.0
I am trying to compile binaries with heap vulnerabilities to practice binary exploitation. To do so, I need an old version of the libc so that doesn't have all the security checks the modern ones do.
I have on my computer a glibc-2.3.2.so file and a ld-2.3.2.so file. I made a small test program -
7 int main()
8 {
9 char * first, *second;
10 first = malloc(0x40);
11 read(0,first,0x40);
12 free(first);
13 second = malloc(0x40);
14 ((void (*)())second)();
15
16 }
(The only thing not included are #include <stdlib.h> and #include <unistd.h>)
I turned the c file into a .o file with the command
gcc -c firstFit.c -m32
Then, I used g++ for the linking, specifying the old glibc.
g++ firstFit.o -o firstFit -Wl,--rpath=`pwd` -Wl,--dynamic-linker=`pwd`/ld-2.3.2.so -m32
It compiles just fine. However, when I try to run the file there is a floating point exception.
[1] 169605 floating point exception (core dumped) ./firstFit
I ran it under gdb to see where and
→ 0xf7fe9572 div DWORD PTR [ecx+0x164]
Using the gdb backtrace command
#0 0xf7fe9572 in ?? () from /home/zac/programming/cybersec/ctfPrepChalls/heap/ld-2.3.2.so
#1 0xf7ff6abd in ?? () from /home/zac/programming/cybersec/ctfPrepChalls/heap/ld-2.3.2.so
#2 0xf7fe8f13 in ?? () from /home/zac/programming/cybersec/ctfPrepChalls/heap/ld-2.3.2.so
#3 0xf7fe8c27 in ?? () from /home/zac/programming/cybersec/ctfPrepChalls/heap/ld-2.3.2.so
Why would ld be have a floating point error? How would I go about fixing this?
Help is appreciated
Then, I used g++ for the linking, specifying the old glibc.
g++ firstFit.o -o firstFit -Wl,--rpath=pwd -Wl,--dynamic-linker=pwd/ld-2.3.2.so -m32
One of the following two reasons very likely explains your crash:
You do not have complete installation of GLIBC-2.3.2 in your current directory.
In particular, g++ will link against libm.so.6, and if you end up using system libm.so.6 with $(pwd)/libc.so.6, you are very likely to have trouble (mixing bits of GLIBC which came from different builds is a no-no).
You link against system libstdc++.so.6, which has DT_GNU_HASH and no DT_HASH.
GLIBC-2.3.2 is old enough not to support GNU_HASH.
I expect the issue#2 is most likely explanation for SIGFPE.
You can confirm either of these by running
env LD_TRACE_LOADED_OBJECTS=1 ./firstFit
to find loaded objects (do not use ldd, it will lie to you), and looking at the output from:
readelf -d ./firstFit | grep HASH
readelf -d /path/to/libstdc++.so.6 | grep HASH
so, here is the program that only returns 0:
int main( void )
{
return 0;
}
compiling the program
gcc -ggdb3 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled1.c" -o "untitled1.o"
Compilation finished successfully.
linking the program (using gcc, not g++)
gcc -ggdb3 -o "untitled1" "untitled1.o"
Compilation finished successfully.
running the program:
./untitled1
(nothing output)
Suggest: don't mix gcc and g++ for the same program
I have a C executable and would like to know if the executable has any information stored in it about which file(s) it was compiled from and, if so, how to access that information? I am using RedHat Linux 6.
If your program has been compiled with debugging information, then yes, it's possible.
For example, I compiled test.c with gcc -ggdb3 test.c -o test
Then, with gdb ./test:
(gdb) info functions
All defined functions:
File main.c:
int main(int, char **);
Non-debugging symbols:
0x0000000000400370 _init
0x00000000004003a0 __libc_start_main#plt
0x00000000004003b0 __gmon_start__#plt
0x00000000004003c0 _start
0x00000000004003f0 deregister_tm_clones
0x0000000000400420 register_tm_clones
0x0000000000400460 __do_global_dtors_aux
0x0000000000400480 frame_dummy
0x00000000004004d0 __libc_csu_init
0x0000000000400540 __libc_csu_fini
0x0000000000400544 _fini
(gdb) info sources
Source files for which symbols have been read in:
/home/john/Projects/test/main.c, /usr/include/bits/sys_errlist.h, ...
Source files for which symbols will be read in on demand:
It entirely depends on the architecture, and whether the executable was compiled in debug mode (or similar).
For example, UNIX systems embed debug information (including file names) in the executable itself, whereas Windows stores the info in a separate file (i.e. myprog.exe has a corresponding myprog.pdb with all the debug info).
I have a program invoking function foo that is defined in a library. How can I know where the library is in the file system? (like is it a static library or a dynamically linked lib?)
Update: with using ldd, the program has a lot of dependency library. How to tell which lib contains function foo?
You didn't say which OS you are on, and the answer is system-dependent.
On Linux and most UNIX systems, you can simply ask the linker to tell you. For example, suppose you wanted to know where printf is coming from into this program:
#include <stdio.h>
int main()
{
return printf("Hello\n");
}
$ gcc -c t.c
$ gcc t.o -Wl,-y,printf
t.o: reference to printf
/lib/libc.so.6: definition of printf
This tells you that printf is referenced in t.o and defined in libc.so.6. Above solution will work for both static and shared libraries.
Since you tagged this question with gdb, here is what you can do in gdb:
gdb -q ./a.out
Reading symbols from /tmp/a.out...done.
(gdb) b main
Breakpoint 1 at 0x400528
(gdb) run
Breakpoint 1, 0x0000000000400528 in main ()
(gdb) info symbol &printf
printf in section .text of /lib/libc.so.6
If foo comes from a shared library, gdb will tell you which one. If it comes from a static library (in which case gdb will say in section .text of a.out), use the -Wl,-y,foo solution above. You could also do a "brute force" solution like this:
find / -name '*.a' -print0 | xargs -0 nm -A | grep ' foo$'
For shared libs try using ldd command line tool.
For static libs the library is in the program itself - there are no external dependencies, which is the whole point of using static libs.
You cannot list static libraries in the final binary. To list the linked dynamic libraries, use the commands: On Linux, use ldd [file]. On Mac OS X, use otool -L [file]. On Windows, I have no idea ;-)
I'm using GCC 4.4.1 and GDB 7.0-ubuntu on Ubuntu 9.10 (Karmic Koala). However, GCC won't generate debugger information when using any of the following switches: -g, -g3, -ggdb, or -ggdb3.
So when I run the program with GDB, it’s as if there wasn’t any debugger information generated. I have created very simple test source files in a new, empty folder.
Here is one example:
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char **argv)
{
char msg[4];
// Allocate 4 bytes on the stack
strcpy (msg, "Hello, World!");
// Overflow
printf ("%s\n", msg);
return 0;
}
Here is my command line sequence:
gcc -g ./mytest.c -o mytest
gdb ./mytest
I have previously turned on MALLOC_CHECK_=1 in order to test the stack overflow problem in the code. And this works, so I get a stack trace. But the stack trace is no different whether I include the debug information or not. With the debugger information, I expected to see a line number of a file for where the problem occurred under GDB. However, this doesn't happen.
It works fine. I ran the debugger on my computer. I had to add
#include <string.h>
to compile it though. I called the file debugger.c. Here are the steps:
gcc -g debugger.c
gdb a.out
which will start the debugger
GNU gdb 6.3.50-20050815
...
...
(gdb) run
Starting program: /Developer/stackoverflow/extern/a.out
Reading symbols for shared libraries +. done
Program received signal SIGABRT, Aborted.
0x00007fff88040886 in __kill ()
(gdb) backtrace
#0 0x00007fff88040886 in __kill ()
#1 0x00007fff880e0e4f in __abort ()
#2 0x00007fff880d5693 in __chk_fail ()
#3 0x00007fff8802f851 in __strcpy_chk ()
#4 0x0000000100000f04 in main (argc=1, argv=0x7fff5fbff958) at debugger.c:9
(gdb)
But it seems like your problem isn't running the debugger, but getting the information where your code failed. You can use backtrace to achieve that.
You want:
gcc -g test.c -o mytest
gdb mytest
Never call anything "test" - it clashes with a shell built in. and "test.o" would by convention be the name of an object file, not an executable.
Your comment says you ran:
gcc -ggdb ./test.c -o test.o
That's probably not what you want.
gcc -ggdb -o mytest test.c
is likelier to be successful. If gdb ralphs on that then you have something wrong with your installation of gcc or gdb.