[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]

Программирование: Разработка и отладка программ


Проверка программных данных

Этот раздел посвящен анализу, проверке и изменению данных в программах.

В этом разделе рассматриваются следующие вопросы:

Обработка сигналов

Программа dbx может перехватывать или игнорировать сигналы, отправляемые в вашу программу. Каждый раз, когда в вашу программу отправляется сигнал, программа dbx получает об этом уведомление. Если сигнал следует проигнорировать, он передается в вашу программу; в противном случае dbx останавливает программу и сообщает о перехвате сигнала. Программа dbx не может проигнорировать сигнал SIGTRAP, если он поступил от внешнего по отношению к ней процесса. В программе с несколькими нитями сигнал может передаваться в определенную нить с помощью функции pthread_kill. По умолчанию программа dbx останавливается и сообщает о перехвате сигнала. С помощью команды ignore можно указать, что программа dbx должна игнорировать сигнал и передавать его нити. Для изменения режима обработки сигнала по умолчанию предназначены команды catch и ignore.

В следующем примере сигналы SIGGRANT и SIGREQUEST применяются программой для выделения ресурсов. Для того чтобы программа dbx продолжала работу при получении этих сигналов, введите:

(dbx) ignore GRANT
(dbx) ignore SIGREQUEST
(dbx) ignore
CONT CLD ALARM KILL GRANT REQUEST

Если установить переменную $sigblock, то программа dbx будет блокировать сигналы, передаваемые в вашу программу. По умолчанию сигналы, поступающие в программу dbx, направляются в исходную программу или в объектный файл, определяемый параметром Объектный_файл программы dbx. Если с помощью команды set установить переменную $sigblock, то сигналы, получаемые программой dbx, не будут передаваться в исходную программу. Если вы хотите, чтобы сигнал передавался в программу, воспользуйтесь командой cont с сигналом в качестве операнда.

Можно использовать этот способ для прерывания выполнения программы, которая запускается программой dbx. Обычно перед продолжением выполнения программы проверяется ее состояние. Если переменная $sigblock не установлена, то при прерывании выполнения в программу передается сигнал SIGINT. При продолжении выполнения программы управление передается обработчику сигнала (если он существует).

Следующий пример программы показывает, как изменяется порядок выполнения при запуске в режиме отладки (т.е. с помощью dbx), если установлена переменная $sigblock:

#include <signal.h>
#include <stdio.h>
void inthand( ) {
        printf("\nПолучен сигнал SIGINT\n");
        exit(0);
}

main( )
{
        signal(SIGINT, inthand);
        while (1) {
                  printf(".");
                  fflush(stdout);
                sleep(1);
        }
}

В следующем примере эта программа используется как исходный файл в сеансе работы с программой dbx. При первом прогоне программы переменная $sigblock не установлена. Во время повторного запуска (rerun) переменная $sigblock установлена. Справа в угловых скобках приведены комментарии:

dbx version 3.1.
Введите 'help' для просмотра справки.
чтение символьной информации ...
(dbx) run
.........^C                      <Здесь пользователь нажал Ctrl-C>
прерывание в sleep в 0xd00180bc
0xd00180bc (sleep+0x40) 80410014          1        r2,0x14(r1)
(dbx) cont

получен SIGINT

выполнение завершено
(dbx) set $sigblock
(dbx) rerun
[ looper ]
..............^C                      <Здесь пользователь нажал Ctrl-C>
прерывание в sleep в 0xd00180bc
0xd00180bc (sleep+0x40) 80410014          1        r2,0x14(r1)
(dbx) cont
....^C   <Программа не получила сигнал, выполнение продолжается>

прерывание в sleep в 0xd00180bc
0xd00180bc (sleep+0x40) 80410014          1        r2,0x14(r1)
(dbx) cont 2                     <Завершение программы с сигналом 2>

получен SIGINT

выполнение завершено
(dbx)

Вызов процедур

Из программы dbx можно вызывать процедуры для тестирования различных аргументов. Можно также вызывать диагностические процедуры, которые форматируют данные для упрощения отладки. Для вызова процедуры служит команда call или команда print.

Просмотр данных трассировки стека

Для просмотра списка вызовов процедур, которые предшествовали останову программы, служит команда where.

В приведенном ниже примере исполняемый объектный файл hello состоит из двух исходных файлов и трех процедур, включая стандартную процедуру main. Программа останавливается в точке прерывания в процедуре sub2.

(dbx) run
[1] останавливается в sub2 в строке 4 в файле "hellosub.c"
(dbx) where
sub2(s = "hello", n = 52), строка 4 в "hellosub.c"
sub(s = "hello", a = -1, k = delete), строка 31 в "hello.c"
main(), строка 19 в "hello.c"

При трассировке стека вызовы просматриваются в обратном порядке. Если начать с дна стека, то происходившие события образуют следующую последовательность:

  1. Оболочка вызвала процедуру main.
  2. Процедура main вызвала процедуру sub в строке 19 со значениями s = "hello", a = -1 и k = delete.
  3. Процедура sub вызвала процедуру sub2 в строке 31 со значениями s = "hello" и n = 52.
  4. Программа остановилась на процедуре sub2 в строке 4.

    Примечание: Для того чтобы отключить режим вывода на экран аргументов, передаваемых в процедуры, задайте в программе отладки переменную $noargs.

С помощью команд up и down можно просматривать фрагменты стека.

Просмотр и изменение переменных

Для просмотра выражений применяется команда print. Для печати имен и значений переменных - команда dump. Если данная процедура - точка, то печатаются все активные переменные. Для изменения значения переменной предназначена команда assign.

В приведенном ниже примере в программе на языке C используются автоматическая целочисленная переменная x со значением 7 и параметры s и n в процедуре sub2:

(dbx) print x, n
7 52
(dbx) assign x = 3*x
(dbx) print x
21
(dbx) dump
sub2(s = "hello", n = 52)
x = 21

Просмотр информации о нитях

Для просмотра информации о пользовательских нитях, взаимных блокировках, условиях и объектах атрибутов предназначены команды thread, mutex, condition и attribute. К этим объектам применима также команда print. В следующем примере выполняется нить 1. Пользователь делает текущей нить 2, запрашивает список нитей, печатает информацию о нити 1 и, наконец, печатает информацию о нескольких объектах, связанных с нитями.

(dbx) thread current 2
(dbx) thread
 thread  state-k   wchan state-u   k-tid mode held scope function
*$t1     run             running   12755 u    no   pro   main
>$t2      run             running   12501 k    no   sys   thread_1
(dbx) print $t1
(thread_id = 0x1, state = run, state_u = 0x0, tid = 0x31d3, mode = 0x1, held = 0x0,
priority = 0x3c, policy = other, scount = 0x1, cursig = 0x5, attributes = 0x200050f8)

(dbx) print $a1,$c1,$m2
(attr_id = 0x1, type = 0x1, state = 0x1, stacksize = 0x0, detachedstate = 0x0, process_shared = 0x0,
 contentionscope = 0x0, priority = 0x0, sched = 0x0, inherit = 0x0, protocol = 0x0, prio_ceiling = 0x0)
(cv_id = 0x1, lock = 0x0, semaphore_queue = 0x200032a0, attributes = 0x20003628)
(mutex_id = 0x2, islock = 0x0, owner = (nil), flags = 0x1, attributes = 0x200035c8)

Область видимости имен

Для преобразования имен в первую очередь применяется статический контекст текущей функции. Динамический контекст используется в том случае, если имя не определено в статическом контексте. Если имя не найдено ни в статическом, ни в динамическом контексте, то выбирается произвольный символ и печатается сообщение usingQualifiedName. Можно переопределить процедуру преобразования имен, задав идентификатор и имя блока (например, Модуль.Переменная). Исходные файлы рассматриваются как модули, имена которых совпадают с именами файлов без расширения. Например, полное имя переменной x, объявленной в процедуре sub внутри файла hello.c, будет hello.sub.x. Точка в имени ставится самой программой.

При наличии нескольких символов с одним именем для того чтобы определить, какой именно символ найден, можно воспользоваться командами which и whereis.

Использование операторов и модификаторов в выражениях

Программа dbx позволяет просматривать широкий диапазон выражений. Для задания выражений используется обычный синтаксис языка C или Pascal, с некоторыми расширениями языка FORTRAN.

* (звездочка) или ^ (знак вставки) Обозначает косвенную адресацию или разыменование указателя.
[ ] (квадратные скобки) или ( ) (круглые скобки) Обозначают индексное выражение массива.
. (точка) Оператор ссылки на поле. Используется в структурах и указателях. При этом оператор языка C -> (стрелка) становится не нужен, хотя и может использоваться.
&(амперсанд) Получение адреса переменной.
.. (две точки) Разделяют верхнюю и нижнюю границы при обозначении части массива. Например, n[1..4].

В выражениях допустимы следующие типы операций:

Алгебраические =, -, *,/(деление вещественных чисел), div (деление целых чисел), mod (вычисление остатка от деления нацело), exp (возведение в степень)
Поразрядные -, I, bitand, xor, ~, <<,>>
Логические or, and, not, II, &&
Сравнения <, >, <=, >=, <> or !=, = or ==
Другие sizeof

Логические операции и операции сравнения разрешается использоваться для записи условий в командах stop и trace.

Контроль типов выражений

Программа dbx контролирует типы выражений. Вы можете переопределять тип выражения с помощью оператора переименования или приведения типа. Существуют три способа переименования типа:

Примечание: Если исходным или целевым типом при приведении является структура, объединение или класс, то выполняется выравнивание влево. Однако при приведении класса к базовому классу соблюдаются синтаксические правила языка C++.

Например, для переименования переменной x целого типа со значением 97 введите:

(dbx) print char (x), x \ char, (char) x, x,
'a' 'a' 'a' 97

В следующем примере проиллюстрировано приведение типов с помощью формата (Имя_типа) Выражение :

print (float) i

print ((struct qq *) void_pointer)->first_element

Приведение типов в программе dbx выполняется по правилам языка C со следующими ограничениями:

Команда whatis выдает описание идентификатора, который может быть уточнен именем блока.

Конструкция $$тег применяется для печати описаний тегов перечислимых типов данных, структур и объединений (или аналогичных объектов языка Pascal).

Тип выражения в команде assign должен совпадать с типом переменной, который вы присваиваете. Если типы не совпадают, будет выдано сообщение об ошибке. Вы можете изменить тип выражения с помощью операции переименования типа. Для отключения контроля типов укажите специальную переменную $unsafeassign программы dbx.

Перевод переменных в нижний или верхний регистр

По умолчанию программа dbx выполняет преобразование символов к нужному регистру в соответствии с текущим языком. Если текущий язык - C, C++ или не определен, то регистр символов не изменяется. Если текущий язык - FORTRAN или Pascal, то символы переводятся в нижний регистр. Текущий язык остается неопределенным, если программа находится в разделе кода, который не компилировался с флагом debug. Изменить настройку, установленную по умолчанию, можно с помощью команды case.

Команда case без аргументов показывает текущий регистр.

Компиляторы FORTRAN и Pascal преобразуют все символы программы в нижний регистр; компилятор C - нет.

Изменение формата вывода с помощью специальных переменных программы отладки

С помощью команды set можно задать специальные переменные программы dbx, которые изменяют формат вывода команды print:

$hexints Печатает целые выражения в шестнадцатеричном формате.
$hexchars Печатает символьные выражения в шестнадцатеричном формате.
$hexstrings Печатает адреса строк символов, а не сами строки.
$octints Печатает целые выражения в восьмеричном формате.
$expandunions Печатает поля в объединении.
$pretty Печатает сложные типы C и C++ в формате pretty.

Для получения результатов отладки в нужном вам формате установите необходимые переменные программы отладки. Например:

(dbx) whatis x; whatis i; whatis s
int x;
char i;
char *s;
(dbx) print x, i, s
375 'c' "hello"
(dbx) set $hexstrings; set $hexints; set $hexchars
(dbx) print x, i, s
0x177 0x63 0x3fffe460
(dbx) unset $hexchars; set $octints
(dbx) print x, i
0567 'c'
(dbx) whatis p
struct info p;
(dbx) whatis struct info
struct info {
    int x;
    double position[3];
    unsigned char c;
    struct vector force;
};
(dbx) whatis struct vector
struct vector {
    int a;
    int b;
    int c;
};
(dbx) print p
(x = 4, position = (1.3262493258532527e-315, 0.0, 0.0), c = '\0', force = (a = 0, b = 9, c = 1))
(dbx) set $pretty="on"
(dbx) print p
{
    x = 4
    position[0] = 1.3262493258532527e-315
    position[1] = 0.0
    position[2] = 0.0
    c = '\0'
    force = {
        a = 0
        b = 9
        c = 1
    }
}
(dbx) set $pretty="verbose"
(dbx) print p
x = 4
position[0] = 1.3262493258532527e-315
position[1] = 0.0
position[2] = 0.0
c = '\0'
force.a = 0
force.b = 9
force.c = 1

Связанная информация

Программа символьной отладки dbx - Обзор

Работа с программой отладки dbx

Просмотр и редактирование исходного файла с помощью программы отладки dbx

Применение dbx для отладки на машинном уровне

Настройка среды отладки dbx


[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]