Таблицы исключений
Ключом к определению источника ошибки обращения к странице является ограниченность круга вызовов, которые ядро может сделать, для обращения к адресному пространству процесса. Лишь небольшая группа функций и макросов, описанных в предыдущем разделе, используется для этих целей. Следовательно, если исключение вызвано недопустимым параметром, то инструкция, приведшая к исключению, обязательно содержится в одной из функций или была сгенерирована макросом. Количество инструкций, обращающихся к адресному пространству пользователя, весьма невелико.
Поэтому не составляет труда поместить адрес каждой инструкции ядра, обращающейся к адресному пространству процесса, в структуру, называемую таблицей исключений. Если мы сделаем это, все остальное просто. Когда в режиме ядра возникнет исключение ошибка обращения к странице”, обработчик do page fauit просмотрит таблицу исключений. Если она содержит инструкцию, вызвавшую исключение, значит, причина ошибки в недопустимом параметре системного вызова. В противном случае причины более серьезные.
В Linux определено несколько таблиц исключений. Главная таблица исключений генерируется компилятором С при сборке образа ядра. Она хранится в
секции ex table сегмента кода ядра, и ее начальный и конечный адреса
идентифицируются символами, тоже сгенерированными компилятором С:
start ex_table И stop ex_table.
Кроме того, каждый динамически загружаемый модуль ядра содержит свою локальную таблицу исключений. Эта таблица автома
тически сгенерируется компилятором С при сборке образа модуля, и она загружается в память, когда модуль подключается к работающему ядру.
Каждая запись таблицы исключений представляет собой структуру
exception_table_entry, СОСТОЯЩУЮ ИЗ Двух ПОЛеЙ:
- insn— линейный адрес инструкции, которая обращается к адресному пространству процесса;
- fixup— адрес кода на языке ассемблера, который выполняется, когда ошибка обращения к странице возникает "по вине” инструкции, расположенной по адресу insn.
Код обработки исключения состоит из нескольких ассемблерных инструкций, решающих проблему, вызвавшую исключение. Как мы увидим далее в этом разделе, обработка обычно заключается во вставке последовательности инструкций, заставляющих служебную процедуру возвратить процессу режима пользователя код ошибки. Эти инструкции, как правило, определенные в том же макросе (функции), который обращается к адресному пространству процесса, помещаются компилятором С в отдельную секцию сегмента кода ядра, называемую .fixup.
Функция search exception tabies о применяется для поиска указанного адреса во всех таблицах исключений. Если адрес находится в какой-либо таблице, функция возвращает указатель на соответствующую структуру except ion_t abl e_en t г у; в противном случае она возвращает NULL. Таким образом, обработчик do page f auit () выполняет следующие операторы:
if ((fixup = search_exception_tables(regs->eip))) { regs->eip = fixup->fixup; return 1;}
Поле regs->eip содержит значение регистра eip, сохраненное в стеке режима ядра, когда возникло исключение. Если значение регистра (указатель на инструкцию) находится в таблице исключений, обработчик do page fault заменяет сохраненное значение на адрес из записи, которую возвратила функция search exception tabies . Затем обработчик исключения "ошибка обращения к странице" завершает свою работу, а прерванная программа возобновляет свою с того, что выполняет код обработки.
Предыдущая страница | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | Следующая страница