Здесь приведен перевод главы 6 из FAQ по программированию Linux [1], посвященной инструментарию. Описание незнакомых терминов и аббревиатур см. в Словарике статьи [2].
[Список вопросов]
6. Использование инструментов
6.1 Как можно отлаживать дочерний процесс после fork?
6.2 Как собрать библиотеку из других библиотек?
6.3 Как создать совместно используемые библиотеки (shared libraries / dll)?
6.4 Как заменить объекты в shared library?
6.5 Как сгенерировать дамп стека из работающей программы?
6.1 Как можно отлаживать дочерний процесс после fork? =====================================================
В зависимости от наличия доступного инструментария есть несколько путей.
У вашего отладчика могут быть опции для выбора, отлаживать родительский процесс, или дочерний (или их обоих) после вызова fork(), что может быть достаточно для некоторых целей.
Альтернативно у вашего отладчика может быть опция, которая позволит вам подключиться к запущенному процессу. Это можно использовать для подключения к дочернему процессу после того, как он был запущен. Если вам не нужно очень раннюю стадию запуска дочернего процесса, то этого обычно достаточно. Иначе вы можете захотеть вставить вызов sleep() после fork() в дочерний процесс, или выполнить примерно такой цикл:
{
volatile int f = 1;
while(f);
}
Этот цикл приведет к зависанию дочернего процесса, пока вы явно не установите в 0 переменную f с помощью отладчика.
Также следует помнить, что активное использование отладчика не единственный путь искать ошибки в программе; доступны утилиты для трассировки системных вызовов и сигналов на многих разновидностях unix-систем, и часто полезен бывает подробный вывод в лог.
6.2 Как собрать библиотеку из других библиотек? ===============================================
Если мы говорим об архиве (*.a, т. е. о статической библиотеке), самый простой путь состоит в том, чтобы расчленить все составляющие библиотеки на их исходные объекты, используя ar x в пустой директории, и потом скомбинировать их обратно. Конечно, существует вероятность коллизии имен файлов, однако если библиотеки большие, то возможно вы не захотите их объединять в первую очередь...
6.3 Как создать совместно используемые библиотеки (shared libraries / dll)? ===========================================================================
Правильный метод создания shared-библиотек меняется в зависимости от используемой операционной системы. У этого процесса 2 основные части; сначала должны быть скомпилированы объекты, которые должны быть включены в shared-библиотеку, обычно с опциями, которые указывают, что код не зависит от позиции в памяти; затем эти объекты линкуются друг с другом, формируя библиотеку.
Вот пример, иллюстрирующий эту идею:
/* Файл shrobj.c */
const char *myfunc()
{
return "Hello World";
}
/* Конец shrobj.c */
/* Файл hello.c */
#include < stdio.h>
extern const char *myfunc();
main()
{
printf("%s\n", myfunc());
return 0;
}
/* Конец hello.c */
Компиляция:
$ gcc -fpic -c shrobj.c
$ gcc -shared -o libshared.so shrobj.o
$ gcc hello.c libshared.so
$ ./a.out
Hello World
Безусловно, если вы хотите достичь какой-то допустимой портируемости библиотеки и процедуры сборки, то самый лучший способ это использование GNU Libtool. Это небольшой набор утилит, которые знают про зависимые от платформы аспекты сборки shared-библиотек; вы можете распространить необходимые биты вместе со своей программой, так что когда инсталлятор конфигурирует пакет, он может решить, какие библиотеки собирать. Libtool хорошо работает на системах, которые не поддерживают shared-библиотеки. Он также знает, как использовать GNU Autoconf и GNU Automake (если вы используете эти инструменты для поддержки процедуры сборки вашей программы).
Если вы не хотите использовать Libtool, то для компиляторов, отличающихся от gcc, вы должны поменять опции компилятора следующим образом:
AIX 3.2 при использовании xlc (не проверено) Отбросьте -fpic, и используйте -bM:SRE -bE:libshared.exp вместо -shared. Также вам нужно создать файл libshared.exp содержащий список символов для экспорта, в нашем примере это myfunc. Дополнительно используйте -e _nostart, когда линкуете библиотеку (не более новых версиях AIX скорее всего это поменяется на -bnoentry).
SCO OpenServer 5 при использовании SCO Development System (не проверено) Shared-библиотеки доступны только на OS5, если вы компилируете в формат ELF, который требует опции -belf. Используйте -Kpic вместо -fpic, и cc -belf -G для шага линковки.
Solaris при использовании компиляторов SparcWorks Используйте -pic вместо -fpic, и используйте ld -G вместо gcc -shared.
(Если кто-то знает другие рецепты, буду рад, если поделитесь.)
Другие вопросы, на которые следует обратить внимание:
* AIX и (что вероятно) Digital Unix не требуют опции -fpic, потому что весь код не зависит от расположения в памяти (position independent). * AIX обычно требует, чтобы вы создали 'файл экспорта', в котором перечислены экспортируемые из shared-библиотеки символы. Некоторые версии линкера (возможно только линкер SLHS, svld?) имеют опцию, чтобы экспортировать все символы. * Если вы хотите обратиться к своей shared-библиотеке, используя обычный параметр -l для линкера, то вам нужно будет понять, как система ищет shared-библиотеки, когда выполняет код runtime. Наиболее распространенным методом является использование переменной окружения LD_LIBRARY_PATH, однако обычно есть дополнительная опция, чтобы указать это во время линковки. * Большинство реализаций записывают внутри себя ожидаемое runtime место размещения shared-библиотеки. Таким образом, если переместить библиотеку из одной директории в другую, то программа может перестать работать. На многих системах есть опция для линкера, чтобы указать ожидаемое runtime место размещения (например, это опция линкера -R на Solaris, или переменная окружения LD_RUN_PATH). * ELF и a.out реализации могут иметь опцию линкера -Bsymbolic, что приводит к разрешению внутренних ссылок в библиотеке. Иначе на этих системах все разрешения символа откладываются на конечную стадию линковки, и отдельные подпрограммы в основной программе могут отменять подпрограммы в библиотеке.
6.4 Как заменить объекты в shared library? ==========================================
В основном никак.
На большинстве систем (кроме AIX), когда вы линкуете объекты для формирования shared-библиотеки, это одно и то же, что и делать линковку исполняемого кода; объекты не сохраняют свою индивидуальную идентичность. В результате как правило нельзя извлечь или заменить отдельные объекты из shared-библиотеки.
6.5 Как сгенерировать дамп стека из работающей программы? =========================================================
Некоторые системы предоставляют библиотечные функции для разматывания стека, так что вы можете (например) создать дамп стека в функции обработки ошибок. Тем не менее, они сильно зависят от системы, и только в меньшинстве систем они есть.
Возможное обходное решение состоит в том, чтобы заставить вашу программу вызвать отладчик "на себе" - детали этой процедуры все еще незначительно отличаются между системами, однако основная идея состоит в том, чтобы сделать следующее:
void dump_stack(void)
{
char s[160];
sprintf(s, "/bin/echo 'where\ndetach' | dbx -a %d", getpid());
system(s);
return;
}
Вам нужно будет настроить команды и параметры dbx в соответствии с вашей системой, или даже заменить на другой отладчик, такой как gdb, однако это вероятно все еще основное решение для такой частной проблемы. Спасибо за это Ralph Corderoy :-)
Список строк команд, требуемых для некоторых систем:
Большинство систем, использующих dbx: "/bin/echo 'where\ndetach' | dbx /path/to/program %d"
AIX: "/bin/echo 'where\ndetach' | dbx -a %d"
IRIX: "/bin/echo 'where\ndetach' | dbx -p %d"
[Ссылки]
1. Unix Programming FAQ (v1.37) site:opennet.ru. 2. FAQ программирования Linux: управление процессами. 3. Опции GCC для поддержки отладки. |