Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Находится ли адрес регионе памяти задачи?
Yes
good.area: Рис. 4.15. Ошибка страницы 2 pgdjc = init__mm.pgd + index; 491 if (! pgd_present(*pgd_k)) goto no_context; pmd = pmd_offset(pgd, address); pmd_k = pmd_offset (pgd_k, address); if (! pmd_j? resent (*pmd_k) ) goto no_context; set_prad(pmd, *pmd_k); pte_k = pte_offset__kernel(pmd_k, address) 506 if (! pte_present(*pte_k)) 507 goto no__context; 508 return; 509 } Строки 473-509 Глобальная директория страницы текущего процесса связана (с помощью сгЗ) и сохранена в переменную pgd, а глобальная директория страницы ядра связана с pgd_k (аналогично переменным pmd и pte). Если проблемный адрес неверен для системы подкачки ядра, код переходит к метке no_context:. В противном случае текущий процесс использует pgd ядра. Теперь посмотрим на метку good__area:. В этой точке мы знаем, что область памяти, хранящая проблемный адрес, находится в адресном пространстве процесса. Теперь нам нужно убедиться, что разрешение доступа верно. Рис. 4.17 показывает диаграмму этой работы. Глава 4 • Управление памятью
Рис. 4.16. Метка vmallocjault arch/i38б/mm/fault.с 2 90 good_area: 291 info.si_code = SEGV_ACCERR; 2 92 write = 0; 2 93 switch (error_code & 3) { 294 default: /* 3: write, present */ /* fall through */ 3 00 case 2; /* write, not present */ 3 02 goto bad_area; 303 write++; 3 04 break; 3 05 case 1: /* read, present */ 3 06 goto bad_area; 3 07 case 0: /* read, not present */ 308 if (! (vma-> vm_flags & (VM_READ | VM_EXEC))) 3 09 goto bad_area; 310 } Строки 294-304 Если ошибка страницы произошла в записываемой области памяти (вспомните, что в этом случае самый левый бит, error__code, равен 1), мы проверяем, является ли область памяти доступной для записи. Если нет, мы получаем несоответствие разрешений и переходим к метке bad_area:. Если запись возможна, мы переходим к строке case и вызываем handle_mm_fault () с локальной переменной, установленной в 1. Ошибка страницы Строки 305-309 Если ошибка памяти вызвана доступом для чтения или выполнения и страница присутствует, мы переходим к метке bad_area:, так как это явное нарушение прав доступа. Если страницы нет, мы проверяем, имеет ли область памяти разрешение за чтение или выполнение. Если нет, мы переходим к метке bad__area:, так как, если бы мы нашли страницы, разрешение не позволило бы выполнить операцию. Если нет, мы переходим к следующему случаю и выполняем handle_mm_fault О с локальной переменной, установленной в 0.
Рис. 4.17. Метка good area Следующая метка помечает код, в который мы попадаем, когда проверка разрешения подтверждается. Этому случаю соответствует метка survive:. arch/i38б/mm/fault.с survive: 318 switch (handle__mm_fault(mm, vma, address, write)) { case VM_FAULT_MINOR: tsk-> min_flt++; break; case VM_FAULT_MAJOR: tsk-> raaj_flt++; break; case VM_FAULT_SIGBUS: goto do_sigbus; Глава 4 • Управление памятью case VM_FAULT_OOM: goto out_of_memory; 329 default: BUG(); } Строки 318-329 Функция handle_mm_f ault () вызывается для текущего описателя памяти (mm), т. е. описателя области проблемного адреса независимо от того, доступна ли эта область для записи или для чтения-исполнения. Конструкция switch перехватывает управление, если мы не смогли обработать ошибку, для того чтобы функция смогла нормально завершиться. Следующий блок кода описывает поток выполнения для метки bad_area и bad_area_no_semaphore. При переходе к этой точке нам известно следующее: 1. Породивший ошибку памяти адрес не является адресом пространства процесса, так как мы проверили его область памяти и не нашли там искомое. 2. Породивший ошибку адрес не находится в адресном пространстве процесса и регионе, до которого оно может наращиваться. 3. Адрес, породивший ошибку памяти, находится в адресном пространстве процесса, но не имеет разрешения для доступа к памяти, соответствующего выполнению желаемого действия. Теперь нам нужно определить, произведен ли доступ из режима ядра. Следующий код и рис. 4.18 демонстрирует поток выполнения этой метки. arch/i38б/mm.fault.с 348 bad_area: 349 up_read (& mm- > mmap_s em); 351 bad_area_nosemaphore: 3 52 /* Доступ пользовательского режима порождает SIGSEGV */ 3 53 if (error_code & 4) { 354 if (is_prefetch(regs/ address)) 3 55 return; 3 57 tsk-> thread.cr2 = address; 3 58 t sk-> thread, err or__code = error_code; 3 59 tsk-> thread.trap_no = 14; 3 60 info.si_signo = SIGSEGV; 3 61 info.si_errno = 0; 3 62 /* info.si_code установлен выше */ Ошибка страницы 3 63 info.si_addr = (void Maddress; 364 force_sig_info(SIGSEGV, & info, tsk); 3 65 return; 366 } Строка 348 Функция up_jread () снимает блокировку чтения с семафора описателя памяти процесса. Обратите внимание, что мы просто перешли к метке bad_area после того, как поставили блокировку семафора описателя памяти и просмотрели его область памяти на предмет нахождения в адресном пространстве процесса нашего адреса. В противном случае мы переходим к метке bad_area_no_semaphore. Единственная разница между этими двумя случаями заключается в установке блокировки семафора. Строки 351-353 Так как адрес не находится в адресном пространстве, мы проверяем, была ли ошибка сгенерирована в пользовательском режиме. Если вы вспомните табл. 4.7, значение error_code означает, что ошибка произошла в пользовательском режиме. Строки 354-366 Мы определили, что ошибка произошла в пользовательском режиме, и поэтому нам нужно послать сигнал SIGSEGV (прерывание 14).
Рис. 4.18. Метка bad area Следующий фрагмент кода описывает поток обработки метки no_context. Когда мы переходим в эту точку, мы знаем следующее: • одна из таблиц страниц потеряна; • доступ к памяти произведен в режиме ядра. Глава 4 • Управление памятью Рис. 4.19 иллюстрирует диаграмму потока метки no_context. Arch/ i3 8 б /mm/ fault. с 388 no_context: 390 if (fixup_exception(regs)) return; 432 die(" Oops", regs, error_code); bust_spinlocks(0); do__exit (SIGKILL); Строка 390 Функция f ixup_exception () использует eip, передаваемый для поиска в таблице исключений соответствующей инструкции. Если инструкция в таблице найдена, она уже должна быть откомпилирована с помощью «скрытого» встроенного кода обработки. Обработчик ошибки страницы do_page_fault () использует код обработки ошибки как адрес возврата и переходит по этому адресу. Затем код может выставить флаг ошибки. Строка 432 Если в таблице исключений нет вхождения для соответствующей инструкции, код выполняет переход по метке no_context и завершается выводом на экран oops.
Рис. 4.19. Метка по context Популярное:
|
Последнее изменение этой страницы: 2016-03-25; Просмотров: 769; Нарушение авторского права страницы