Как сделать полноценный SEH

Kernel architecture questions
  • Засыпаю, посему обрывки мыслей:

    ИМХО то как Sexual Exception Handler сделан в Win (FS:0) - не лучший способ. Для меня предпочтительнее интерфейс UNIX (POSIX) сигналов. Так же нужно подумать о возможности вложенных обработчиков (очередь обратоки, не обработал крайний - передается предыдущему, и т.д. вплоть до системного - просто прикрывающего процесс, как сейчас ). Ещё нужно не забыть дать возможность установки выделенного стека для обработчика, простой пример: исключение ESP - на границе памяти, pop *... Ну и раз уж мы отдаем обработку исключений приложению, и система у нас мультизадачная, то и двойного исключения при ошибке в пользовательском обработчике (например затирание кода...), аппаратно возникать не будет, это надо отслеживать программно (новое состояние процесса?). Кроме того с сигналами можно сделать и человеческий таймер, и как ни как это IPC.
  • Дык время-то еще детское (было) :D
    Ну ты главное проснувшись - продолжи :)

    1) Про FS:0 спорить не буду. Да, как-то и не принято, как мне показалось, в KoApi, чтобы ядро само аллоцировало память, и хитро возвращало ее потоку... Даже стек при создании потока - проблемы пользователя. Ну так и пущай, к примеру, при создании потока в аргументах идет не только адрес вершины стека, но и его дна. А там и будет располагаться TLS. В котором одним из значений и будет номер исключения...

    2) Ну если не FS:0, то может быть некий фиксированный адрес в адресном пространстве потока??? Точнее, одно из полей хедера. Что сразу приводит к следующей версии хедера, а в этом поле исходно (design-time) и будет прошиваться адрес TLS стартового потока приложения. Ну а do_change_task тупо, но честно, будет писать туда адрес текущего - не супер и работа-то...
    : Кстати говоря, у меня давно было желание про следующую версию хедера, чтобы одним из полей был адрес таблицы импорта....

    3) Про POSIX - должной эрудицией не обладаю... Но мне пока кажется: мухи - отдельно, котлеты отдельно. Способы раскрута, и место сохранения информации для этих раскрутов - это дело третьего кольца. Про системную библиотеку говорить можно бесконечно... Где-то уже говорил, что это должно получиться (имхо) вовсе не виндячие user32, а наоборот - больше похожее на некую визуальную библиотеку + некую системную некого языка. Чтобы для запуска пустой формы было достаточно двух операций: создания некого апплета, и запуска его метода Run :wink:
    А попробуй такое сделать - сразу же упрешься в ограничения KoApi
    И seh - один из таких вопросов, где сразу упираешься. Ну вот, я со стороны ядра и пытаюсь потихоньку чистить ситуацию...

    4) Как-то меня не очень напрягают повторные исключения... В том смысле, что делай некий супер стек, не делай его - все равно пользователь сумеет уронить приложение. А зачем платить больше, если нет разницы :)
    Но, согласен. Некий флаг работы в исключении - заводить в APPDATA будет нужно. Ну типа, в основном режиме работает фильтр перехвата, а перехвативши - он как бы и "нулевой", и любое исключение, это "Process - forced terminate" (ну или debug_notification)

    5) Про таймеры... Ну опиши конкретно свое видение интерфейса. Вплоть до номеров ф-й/подф-й...
    Возьму да сделаю... Обсудивши коротенько
    Типа, я уже самый большой специалист по "правильным ожиданиям" :lol:
  • Если tls не очень большой можно сделать персональную страницу для каждого потока и мапить её при переключении контекста.
  • Serge, Вы имеете в виду фиксированные адреса в приложении для всех потоков ???
    Тогда какие....
    В смысле, как бы это могло выглядеть со стороны пользователя :?:

    Хотя, если напихаем туды барахла на 4К это уже больше на винду будет похоже, чем на Kolibri :)
    Мне пока понятнее наоборот - значительно меньше, чем 4К
  • Приложение определяет адрес и размер tls (можно и через заголовок) а ядро для каждого потока создаст персональную страницу и будет мапить её на этот адрес. В этом случае доступ к данным tls будет для программиста таким же простым как и к обычным данным, без разных ухищрений.

    для fasm

    Code: Select all

    
    tls          dd tls_begin        
    tls_size   dd tls_end-tls_begin
    
    align 4096
    tls_begin:
    
    var1 dd ?
    var2 dd ?
    var3 dd ?
    
    align 4
    tls_end:
    
    для gcc
    int local_data __attribute__ ((section (".tls))) = 0;

    Большинство компиляторов яву умеют размещать данные в именованых секциях. В крайнем случае данные можно объявить extern а tls секцию сделать на асме.
  • Угу, согласен. Доступ будет проще на одну косвенность...
    В том варианте, что я думал, программисту очень просто добраться до переменной, которая лишь указывает на TLS (зато ядру практически ничего делать не надо)

    Чего смущает: мы скидываем на пользователя выравнивание этого блока (как по адресу, так и по размеру) на пользователя
    Ошибется разок, захватив 4К-блоком по настоящему глобальные переменные - вот намучается-то коллега :)
    Подумать надо......


    Такой вопрос: а насколько мы связаны в своих фантазиях проблемами совместимости :?:
    В смысле, использовал ли кто уже имеющиеся хуки на FPU и SSE :?:
    Думаю себе... Ну предположим, в калькуляторе (или еще где) мы решили посчитать логорифм отрицательного числа...
    Оказываемся в хуке, и чего мы там должны делать ???
    Простой ret, это повторение пройденного. Следовательно, надо делать что-то типа ljmp (играться со стеком, в общем) в то место, где эти неправильные данные формировались, и чего-то каким-то макаром исправлять
    Даже интересно посмотреть бы...
  • На работу ядра ошибка не повлияет, это главное. А страховать программиста от всех возможных ошибок ядро не обязано.

    Обработка исключений FPU есть в Open Watcom. Всё работает и протестировано. fpeinth.asm - пример обработчика.
  • Кстати там эмулируются сигналы POSIX. Библиотека устанавливает свой первичный обработчик. Он производит анализ исключения FPU. Потом из таблицы обработчиков сигналов вызывается пользовательский обработчик если он установлен.

    Code: Select all

    void __sigfpe_handler( int fpe_type )
    {
        __sig_func  func;
        
        func = SignalTable[ SIGFPE ];
        if( func != SIG_IGN  &&  func != SIG_DFL  &&  func != SIG_ERR ) {
            SignalTable[ SIGFPE ] = SIG_DFL;      /* 09-nov-87 FWC */
            (*(__sigfpe_func)func)( SIGFPE, fpe_type );        /* so we can pass 2'nd parm */
        }
    }
  • Уточню вопрос :)
    Реально ли сделать изменения в системной библиотеке Open Watcom, чтобы она не пользовалась f68:15/18, но предоставляла те же (вообще-то - большие) возможности прикладному программисту :?:
    Грубо говоря, чтобы он ничего незаметил...
    Естественно, после того, как мы закончим нашу постановочную часть.

    Откуда ноги растут
    Эти хуки сегодня локализованы в строках 135-141 файла sys32.inc. Теперь же просто в глаза бросается, что вместо этого надо лепить один универсальный.
    Можно конечно пытаться оставить и то, и другое... Но не факт, что это получится полноценно и без костылей. Да и смотреться будет типа: "здесь играть, здесь не играть, а здесь рыбу заворачивали..."
    Вопрос исключений при делении на 0, и программистам на Open Watcom - тоже не безынтересен должен быть...

    Вот еще....
    Поясните, если можно, Ваши магические слова про POSIX, и егойные "сигналы". На 100% не надо, скажем так - "тремя фразами", но чтобы хоть базовое понимание осталось...
    Уровень моей образованности примерно таков: с nix-ами сроду дело не имел. Сделать любого типа перехваты исключений в винде через winApi - да без проблем (как это делается конкретно на VC - тоже знаю).
    А вот чтобы поднять это на ЯВУ - мегабайты кодов же перелопатить надо :(
    Фиг поймешь, где там чего начинается, и где заканчивается...
    На ассемблере оно как-то "по-настоящему" и поэтому значительно более понятно.
    Serge wrote:А страховать программиста от всех возможных ошибок ядро не обязано
    Дык собственно, я не о страховке говорил...
    Добавлю даже, что и бесполезно.
    Просто смотрю, есть два варианта... Оба вроде должны быть работоспособны.
    Какие есть факторы: а) насколько это вызывает суету в ядре при переключениях б) насколько это вредоносно, или наоборот - удобно пользователю.
    Вот и все :)
    Для себя - я еще и сам не понял окончательно. Может и еще какие факторы есть, кроме вышепречисленного, и более приоритетные
    Будем спешить не торопясь...
  • Не уверен что нужен именно один универсальный. #gpf, #pf это одно, а исключение fpu или sse совсем другое. Валить всё в одну кучу - только усложнять код. Фактически получится что сначала ядро сгребает все исключения вместе чтобы вызвать одну единственную функцию, а потом функция должна снова разобрать эти исключения и вызвать для каждого свой обработчик. Ненужная двойная работа.

    Исключения POSIX подробно описаны в gnu libc manual
  • Serge, дык ты возьми и сравни.

    Это раньше была двойная работа. Можно даже сказать, что очень много двойной работы. Да и не всегда одинаково эта, одна и та же работа, в разных местах выполнялась...
    А #pf и так