Shell – GDB cannot exec the test program

execgdbshell

My computer run with Ubuntu 14.04. GDB seems to be abnormal in different account. For example I make a very simple test. I write a file under ~/test/test.c like this:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    printf("hello,world");
    return 0;
}

and build with command "gcc -g test.c -o test", then I get result file named test.
Next step, run gdb to debug. Notice that current account is user of my own.

$gdb test
(gdb)l      //work well
(gdb) b 6   //work well
(gdb) r     //error: Cannot exec /home/xxx/test/test -c exec /home/xxx/test/test .
            //Error: No such file or directory

But if I change to root account by command "su", gdb works well.
Why?

Best Answer

It appears that your SHELL variable is set to a file that doesn't exist. Try the following:

export SHELL=/bin/sh
gdb test

ensuring that /bin/sh exists and is executable. This works via su not because of root permissions, but because su resets the SHELL environment variable. Per the su manual page:

Note that the default behavior for the environment is the following:

The $HOME, $SHELL, $USER, $LOGNAME, $PATH, and $IFS environment variables are reset.

Further Discussion

If you are asking yourself, "How was I supposed to know that from the following error message?":

//error: Cannot exec /home/xxx/test/test -c exec /home/xxx/test/test .
//Error: No such file or directory

You are not alone. This appears to be poor error reporting from gdb. When gdb decides that it needs to execute your command using a shell, it constructs a command in the following format:

/path/to/shell -c exec /path/to/executable

However, when it prints the error message, it does this:

  save_errno = errno;
  fprintf_unfiltered (gdb_stderr, "Cannot exec %s", exec_file);
  for (i = 1; argv[i] != NULL; i++)
    fprintf_unfiltered (gdb_stderr, " %s", argv[i]);
  fprintf_unfiltered (gdb_stderr, ".\n");
  fprintf_unfiltered (gdb_stderr, "Error: %s\n",
                      safe_strerror (save_errno));
  gdb_flush (gdb_stderr);

Here exec_file is the expanded path of the file you passed on the command line. It prints exec_file first, followed by the elements of argv, starting at the 1st index. argv contains the arguments it passed to execvp.

Unfortunately, the shell it is trying to use is in the 0th element of argv, which never gets printed. Thus, you never see the file that execvp couldn't find.

Further, it then prints a trailing . which isn't actually one of the arguments that it passed to execvp and is presumably there to make the message a completely sentence.

Finally, it prints the error we got back from our call to execvp, which is that the executable file could not be found.

This bug likely is caused by the fact that this error handling code is the same for the case where gdb attempts to exec the command directly and for the case when it uses the shell. In the former case, the constructed error message would look correct since exec_file and argv[0] would be the same.

Related Question