【问题标题】:Why I can't print out environment variables in gdb?为什么我不能在 gdb 中打印出环境变量?
【发布时间】:2011-09-06 09:40:28
【问题描述】:
#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;
}

这是我的操作:

(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]) {

如你所见,printf 可以打印出environ[i],但是p environ[i] 给了我Cannot access memory at address 0x0,为什么?

【问题讨论】:

  • 奇怪。我重现。如果我在 while 循环之前添加 ptr = environ,我可以使用 ptrenviron 保持空指针。
  • 显然gdb在没有环境的情况下启动了被调试程序的进程。
  • @pmg,它有一个环境。我经常在 gdb 中使用 set env 来确定这一点。

标签: c linux gdb environment-variables


【解决方案1】:

gdb 解析了错误的environ 符号。 我不知道为什么。请看下文。

但你可以测试它。将程序更改为:

#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;
}

现在让我们在调试器中运行它。

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

所以。实际程序在其链接期间已将environ 解析为地址0x8049760。 当gdb要访问environ符号时,它解析为0x46328da0,这是不同的。

编辑。 看来您的 environ 符号实际上链接到 environ@@GLIBC_2.0 符号。 在 gdb 中这样写:

(gdb) p 环境

然后按 Tab 键(两次),它会自动完成符号。产生:

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

environ@@GLIBC_2.0 是实际链接到extern char **environ 的那个

打印这个会产生与程序看到的地址相同的地址,0x8049760:

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

因此,glibc 曾一度弃用 environ 符号,并添加了更新版本

【讨论】:

  • 这是否解释了为什么environprintfp 中不同?
  • @nos 我遇到了一个相反的情况,gdb 打印环境完美,但共享库中的程序不能(得到 0x00 指针),有什么想法吗?
【解决方案2】:

在 C/C++ 中使用 stdlib.h 中定义的函数 getenv() 访问环境变量。但是,使用 main 函数的 envp 参数,您可以使用以下示例来迭代环境变量。

#include <stdio.h>

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

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


}

在 Mac 上测试

【讨论】:

  • GDB 可以调用函数。例如:call (char*) getenv("PATH")(似乎假设返回是一个没有类型转换的整数。)当然,该函数必须可用,但如果程序关心环境变量,那么它肯定必须可用!
  • 这不是问题,并非所有平台都直接支持 _environ / environ 变量。
  • 我的意思是,通常有一种方法可以查看环境变量,而根本不关心 environ_environ 是否存在。
【解决方案3】:

就像 grundprinzip 说的那样,使用 getenv(sz) 并记住对返回值进行空检查

或者,

#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】:

    大概是被调试的进程启动于

    execve(binary, NULL, NULL);
    

    即使有可用的环境,extern char **environ 也会获得第二个 NULL

    稍作改动,您的程序既可以独立运行,也可以在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;
    }
    

    为什么以及如何将NULL 转换为gdb 中的正确值我不知道。

    【讨论】:

      【解决方案5】:

      您的代码没有问题。我在我的机器上试了一下,它按预期打印了环境。您应该不需要使用 getenv()。

      您是否从终端运行此应用程序?如果不是,你应该是。执行应用程序的其他方法可能是调用您的二进制文件而不将其传递给环境。

      从终端运行“env”时,您的输出是什么?它应该输出与您的程序相同的列表。在我的机器上可以。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-03
        • 1970-01-01
        • 1970-01-01
        • 2013-02-06
        • 1970-01-01
        相关资源
        最近更新 更多