1

Need to extract a few values from an auxiliary vector. You can read more about it here. That's where I got and slightly modified code below:

#include <stdio.h>
#include <elf.h>

int main(int argc, char* argv[], char* envp[])
{
    Elf64_auxv_t *auxv;
    while (*envp++ != NULL); /* from stack diagram above: *envp = NULL marks end of envp */

    for (auxv = (Elf64_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++)
        /* auxv->a_type = AT_NULL marks the end of auxv */
    {
        if (AT_EXECFN == auxv->a_type)
        {
            char *str = (char *)auxv->a_un.a_val;
            printf("%s\n", str);
            break;
        }
    }
    return 0;
}

I compile the code with gcc -g aux-extractor.c.

Here is the weird part. If I run the code as ./a.out I get and output as ./a.out which makes sense. However when I debug it in gdb and print the value at a specific address I get /tmp/a.out, which also makes sense I compiled my code in /tmp directory. My question is why I'm getting two different results, a.out and /tmp/a.out?

Here is my debugging session (pay attention to the output of the x/s command:

$ gdb ./a.out
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details. 
This GDB was configured as "x86_64-linux-gnu". T
ype "show configuration" for configuration details. 
For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...
(gdb) start
Temporary breakpoint 1 at 0x1149: file auxv-extractor.c, line 5.
Starting program: /tmp/a.out

Temporary breakpoint 1, main (argc=21845, argv=0x0, envp=0x5555555551c0 <__libc_csu_init>) at auxv-extractor.c:5
5       {
(gdb) break 15
Breakpoint 2 at 0x555555555198: file auxv-extractor.c, line 15.
(gdb) c
Continuing.

Breakpoint 2, main (argc=1, argv=0x7fffffffe408, envp=0x7fffffffe520) at auxv-extractor.c:15
15                  printf("%s\n", str);
(gdb) x/s str
0x7fffffffefed: "/tmp/a.out"
(gdb)
flashburn
  • 4,180
  • 7
  • 54
  • 109
  • 1
    Did you read the [documentation of GCC](https://gcc.gnu.org/onlinedocs/gcc/) ? You could use [readelf(1)](https://man7.org/linux/man-pages/man1/readelf.1.html) (and study its source code, since it is opensource) – Basile Starynkevitch May 14 '21 at 04:35
  • @BasileStarynkevitch that's not really my question. I know about various tools, I'm asking why there is a difference. – flashburn May 14 '21 at 04:39
  • You could also use [strace(1)](https://man7.org/linux/man-pages/man1/strace.1.html) and [pwd(1)](https://man7.org/linux/man-pages/man1/pwd.1.html) – Basile Starynkevitch May 14 '21 at 04:40
  • 1
    The documentation you link to does not mention `EXECFN`. Where did you find it? Is that a link to the correct version of the documentation? – Eric Postpischil May 14 '21 at 05:29
  • This is the key: `Starting program: /tmp/a.out` -- GDB doesn't start your program the same way `$SHELL` does. – Employed Russian May 15 '21 at 03:39

2 Answers2

2

When gdb runs your program, it does so by executing /tmp/a.out, having expanded the path from the ./a.out on the command line.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • GDB does _do_ that. It's a problem when debugging programs which look at `argv[0]` and e.g. try to find their own location -- they don't get the same `argv[0]` under GDB. – Employed Russian May 15 '21 at 03:37
0

GDB has a habit of starting the program with $(realpath ./a.out) when ./a.out is given on the command line.

I've tried to set exec-wrapper as a way to avoid this, but was not successful -- even when setting exec-wrapper wrapper.sh with this contents:

#!/bin/bash
exec -a "./a.out" "$@"

the AT_EXECFN remains /tmp/a.out.

This answer shows how to pause the program after main() to make it easy to attach GDB from "outside". AT_EXECFN will be set to ./a.out as expected, and you can continue debugging as you normally would.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362