Н.В. Вдовикина, И.В. Машечкин, А.Н. Терехин, А.Н. Томилин - Операционные системы - взаимодействие процессов (2008) (1114653), страница 17
Текст из файла (страница 17)
Если в это времяотлаживающий процесс осуществляет системный вызов wait(),98этот вызов немедленно возвращает управление. В то время, кактрассируемый процесс находится в приостановленном состоянии,процесс-отладчик имеет возможность анализировать и изменятьданные в адресном пространстве отлаживаемого процесса и впользовательской составляющей его контекста. Далее, процессотладчик возобновляет выполнение трассируемого процесса доследующей приостановки (либо, при пошаговом выполнении, длявыполнения одной инструкции).Основной системный вызов, используемый при трассировке,–это ptrace(), прототип которого выглядит следующим образом:#include <sys/ptrace.h>int ptrace(int cmd, pid, addr, data);где cmd – код выполняемой команды, pid – идентификаторпроцесса-потомка, addr – некоторый адрес в адресном пространствепроцесса-потомка, data – слово информации.Чтобы оценить уровень предоставляемых возможностей,рассмотрим основные кодыпараметра cmd, обозначающиеоперации этой функции:cmd = PTRACE_TRACEME — ptrace() с таким кодом операциисыновний процесс вызывает в самом начале своей работы, позволяятем самым трассировать себя.
Все остальные обращения к вызовуptrace() осуществляет процесс-отладчик.PTRACE_PEEKDATA — чтение слова из адресногопространства отлаживаемого процесса по адресу addr, ptrace()cmd=возвращает значение этого слова.cmd=PTRACE_PEEKUSER — чтение слова из контекстапроцесса. Речь идет о доступе к пользовательской составляющейконтекста данного процесса, сгруппированной в некоторуюструктуру, описанную в заголовочном файле <sys/user.h>. В этомслучае параметр addr указывает смещение относительно началаэтой структуры.
В этой структуре размещена такая информация, какрегистры, текущее состояние процесса, счетчик адреса и так далее.ptrace() возвращает значение считанного слова.cmd = PTRACE_POKEDATA — запись данных, размещенных впараметре data, по адресу addr в адресном пространстве процесса-потомка.= PTRACE_POKEUSER — запись слова из data в контексттрассируемого процесса со смещением addr. Таким образом можно,cmdнапример, изменить счетчик адреса трассируемого процесса, и при99последующем возобновлении трассируемого процесса еговыполнение начнется с инструкции, находящейся по заданномуадресу.cmd=PTRACE_GETFREGS — чтениеPTRACE_GETREGS,регистров общего назначения (в т.ч. с плавающей точкой)трассируемого процесса и запись их значения по адресу data.cmd=PTRACE_SETFREGS — запись вPTRACE_SETREGS,регистры общего назначения (в т.ч.
с плавающей точкой)трассируемого процесса данных, расположенных по адресу data втрассирующем процессе.— возобновление выполнениятрассируемого процесса. Отлаживаемый процесс будет выполнятьсядо тех пор, пока не получит какой-либо сигнал, либо пока незавершится.cmd=PTRACE_CONTcmd = PTRACE_SYSCALL, PTRACE_SINGLESTEP — эта команда,аналогично PTRACE_CONT, возобновляет выполнение трассируемойпрограммы, но при этом произойдет ее остановка после того, каквыполнится одна инструкция.
Таким образом, используяPTRACE_SINGLESTEP, можно организовать пошаговую отладку. Спомощью команды PTRACE_SYSCALL возобновляется выполнениетрассируемой программы вплоть до ближайшего входа или выходаиз системного вызова. Идея использования PTRACE_SYSCALL в том,чтобы иметь возможность контролировать значения аргументов,переданных в системный вызов трассируемым процессом, ивозвращаемое значение, переданное ему из системного вызова.cmd=—PTRACE_KILLзавершениевыполнениятрассируемого процесса.Пример 22.
Общаятрассировки.схемаиспользованиямеханизмаРассмотрим некоторый модельный пример, демонстрирующийобщую схему построения отладочной программы (см. также Рис.17):...if ((pid = fork()) == 0){ptrace(PTRACE_TRACEME, 0, 0, 0);/* сыновний процесс разрешает трассировать себя*/100exec(“трассируемый процесс”, 0);/*замещаетсятеломнеобходимо трассировать */процесса,который}else{/* это процесс, управляющий трассировкой */wait((int ) 0);/* процесс приостанавливается до тех пор, покаот трассируемого процесса не придет сообщение отом, что он приостановился */for(;;){ptrace(PTRACE_SINGLESTEP, pid, 0, 0);/* возобновляемпрограммы */выполнениетрассируемой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 Общая схема трассировки процессов101Предназначение процесса-потомка — разрешить трассировкусебя. После вызова ptrace(PTRACE_TRACEME, 0, 0, 0) ядроустанавливает для этого процесса бит трассировки. Сразу же послеэтого можно заместить код процесса-потомка кодом программы,которую необходимо отладить. Отметим, что при выполнениисистемного вызова exec(), если для данного процесса ранее былустановлен бит трассировки, ядро перед передачей управления вновую программу посылает процессу сигнал SIGTRAP.
Приполученииданногосигналатрассируемыйпроцессприостанавливается, и ядро передает управление процессуотладчику, выводя его из ожидания в вызове wait().Процесс-родитель вызывает wait() и переходит в состояниеожидания до того момента, пока потомок не перейдет в состояниетрассировки. Проснувшись, управляющий процесс, выполняяфункцию ptrace(cmd, pid, addr, data) с различными кодамиопераций, может производить любое действие с трассируемойпрограммой, в частности, читать и записывать данные в адресномпространстве трассируемого процесса, а также разрешатьдальнейшее выполнение трассируемого процесса или производитьего пошаговое выполнение. Схема пошаговой отладки показана впримере выше и на рисунке: на каждом шаге процесс-отладчикразрешает выполнение очередной инструкции отлаживаемогопроцесса и затем вызывает wait() и погружается в состояниеожидания, а ядро возобновляет выполнение трассируемого потомка,исполняет трассируемую команду и вновь передает управлениеотладчику, выводя его из ожидания .Пример 23.
Трассировка процессов.В приведенном ниже примере процесс-потомок, разрешивтрассировку, замещает свое тело простейшей программой,осуществляющей деление на 0.Процесс-предок осуществляет трассировку и выводит на экрансодержимое двух регистров потомка и информацию о причине егоостановки.Отметим, что в BSD UNIX структура для полученияинформации о регистрах и константы команд трассировки имеютнемного другие названия.
Для того, чтобы обойти этонесоответствие, в тексте примера используется условнаякомпиляция./* Процесс-сын: */102int 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/param.h>#include <sys/ptrace.h>#include <sys/user.h>#include <sys/wait.h>#ifdef BSD#include <machine/reg.h>#define PTRACE_TRACEME PT_TRACE_ME#define PTRACE_KILL PT_KILL#define PTRACE_GETREGS PT_GETREGS#define PTRACE_CONT PT_CONTINUE#define user_regs_struct reg#endifint main(int argc, char *argv[]){pid_t pid;int status;struct user_regs_struct REG; /* эта структураиспользуетсядлячтениясодержимогорегистровобщегоназначенияприиспользованиикомандыPTRACE_GETREGS */if((pid = fork()) == 0) {/*находимся в процессе-потомке, разрешаемтрассировку */ptrace(PTRACE_TRACEME, 0, 0, 0);execl(“son”, ”son”, 0);процесса *//* замещаем тело/* здесь процесс-потомок будет остановленссигналомSIG_TRAP,ожидаякоманды103продолженияпроцесса*/выполненияотуправляющего}/* в процессе-родителе */while (1) {/*ждем,когдаприостановится */отлаживаемыйпроцессwait(&status);/*читаемсодержимоеотлаживаемого процесса */регистровptrace(PTRACE_GETREGS, pid, ®, ®);/* выводим статус отлаживаемого процесса,номер сигнала, который его остановил изначения считанных регистров EIP и ESP */#ifdef BSDprintf("signal = %d, status = %#x, EIP=%#xESP=%#x\n", WSTOPSIG(status), status,REG.r_eip, REG.r_esp);#elseprintf("signal = %d, status = %#x, EIP=%#xESP=%#x\n", WSTOPSIG(status), status,REG.eip, REG.esp);#endifif (WSTOPSIG(status) != SIGTRAP) {if (!WIFEXITED(status)) {/*завершаемвыполнениетрассируемого процесса */ptrace (PTRACE_KILL, pid, 0, 0);}break;}/*разрешаемпроцессу */выполнениетрассируемомуptrace (PTRACE_CONT, pid, 0, 0);}}1045СредстваSystem VмежпроцессноговзаимодействияВсе рассмотренные выше средства взаимодействия процессовне обладают достаточной универсальностью и имеют те или иныенедостатки: так, сигналы несут в себе слишком мало информации ине могут использоваться для передачи сколь либо значительныхобъемов данных; неименованный канал должен быть создан до того,как порождается процесс, который будет осуществлятькоммуникацию; именованный канал, хотя и лишен этого недостатка,как правило предполагает одновременную работу с ним обоихпроцессов, участвующих в коммуникации (хотя это требование иможно частично обойти, используя его в неблокирующем режиме).Поэтому практически все UNIX-системы поддерживают болеемощные и развитые средства межпроцессного взаимодействия, хотяпоявление и развитие этих средств в разных версиях UNIX шлоразными путями.
Рассматриваемую в этой главе группу средствмежпроцессного взаимодействия называют System V IPC17, так какизначально эти средства были реализованы именно в UNIX SystemV, однако к настоящему моменту они включены практически во всеверсии UNIX. System V IPC включает в себя очереди сообщений,семафоры, разделяемую память.Следует отметить, что объекты и методы IPC поддерживаютсястандартом POSIX (хотя они определены не в самом стандартеPOSIX.1, а в дополнении POSIX.1b, описывающем переносимую ОСреального времени), однако, синтаксис их отличается отпредложенного в System V, в частности, используется другоепространство имен.
Далее в этой главе мы рассмотрим методы IPCтак, как они реализованы в System V.5.1 Организация доступа и именования в разделяемыхресурсах5.1.1 Именование разделяемых объектовДля всех средств IPC приняты общие правила именованияобъектов, позволяющие процессу получить доступ к такому объекту.Для именования объекта IPC используется ключ, представляющийсобой целое число. Ключи являются уникальными во всей UNIX-17аббревиатура IPC – это сокращение от английского interprocess communication105системе идентификаторами объектов IPC, и зная ключ длянекоторого объекта, процесс может получить к нему доступ. Приэтом процессу возвращается дескриптор объекта, который вдальнейшем используется для всех операций с ним.
Проведяаналогию с файловой системой, можно сказать, что ключ аналогиченимени файла, а получаемый по ключу дескриптор – файловомудескриптору, получаемому во время операции открытия файла.Ключ для каждого объекта IPC задается в момент его создания темпроцессом, который его порождает, а все процессы, желающиеполучить в дальнейшем доступ к этому объекту, должны указыватьтот же самый ключ.Итак, все процессы, которые хотят работать с одним и тем жеIPC-ресурсом, должны знать некий целочисленный ключ, покоторому можно получить к нему доступ.