Развлечения со strace и отладчиком GDB

Получите новые знания, изучая свою UNIX-систему

Программирование для UNIX® может быть таким же забавным, как и их изучение. С помощью утилиты UNIX - strace и GDB - отладчика, созданного в рамках проекта GNU, можно реально глубоко погрузиться в недра системы, а также многое узнать о различных программах, которые работают в ней. Согласованно используя обе утилиты, можно вознаградить себя - аглянуть под капот вашей UNIX-машины.

Вильям Зиммерли, внештатный писатель и научный инженер, внештатный писатель

Photo of Bill ZimmerlyБил Зиммерли (Bill Zimmerly) является специалистом в области инженерии знаний, а также программистом низкоуровневых систем. Он имеет большой опыт работы с различными версиями программного обеспечения UNIX ® и Microsoft ® Windows ® и считается человеком с большим логическим мышлением. Бил с огромным энтузиазмом и удовольствием занимается созданием новых технологий и рассказывает о них в своих статьях. Живет он в деревушке Хилсборо, Миссури, где может наслаждаться чистым воздухом и прекрасной природой. Кроме того, неподалеку находятся несколько винных заводов.



29.12.2008

Семейство UNIX всегда изобиловало возможностями для пользователей. UNIX - сокровищница утилит, которые можно не только продуктивно использовать, но также обучаться и баловать себя исследованием глубин операционной системы. Две полезные утилиты, нужные нам - это strace, которая позволяет выполнять трассировку вызовов любых программ, и отладчик GDB, который является полнофункциональным отладчиком, позволяющим запускать программы в контролируемом окружении.

UNIX задуман так, что сотни функциональных вызовов (называемых системными вызовами) выполняют простые задачи, например, задать задачу приоритетов отображения символов на экране. Все UNIX-программы выполняют свои задачами, вызывая эти низкоуровневые службы, которые предоставляет операционная система, а с помощью утилиты strace можно в реальном времени следить за этими вызовами и используемыми для них параметрами. Можно реально поиграть с программами, изучив их низкоуровневые взаимосвязи с операционной системой.

Начнем игру

Начнем с рассмотрения простой команды UNIX - pwd, и выясним до конца, что делает данная команда. Необходимо запустить xterm, чтобы создать контролируемое окружение для экспериментов и набрать следующую команду:

$ pwd

Команда pwd показывает текущий рабочий каталог. Вывод (команды) на моем компьютере на тот момент времени был таким:

/home/bill/

Таким образом, простая функция опровергает кажущуюся сложность программы (кстати, так делают все компьютерные программы). Чтобы получить полное представление о всей сложности, необходимо запустить команду pwd заново, используя утилиту strace:

$ strace pwd

С помощью этой команды можно увидеть, сколько всего происходит на UNIX-машине только для того, чтобы обнаружить и вывести текущий рабочий каталог пользователя (листинг 1).

Листинг 1. Консольный вывод команды strace pwd
execve("/bin/pwd", ["pwd"], [/* 39 vars */]) = 0
uname({sys="Linux", node="sammy", ...}) = 0
brk(0)                                  = 0x804c000
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4001...
	.
	.
	.
	fstat64(3, {st_mode=S_IFREG|0644, st_size=115031, ...}) = 0
old_mmap(NULL, 115031, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40017000
close(3)                                = 0
open("/lib/tls/libc.so.6", O_RDONLY)    = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360U\1"..., 1024) = 1024
fstat64(3, {st_mode=S_IFREG|0755, st_size=1547996, ...}) = 0
old_mmap(0x42000000, 1257224, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x42000000
mprotect(0x4212e000, 20232, PROT_NONE)  = 0
old_mmap(0x4212e000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x12e000)...
old_mmap(0x42131000, 7944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS,...
close(3)                                = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0x40016ac0, limit:1048575, seg_32bit...
munmap(0x40017000, 115031)              = 0
brk(0)                                  = 0x804c000
brk(0x804d000)                          = 0x804d000
brk(0)                                  = 0x804d000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=30301680, ...}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40017000
close(3)                                = 0
brk(0)                                  = 0x804d000
brk(0x804e000)                          = 0x804e000
getcwd("/home/bill", 4096)              = 11
fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 6), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4021700...
write(1, "/home/bill\n", 11/home/bill
)            = 11
munmap(0x40217000, 4096)                = 0
exit_group(0)                           = ?

Основы системных вызовов UNIX

Вдаваться в детали того, почему все эти системные вызовы необходимы для получения и вывода на экран текущего рабочего каталога, мы не будем, так как это выходит за рамки данной статьи, но я покажу, как получить эту информацию. В каждой строчке листинга 1 - системный вызов с параметрами выводится в Си-подобном формате, именно так, как этого ожидают Си-программисты. strace всегда отображает вызовы таким образом, независимо от фактического языка программирования, используемого при написании программы.

Если требуется понять все детали вывода листинга 1, UNIX предоставляет огромное количество документации по всем системным вызовам. Самая важная функция там - это функция getcwd(), которая позволяет получить текущий рабочий каталог. В текущем xterm показывается вывод strace pwd, поэтому можно запустить еще один xterm и набрать такую же команду, чтобы увидеть, что UNIX выведет для этой функции:

$ man getcwd

Должен быть выведен полный листинг функции getcwd() и листинг аргументов, которые эта важная Си-функция принимает и возвращает. Аналогично, можно набрать man brk или man fstat64 и так далее. Эти системные функции обычно хорошо документированы, и если потратить время на их изучение, придет понимание реальной мощи UNIX и того, как просто производить низкоуровневый анализ системы. Из всех операционных систем UNIX является наилучшей с точки зрения понимания происходящего внутри и вне системы.


Обзор nweb

Далее потребуется что-либо более крупное и сложное, нежели простая UNIX-команда типа pwd. Простой сервер Hypertext Transfer Protocol (HTTP), такой как nweb, прекрасно подойдет. HTTP-сервер слушает запросы Web-браузера, когда вы бороздите Интернет, и отправляет по этим запросам запрашиваемые объекты, такие как Web-страницы и графические файлы.

Потребуется скачать и установить nweb, написанный сотрудником IBM developerWorks Нигелем Гриффитсом (см. ссылку в разделе Ресурсы на статью Нигеля - "nweb: a tiny, safe Web server (static pages only)" (developerWorks, июнь 2004).)

После загрузки архива es-nweb.zip в папку $HOME/downloads необходимо набрать простые команды, выполняющие извлечение, компиляцию и запуск программы (листинг 2):

Замечание. Предполагается, что программа будет компилироваться на рабочей станции с Linux®. Если это не так, то необходимо прочесть справку nweb'а о деталях компилирования программы для других вариантов UNIX.

Листинг 2. Команды извлечения, компиляции и запуска nweb
$ cd src
$ mkdir nweb
$ cd nweb
$ unzip $HOME/downloads/es-nweb.zip
$ gcc -ggdb -O -DLINUX nweb.c -o nweb
$ ./nweb 9090 $HOME/src/nweb &

Замечание. Опция -ggdb в листинге 2 отличается от статьи Нигеля и дает команду компилятору GCC оптимизировать программу для отладки в отладчике GDB, который будет использоваться позже.

Далее нужно проверить, что nweb-сервер запущен, используя команду ps для отображения результатов проверки (листинг 3).

Листинг 3. Команда ps
$ ps
  PID TTY          TIME CMD
 2913 pts/5    00:00:00 bash
 4009 pts/5    00:00:00 nweb
 4011 pts/5    00:00:00 ps

Наконец, нужно проверить, что nweb действительно запущен и все корректно, запустив Web-браузер на компьютере и набрав http://localhost:9090 в адресной строке.

Использование strace с nweb

Пришло время начать исследование. Запустим еще один xterm и воспользуемся strace для трассировки запущенного nweb-сервера. Для того чтобы сделать это, нужно знать идентификатор процесса программы и иметь соответствующие права доступа. Будем рассматривать только определенные системные вызовы - те, которые имеют отношение к сети. Для начала необходимо ввести команду, показанную в первой строке листинга 4, используя идентификатор процесса nweb, выведенный ранее. Должен быть показан следующий вывод - строка 2 листинга 4.

Листинг 4. Запуск трассировки nweb'а
$ strace -e trace=network -p 4009
accept(0,

Отметим, что трассировка останавливается в середине вызова сетевой функции accept(). Необходимо несколько раз обновить страницу http://localhost:9090 в Web-браузере, чтобы увидеть, что strace отображает каждое обновление страницы. Не великолепно ли? Мы видим низкоуровневые сетевые вызовы HTTP-сервера nweb, которые были вызваны Web-браузером. Буквально говоря, nwebпринимает запросы Web-браузера.

Можно остановить трассировку сетевых вызовов запущенного процесса nweb, нажав Ctrl+C, когда текущим является окно xterm c запущенным strace.


Отладчик GDB

Как было показано, strace может быть прекрасной программой для изучения того, как пользовательские программы взаимодействуют с операционной системой посредством определенных системных вызовов. Отладчик GDB также может подсоединиться к текущему запущенному процессу, помогая копнуть глубже.

Отладчик GDB - довольно полезная штука, так что о нем доступно много информации в Интернет. Отладчики - это обычно важные утилиты, и каждый, кто ответственен за разработку и поддержку компьютерных систем, должен быть знаком с ними. Пока nweb работает в другой сессии xterm, остановим strace, нажав Ctrl+C, и запустим отладчик GDB, введя команды, показанные в листинге 5.

Листинг 5. Запуск отладчика GDB
$ gdb --quiet
(gdb) attach 4009
Attaching to process 4009
Reading symbols from /home/bill/src/nweb/nweb...done.
Reading symbols from /lib/tls/libc.so.6...done.
Loaded symbols for /lib/tls/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
0xffffe410 in ?? ()
(gdb)

Опция --quiet дает команду GDB показывать только подсказки, а не всю другую стартовую информацию, которая обычно выводится. Если необходимо увидеть дополнительный текст, опустите опцию --quiet.

Команда attach 4009 запускает отладку текущего запущеного nweb-сервера, а отладчик GDB в ответ на это считывает всю возможную информацию о процессе. Далее необходимо использовать команду info для получения информации об исследуемой программе (листинг 6).

Листинг 6. Команда info показывает информацию о программе
(gdb) info proc
process 4009
cmdline = './nweb'
cwd = '/home/bill/src/nweb'
exe = '/home/bill/src/nweb/nweb'
(gdb)

Другой полезный вариант команды info - это info functions, однако список функций может оказаться очень длинным (листинг 7).

Листинг 7. Функции, перечисленные с помощью команды info functions
(gdb) info functions
All defined functions:

File nweb.c:
void log(int, char *, char *, int);
int main(int, char **);
void web(int, int);

File __finite:
int __finite();
	.
	.
	.
(gdb)

Так как программа nweb была скомпилирована с опцией -ggdb, то в исполняемый файл было включено много отладочной информации, позволяющей отладчику видеть описания функций, приведенных в файле, как показано в листинге 7.


Команды list и disassemble

Две важнейшие команды GDB - это list и disassemble. Давайте посмотрим, как работают эти команды, на примере кода в листинге 8.

Листинг 8. Команда list
(gdb) list main
121             exit(1);
122     }
123
124
125     main(int argc, char **argv)
126     {
127             int i, port, pid, listenfd, socketfd, hit;
128             size_t length;
129             char *str;
130             static struct sockaddr_in cli_addr; /* static = initialised to zeros */
(gdb) 
131             static struct sockaddr_in serv_addr; /* static = initialised to zeros */
132
133             if( argc < 3  || argc > 3 || !strcmp(argv[1], "-?") ) {
134                     (void)printf("hint: nweb Port-Number Top-Directory\n\n"
135             "\tnweb is a small and very safe mini web server\n"
136             "\tnweb only servers out file/web pages with extensions named below\n"
137             "\t and only from the named directory or its sub-directories.\n"
138             "\tThere is no fancy features = safe and secure.\n\n"
139             "\tExample: nweb 8181 /home/nwebdir &\n\n"
140             "\tOnly Supports:");

Как видно, команда list выводит для запущенной программы исходный код с номерами строк. Нажатие клавиши возврата (показано между строками 130 и 131) просто продолжает листинг с того места, где он закончился. Теперь необходимо набрать команду disassemble, которую можно сократить до disass (листинг 9).

Листинг 9. Команда disassemble
(gdb) disass main
Dump of assembler code for function main:
0x08048ba2 <main+0>:    push   ebp
0x08048ba3 <main+1>:    mov    ebp,esp
0x08048ba5 <main+3>:    push   edi
0x08048ba6 <main+4>:    push   esi
0x08048ba7 <main+5>:    push   ebx
0x08048ba8 <main+6>:    sub    esp,0xc
0x08048bab <main+9>:    mov    ebx,DWORD PTR [ebp+12]
0x08048bae <main+12>:   and    esp,0xfffffff0
	.
	.
	.
0x08048c01 <main+95>:   call   0x8048664 <printf>
0x08048c06 <main+100>:  add    esp,0x10
0x08048c09 <main+103>:  inc    esi
0x08048c0a <main+104>:  cmp    DWORD PTR [ebx+esi],0x0
---Type <return> to continue, or q <return> to quit---

Это выводится код ассемблера из функции main. В этом случае ассемблерный код показывает, что запущенный код выполняется на процессоре Intel® Pentium®. Код будет выглядеть совершенно по-другому, если его запустить на компьютере с другим типом процессора, например, на компьютере с IBM Power PC®.


Наблюдение за работающей программой

Так как ведется наблюдение за реально запущенной программой, то можно установить точки останова и увидеть, как программа отвечает на запросы Web-браузера и передает файлы .html и .jpg браузеру по запросу. Как это делается, показано в листинге 10.

Листинг 10. Установка точек останова
(gdb) break 188
Breakpoint 1 at 0x8048e70: file nweb.c, line 188.
(gdb) commands 1
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>continue
>end
(gdb) c
Continuing.

В этой точке отладчик GDB устанавливает линию разрыва, когда сервер nweb принимает запрос Web-браузера; отладчик просто будет показывать запросы и продолжать обработку без прерывания запущенной программы. Необходимо несколько раз обновить страницу http://localhost:9090/ в Web-браузере, и можно увидеть, что отладчик GDB покажет точку останова и продолжит работу.

Пока обновляется страница браузера, должна быть видна информация о точках останова; это можно просмотреть, прокрутив в xterm вывод GDB (листинг 11). Как и со strace, можно остановить отладку сервера nweb, нажав комбинацию клавиш Ctrl+C. После остановки трассировки для выхода из GDB необходимо набрать команду quit.

Листинг 11. Информация о точках останова отладчика GDB в xterm
Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188
188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188
188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188
188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188
188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
Program received signal SIGINT, Interrupt.
0xffffe410 in ?? ()
(gdb) quit
The program is running.  Quit anyway (and detach it)? (y or n) y
Detaching from program: /home/bill/src/nweb/nweb, process 4009
$

Отметим, что при вызове завершения отладки программы отладчиком GDB сама программа остается активной в памяти. Сразу после завершения отладки можно обновить страницу в Web-браузере и увидеть, что nweb продолжает работать. Можно остановить программу, набрав команду kill 4009, или страница исчезнет после завершения сессии.

Как обычно, можно узнать многое об утилитах, таких как strace и GDB из их man- и info-страниц. Увереннее используйте утилиты, которые предоставляет UNIX!


Узнай как можно больше

Неплохо было бы знать как можно больше о компьютере, на котором вы работаете, а еще лучше - получать удовольствие от процесса работы. UNIX действительно поощряет обзор и изучение утилит, таких как strace и отладчик GDB, также предоставляя много информации в их man- и info-страницах. Компьютер - это продолжение нашего мозга, и чем больше мы о нем знаем, тем больше от него пользы.

Ресурсы

Научиться

Получить продукты и технологии

  • IBM trial software: ознакомительные версии программного обеспечения для разработчиков, которые можно загрузить прямо со страницы сообщества developerWorks.(EN)

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=AIX и UNIX
ArticleID=361310
ArticleTitle=Развлечения со strace и отладчиком GDB
publish-date=12292008