Why gdb doesn't break when I use exec-wrapper script to exec my target binary.
Here my little test.
I use a binary with no pie option to use predictable address.
$ gcc -no-pie main.c
I have this litle gdb exec wrapper script.
$ cat wrapper.sh
#!/bin/bash
env -i ./a.out
Then I debug my program like this, by setting the exec-wrapper variable and a debug breakpoint at *main, the breakpoint doesn't work:
$ gdb -q ./a.out
Reading symbols from ./a.out...(no debugging symbols found)...done.
(gdb) b *main
Breakpoint 1 at 0x401126
(gdb) set exec-wrapper ./wrapper.sh
(gdb) r
Starting program: /home/snake/gdb-test/a.out
boum !
During startup program exited normally.
(gdb)
Here the same example without exec-wrapper variable set and a debug breakpoint at *main, the breakpoint works:
$ gdb -q ./a.out
Reading symbols from ./a.out...(no debugging symbols found)...done.
(gdb) b *main
Breakpoint 1 at 0x401126
(gdb) r
Starting program: /home/snake/gdb-test/a.out
Breakpoint 1, 0x0000000000401126 in main ()
(gdb)
Why in the first case the breakpoint not work?
Maybe gdb is not attached to the process run by my exec wrapper script.
Thank's for your help.
UPDATE:
Thank's @ws, your reminder and point of view is interesting.
I use env -i
in order to start the program in an empty environment in order to have a predictable stack in a non randomized address space, in/out of gdb and in any path. But GDB lack of options to configure the binary name with a relative path to pass to argv[0] and other variables pushed on the stack will cause a stack offset according the directory location the execution context.
So I have build this little wrapper to overcome the problem. Maybe dirty, but work well.
#include <unistd.h>
int main()
{
int e;
char *envp[] = { NULL };
char *argv[] = { "./a.out", NULL };
e = execve("./a.out", argv, envp);
}
then
$ gcc exec_wrapper.c -o exec_wrapper
and finaly
$ gdb -q ./a.out
Reading symbols from ./a.out...(no debugging symbols found)...done.
(gdb) set exec-wrapper ./exec_wrapper
(gdb) b *main
Breakpoint 1 at 0x1149
(gdb) r
Starting program: /home/snake/gdb-test/a.out
Breakpoint 1, 0x0000555555555149 in main ()
(gdb)
So I don't understand your answer very well @ws, my executable name is directly encoded in the binary, and it works well. If I understand the behavior of gdb, normally GDB monitors for the first process trap execve() start by the shell to follow it. In the case of exec-wrapper is configure, it follow the second execve(). (thank's to a friend for show me this behavior).
gdb/nat/fork-inferior.h
/* Number of traps that happen between exec'ing the shell to run an
inferior and when we finally get to the inferior code, not counting
the exec for the shell. This is 1 on all supported
implementations. */
#define START_INFERIOR_TRAPS_EXPECTED 1
gdb/nat/fork-inferior.c
/* The process was started by the fork that created it, but it will
have stopped one instruction after execing the shell. Here we
must get it up to actual execution of the real program. */
if (get_exec_wrapper () != NULL)
pending_execs++;
Maybe I doesn't understand your answer @ws. sorry. you meant to say that gdb performs string comparison of the binary name with full path with the argv[0] of the execve() call?