Н.В. Вдовикина, А.В. Казунин, И.В. Машечкин, А.Н. Техехин - Системное программное обеспечение - взаимодействие процессов (1114927), страница 16
Текст из файла (страница 16)
Таким образом можно,cmdнапример, изменить счетчик адреса трассируемого процесса, и припоследующем возобновлении трассируемого процесса еговыполнение начнется с инструкции, находящейся по заданномуадресу.cmd=PTRACE_GETREGS,PTRACE_GETFREGS — чтениерегистров общего назначения (в т.ч. с плавающей точкой)трассируемого процесса и запись их значения по адресу data.cmd=PTRACE_SETREGS,PTRACE_SETFREGS — запись врегистры общего назначения (в т.ч. с плавающей точкой)трассируемого процесса данных, расположенных по адресу data втрассирующем процессе.— возобновление выполнениятрассируемого процесса.
Отлаживаемый процесс будет выполнятьсядо тех пор, пока не получит какой-либо сигнал, либо пока незавершится.cmd=PTRACE_CONTcmd = PTRACE_SYSCALL, PTRACE_SINGLESTEP — эта команда,аналогично PTRACE_CONT, возобновляет выполнение трассируемой94программы, но при этом произойдет ее остановка после того, каквыполнится одна инструкция. Таким образом, используяPTRACE_SINGLESTEP, можно организовать пошаговую отладку. Спомощью команды PTRACE_SYSCALL возобновляется выполнениетрассируемой программы вплоть до ближайшего входа или выходаиз системного вызова.
Идея использования PTRACE_SYSCALL в том,чтобы иметь возможность контролировать значения аргументов,переданных в системный вызов трассируемым процессом, ивозвращаемое значение, переданное ему из системного вызова.cmd=—PTRACE_KILLзавершениевыполнениятрассируемого процесса.Пример 22. Общаятрассировки.схемаиспользованиямеханизмаРассмотрим некоторый модельный пример, демонстрирующийобщую схему построения отладочной программы (см.
также Рис.17):...if ((pid = fork()) == 0){ptrace(PTRACE_TRACEME, 0, 0, 0);/* сыновний процесс разрешает трассировать себя*/exec(“трассируемый процесс”, 0);/*замещаетсятеломнеобходимо трассировать */процесса,который}else{/* это процесс, управляющий трассировкой */wait((int ) 0);/* процесс приостанавливается до тех пор, покаот трассируемого процесса не придет сообщение отом, что он приостановился */for(;;){ptrace(PTRACE_SINGLESTEP, pid, 0, 0);95/* возобновляемпрограммы */выполнениетрассируемойwait((int ) 0);/* процесс приостанавливается до тех пор,пока от трассируемого процесса не придетсообщение о том, что он приостановился */…ptrace(cmd, pid, addr, data);/* теперь выполняются любые действия надтрассируемым процессом */…}}cигналSIGTRAPПроцесс-потомокptrace(PTRACE_TRACEME,0, 0, 0);exec(…);...cигналSIGTRAPПроцесс-предокwait(…);for(;;) {…ptrace(PTRACE_SINGLESTEP, …);…wait(…);…}Рис. 17 Общая схема трассировки процессовПредназначение процесса-потомка — разрешить трассировкусебя.
После вызова ptrace(PTRACE_TRACEME, 0, 0, 0) ядроустанавливает для этого процесса бит трассировки. Сразу же послеэтого можно заместить код процесса-потомка кодом программы,которую необходимо отладить. Отметим, что при выполнениисистемного вызова exec(), если для данного процесса ранее былустановлен бит трассировки, ядро перед передачей управления вновую программу посылает процессу сигнал SIGTRAP. Приполученииданногосигналатрассируемыйпроцессприостанавливается, и ядро передает управление процессуотладчику, выводя его из ожидания в вызове wait().Процесс-родитель вызывает wait() и переходит в состояниеожидания до того момента, пока потомок не перейдет в состояниетрассировки. Проснувшись, управляющий процесс, выполняяфункцию ptrace(cmd, pid, addr, data) с различными кодамиопераций, может производить любое действие с трассируемой96программой, в частности, читать и записывать данные в адресномпространстве трассируемого процесса, а также разрешатьдальнейшее выполнение трассируемого процесса или производитьего пошаговое выполнение.
Схема пошаговой отладки показана впримере выше и на рисунке: на каждом шаге процесс-отладчикразрешает выполнение очередной инструкции отлаживаемогопроцесса и затем вызывает wait() и погружается в состояниеожидания, а ядро возобновляет выполнение трассируемого потомка,исполняет трассируемую команду и вновь передает управлениеотладчику, выводя его из ожидания .Пример 23.
Трассировка процессов./* Процесс-сын: */int main(int argc, char **argv){/* деление на ноль – здесь процессу будетпослан сигнал SIGFPE – floating point exception*/return argc/0;}Процесс-родитель:#include <stdio.h>#include <sys/types.h>#include <unistd.h>#include <signal.h>#include <sys/ptrace.h>#include <sys/user.h>#include <sys/wait.h>int main(int argc, char *argv[]){pid_t pid;int status;struct user_regs_struct REG;if((pid = fork()) == 0) {/*находимся в процессе-потомке, разрешаемтрассировку */ptrace(PTRACE_TRACEME, 0, 0, 0);97execl(“son”, ”son”, 0);процесса *//* замещаем тело/* здесь процесс-потомок будет остановленссигналомSIG_TRAP,ожидаякомандыпродолжениявыполненияотуправляющегопроцесса*/}/* в процессе-родителе */while (1) {/*ждем,когдаприостановится */отлаживаемыйпроцессwait(&status);/*читаемсодержимоеотлаживаемого процесса */регистровptrace(PTRACE_GETREGS, pid, ®, ®);/* выводим статус отлаживаемого процесса,номер сигнала, который его остановил изначения прочитанных регистров */printf("signal = %d, status = %#x, EIP=%#xESP=%#x\n",WSTOPSIG(status),status,REG.eip, REG.esp);if (WSTOPSIG(status) != SIGTRAP) {if (!WIFEXITED(status)) {/*завершаемвыполнениетрассируемого процесса */ptrace (PTRACE_KILL, pid, 0, 0);}break;}/*разрешаемпроцессу */выполнениетрассируемомуptrace (PTRACE_CONT, pid, 0, 0);}}986 СредстваSystem V.межпроцессноговзаимодействияВсе рассмотренные выше средства взаимодействия процессовне обладают достаточной универсальностью и имеют те или иныенедостатки: так, сигналы несут в себе слишком мало информации ине могут использоваться для передачи сколь либо значительныхобъемов данных; неименованный канал должен быть создан до того,как порождается процесс, который будет осуществлятькоммуникацию; именованный канал, хотя и лишен этого недостатка,требует одновременной работы с ним обоих процессов,участвующих в коммуникации.Поэтому практически все UNIX-системы поддерживают болеемощные и развитые средства межпроцессного взаимодействия, хотяпоявление и развитие этих средств в разных версиях UNIX шлоразными путями..
Рассматриваемую в этой главе группу средствмежпроцессного взаимодействия называют System V IPC11, так какизначально эти средства были реализованы именно в UNIX SystemV, однако теперь она реализована во всех версиях UNIX. Онавключает в себя очереди сообщений, семафоры, разделяемуюпамять.Следует отметить, что объекты и методы IPC поддерживаютсястандартом POSIX (хотя они определены не в самом стандартеPOSIX.1, а в стандарте POSIX.1b, описывающем переносимую ОСреального времени), однако, синтаксис их отличается отпредложенного в System V, в частности, используется другоепространство имен. Далее в этой главе мы рассмотрим методы IPCтак, как они реализованы в System V.6.1 Организациядоступаразделяемых ресурсах.иименованияв6.1.1 Именование разделяемых объектов.Для всех средств IPC приняты общие правила именованияобъектов, позволяющие процессу получить доступ к такому объекту.Для именования объекта IPC используется ключ, представляющийсобой целое число. Ключи являются уникальными во всей UNIXсистеме идентификаторами объектов IPC, и зная ключ длянекоторого объекта, процесс может получить к нему доступ.
Приэтом процессу возвращается дескриптор объекта, который в11аббревиатура IPC – это сокращение от английского interprocess communication99дальнейшем используется для всех операций с ним. Проведяаналогию с файловой системой, можно сказать, что ключ аналогиченимени файла, а получаемый по ключу дескриптор – файловомудескриптору, получаемому во время операции открытия файла.Ключ для каждого объекта IPC задается в момент его создания темпроцессом, который его порождает, а все процессы, желающиеполучить в дальнейшем доступ к этому объекту, должны указыватьтот же самый ключ.Итак, все процессы, которые хотят работать с одним и тем жеIPC-ресурсом, должны знать некий целочисленный ключ, покоторому можно получить к нему доступ. В принципе, программист,пишущий программы для работы с разделяемым ресурсом, можетпросто жестко указать в программе некоторое константное значениеключа для именования разделяемого ресурса.
Однако, возможнаситуация, когда к моменту запуска такой программы в системе ужесуществует разделяемый ресурс с таким значением ключа, и в видутого, что ключи должны быть уникальными во всей системе,попытка породить второй ресурс с таким же ключом закончитсянеудачей (подробнее этот момент будет рассмотрен ниже).6.1.2 Генерация ключей: функция ftok().Как видно, встает проблема именования разделяемого ресурса:необходим некий механизм получения заведомо уникального ключадля именования ресурса, но вместе с тем нужно, чтобы этотмеханизм позволял всем процессам, желающим работать с однимресурсом, получить одно и то же значение ключа.Для решения этой задачи служит функция ftok():#include <sys/types.h>#include <sys/ipc.h>key_t ftok(char *filename, char proj);Эта функция генерирует значение ключа по некоторой строкесимволов и добавочному символу, передаваемым в качествепараметров.
Гарантируется, что полученное таким образом значениебудет отличаться от всех других значений, сгенерированныхфункцией ftok() с другими значениями параметров, и в то жевремя, при повторном запуске ftok() с теми же параметрами, будетполучено то же самое значение ключа.Смысл второго аргумента функции ftok() – добавочногосимвола – в том, что он позволяет генерировать разные значенияключа по одному и тому же значению первого параметра – строки.100Это позволяет программисту поддерживать несколько версий своейпрограммы, которые будут использовать одну и ту же строку, норазные добавочные символы для генерации ключа, и тем самымполучат возможность в рамках одной системы работать с разнымиразделяемыми ресурсами.Следует заметить, что функция ftok() не является системнымвызовом, а предоставляется библиотекой.6.1.3 Общиепринципыресурсами.работысразделяемымиРассмотрим некоторые моменты, общие для работы со всемиразделяемыми ресурсами IPC.