Why I can't print out environment variables in gdb?

送分小仙女□ 提交于 2020-01-14 07:32:30

问题


#include <unistd.h>
#include <stdio.h>

extern char **environ;
int main(int argc, char *argv[]) { 
  int i = 0;
  while(environ[i]) {
    printf("%s\n", environ[i++]);
  }
  return 0;
}

Here's my ops:

(gdb) n
8       printf("%s\n", environ[i++]);
(gdb) p environ[i]
Cannot access memory at address 0x0
(gdb) n
LOGNAME=root
7     while(environ[i]) {

As you can see,printf can print out environ[i],but p environ[i] gives me Cannot access memory at address 0x0,why?


回答1:


gdb resolves the wrong environ symbol. I don't know why though. See below as to why.

But you can test it. Change the program to:

#include <unistd.h>
#include <stdio.h>

extern char **environ;
int main(int argc, char *argv[]) {
  int i = 0;
  printf("%p\n", &environ);
  while(environ[i]) {
    printf("%s\n", environ[i++]);
  }
  return 0;
}

Now let's run this in the debugger.

(gdb) n
7         printf("%p\n", &environ);
(gdb) n
0x8049760
8         while(environ[i]) {
(gdb) p &environ
$1 = (char ***) 0x46328da0
(gdb)

So. The actual program has, during its linking, resolved environ to the address 0x8049760. When gdb wants to access the environ symbol, it resolves to 0x46328da0, which is different.

Edit. It seems your environ symbol is actually linked to the environ@@GLIBC_2.0 symbol. In gdb write this:

(gdb) p environ

And hit the tab key (twice), it'll autocomplete the symbols. Which yields:

(gdb) p environ
environ             environ@@GLIBC_2.0

environ@@GLIBC_2.0 is the one actually linked to the extern char **environ

Printing this yields the same address as the program sees, 0x8049760:

(gdb) p &'environ@@GLIBC_2.0'
$9 = ( *) 0x8049760
(gdb) p ((char**)'environ@@GLIBC_2.0')[i]
$10 = 0xbffff6ad "XDG_SESSION_ID=1"

So, at one point glibc deprecated the environ symbol, and added a newer version




回答2:


Environment variables are accessed in C/C++ using the function getenv() defined in stdlib.h. However, using the envp parameter of the main function you can use the following example to iterate over environment variables.

#include <stdio.h>

int main(int argc, char *argv[], char *envp[])
{
  char **next = envp;

  while (*next) 
  {
    printf("%s\n", *next);
    next++;
  }
  return 0;


}

Tested on a Mac




回答3:


Like grundprinzip said, use getenv(sz) and remember to null-check the return value

Alternatively,

#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[], char*[] environ) { 
  int i = 0;
  while(environ[i]) {
    printf("%s\n", environ[i++]);
  }
  return 0;
}



回答4:


Probably the process under debugging is started with

execve(binary, NULL, NULL);

and the extern char **environ gets that 2nd NULL even though there's an environment available.

With a little change, your program works both standalone and under gdb.

/* #include <unistd.h> */           /* no more environ */
#include <stdio.h>

/* extern char **environ; */        /* no more environ */
int main(int argc, char *argv[]) { 
  int i = 0;
  char **ptr = argv + argc + 1;     /* points to environment, in Un*x */
  while(ptr[i]) {
    printf("%s\n", ptr[i++]);
  }
  return 0;
}

Why, and how, that NULL gets converted to the proper value inside gdb I have no idea.




回答5:


There's nothing wrong with your code. I tried it on my machine and it printed the environment as expected. You should not need to use getenv().

Are you running this application from the terminal? If not, you should be. Other means of executing an application might be calling your binary without passing it the environment.

From the terminal what is your output when you run "env"? It should output the same list as your program. It does on my machine.



来源:https://stackoverflow.com/questions/6203455/why-i-cant-print-out-environment-variables-in-gdb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!