Почему я не могу распечатать переменные окружения в GDB? - PullRequest
8 голосов
/ 01 июня 2011
#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, почему?

Ответы [ 5 ]

9 голосов
/ 01 июня 2011

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         while(environ[i]) {
(gdb) p &environ
$1 = (char ***) 0x46328da0
(gdb)

Итак.Фактическая программа во время связывания разрешает environ по адресу 0x8049760.Когда GDB хочет получить доступ к символу environ, он разрешается в 0x46328da0, что отличается.

Редактировать.Кажется, ваш символ environ действительно связан с символом environ@@GLIBC_2.0.В gdb напишите это:

(gdb) p environ

и нажмите клавишу табуляции (дважды), она автоматически завершит символы.Который дает:

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

environ@@GLIBC_2.0 - это тот, который на самом деле связан с extern char **environ

. При печати это дает тот же адрес, который видит программа, 0x8049760:

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

Итак, в какой-то момент glibc устарел символ environ и добавил более новую версию

0 голосов
/ 01 июня 2011

Возможно, процесс отладки запускается с

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 Понятия не имею.

0 голосов
/ 01 июня 2011

В вашем коде нет ничего плохого. Я попробовал это на своей машине, и это напечатало окружающую среду как ожидалось. Вам не нужно использовать getenv ().

Запускаете ли вы это приложение из терминала? Если нет, вы должны быть. Другим средством выполнения приложения может быть вызов вашего двоичного файла без передачи его в среду.

Из терминала, что вы выводите, когда запускаете "env"? Он должен вывести тот же список, что и ваша программа. Это на моей машине.

0 голосов
/ 01 июня 2011

Как сказал 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;
}
0 голосов
/ 01 июня 2011

Переменные среды доступны в C / C ++ с помощью функции getenv(), определенной в stdlib.h.Однако, используя параметр 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

...