Доброго времени суток. Устанавливаю SEH-обработчик потоку. В нем хочу просто посмотреть состояние регистров на момент возникновения ошибки. Но вместо валидной инфы вижу порнуху (в обоих случаях получения контекста - см. код). Подскажите, где ошибся (хотя есть подозрения, что дело, все-таки, в гребаной самостоятельности Делфей): Код (Text): function _handler(Exception: PExceptionRecord; EstablisherFrame: DWORD; Context: PContext; DispContext: DWORD): DWORD; cdecl; var c: _CONTEXT; begin ShowMessage('EDI: ' + IntToHex(Context.Edi, 8) + #13#10 + 'ESI: ' + IntToHex(Context.Esi, 8) + #13#10 + 'EBX: ' + IntToHex(Context.Ebx, 8) + #13#10 + 'EDX: ' + IntToHex(Context.Edx, 8) + #13#10 + 'ECX: ' + IntToHex(Context.Ecx, 8) + #13#10 + 'EAX: ' + IntToHex(Context.Eax, 8) + #13#10 ); c.ContextFlags := CONTEXT_FULL; GetThreadContext(hThread, c); ShowMessage('GetThreadContext' + #13#10 + 'EDI: ' + IntToHex(C.Edi, 8) + #13#10 + 'ESI: ' + IntToHex(C.Esi, 8) + #13#10 + 'EBX: ' + IntToHex(C.Ebx, 8) + #13#10 + 'EDX: ' + IntToHex(C.Edx, 8) + #13#10 + 'ECX: ' + IntToHex(C.Ecx, 8) + #13#10 + 'EAX: ' + IntToHex(C.Eax, 8) + #13#10 ); end; procedure ThreadProc(lpParam: pointer); stdcall; asm //int 3 push offset _handler xor eax, eax push fs:[eax] mov fs:[eax], esp mov ebx, $12345678 mov [eax], eax end; procedure TForm1.Button3Click(Sender: TObject); var ThId: DWORD; begin hThread := CreateThread(nil, 0, @ThreadProc, nil, 0, ThId); end; Так же, попутно, хочу задать еще два вопроса: 1. Какое значение будет содержать _EXCEPTION_RECORD.ExceptionCode в случае трассировочного исключения? 2. Какое значение следует вернуть функции _handler, чтоб выполнение кода продолжилось со следующей инструкции, после вызвавшей исключение. Интересует как числовое значение, так и сишный хидер с соответствующей константой (а то Сей у меня на данный момент нет)? Заранее спасибо.
Код (Text): {$O+} function _except_handler( ExceptionRecord:PExceptionRecord; EstablisherFrame:Pointer; ContextRecord:PContext; DispatcherContext:Pointer): EXCEPTION_DISPOSITION; cdecl; begin ContextRecord.Eip := __seh.SafeEip; ContextRecord.Esp := __seh.PrevEsp; ContextRecord.Ebp := __seh.PrevEbp; // Tell the OS to restart the faulting instruction Result := ExceptionContinueExecution; end; {$O-}
1. Код (Text): STATUS_BREAKPOINT equ 80000003h STATUS_SINGLE_STEP equ 80000004h У меня вылезало первое, но не исключаю и второе. 2. тут было полнейшее враньё Не обязательно иметь - качай у хатча windows.inc много полезной информации в одном месте. А вопче на форуме и сайте уже куча раз поднималась тема обработки исключений... и причём, оооочень детально, с широкими исследованиями в области.
передается же параметр Context:PCONTEXT, который как раз представляет из себя указатель на контекст. зачем делать GetThreadContext/SetThreadCOntext я не знаю
Тааак... терь я чой-то гоню Код (Text): FORMAT PE GUI 4.0 INCLUDE 'win32wxp.inc' ENTRY start ;EXCEPTION_EXECUTE_HANDLER = 1 ;EXCEPTION_CONTINUE_SEARCH = 0 ;EXCEPTION_CONTINUE_EXECUTION = -1 ; For SEH Kernel ExceptionContinueExecution = 0 ExceptionContinueSearch = 1 ExceptionNestedException = 2 ExceptionCollidedUnwind = 3 EXCEPTION_MAXIMUM_PARAMETERS = 15 SIZE_OF_80387_REGISTERS = 80 MAXIMUM_SUPPORTED_EXTENSION = 512 struct EXCEPTION_POINTERS pExceptionRecord dd ? ContextRecord dd ? ends struct EXCEPTION_RECORD ExceptionCode dd ? ExceptionFlags dd ? pExceptionRecord dd ? ExceptionAddress dd ? NumberParameters dd ? ExceptionInformation dd EXCEPTION_MAXIMUM_PARAMETERS dup(?) ends struct FLOATING_SAVE_AREA ControlWord dd ? StatusWord dd ? TagWord dd ? ErrorOffset dd ? ErrorSelector dd ? DataOffset dd ? DataSelector dd ? RegisterArea db SIZE_OF_80387_REGISTERS dup(?) Cr0NpxState dd ? ends struct CONTEXT ContextFlags dd ? iDr0 dd ? iDr1 dd ? iDr2 dd ? iDr3 dd ? iDr6 dd ? iDr7 dd ? FloatSave FLOATING_SAVE_AREA regGs dd ? regFs dd ? regEs dd ? regDs dd ? regEdi dd ? regEsi dd ? regEbx dd ? regEdx dd ? regEcx dd ? regEax dd ? regEbp dd ? regEip dd ? regCs dd ? regFlag dd ? regEsp dd ? regSs dd ? ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?) ends SECTION '.text' CODE EXECUTABLE READABLE start: xor ebx,ebx push SEHhandler push DWORD [fs:ebx] mov [fs:ebx],esp int3 ; xchg [ebx],ebx ..safe: pop DWORD [fs:ebx] pop edx invoke MessageBox,ebx,sMessage1,sCaption1,MB_OK OR MB_ICONINFORMATION invoke ExitProcess,ebx proc SEHhandler c pExceptionRecord:DWORD, pException:DWORD, pContext:DWORD, pDispatcherContext:DWORD xor ebx,ebx invoke MessageBox,ebx,sMessage2,sCaption2,MB_OK OR MB_ICONINFORMATION mov eax,[pContext] mov [eax + CONTEXT.regEip],..safe ; invoke SetThreadContext,-2,[pContext] ; áåç ýòîãî íå ðàáîòàåò, ò.å. çàöèêëèâàåòñÿ íà ýêñåïøåíå!!! ; Ошибка была тут! ; mov eax,EXCEPTION_CONTINUE_EXECUTION mov eax,ExceptionContinueExecution ret endp SECTION '.idata' DATA READABLE WRITABLE IMPORT library kernel32,'KERNEL32.DLL',\ user32,'USER32.DLL' INCLUDE 'api\kernel32.inc' INCLUDE 'api\user32.inc' SECTION '.rdata' DATA READABLE sMessage1 TCHAR 'After exception',0 sCaption1 TCHAR 'Repaired',0 sMessage2 TCHAR 'In exception',0 sCaption2 TCHAR 'Repairing',0 Собсно не работает без явной установки контекста через ф-ю. Что за гон?! XP pre SP3, патчи на ядре и проч муть, связанная с безопасностью... файл аттачу для удобства компилирования. Это только у меня так он работате "корректно" или так задумао? Прошу прояснить или ткнуть носом. Спс. Ошибка устранена.
Пардон, разобрался! Гон был в следующем: "Правильные" константы выглядят следующим образом А "неправильные" фтопку! Терь возник другой вопрос - где ж тогда используются те самые "неправильные" константы? Оба варианта можно найти в хедерах... вот вилы то! Вопрос снимается - разобрался... точнее съел кашу из головы. Первые используются в мануальном SEH'e, вторые в с нотации __except() и в нек-рых апи. пример ниже.
// // Exception disposition return values. // EXCEPTION_DISPOSITION = DWORD; const ExceptionContinueExecution = 0; ExceptionContinueSearch = 1; ExceptionNestedException = 2; ExceptionCollidedUnwind = 3; упс, опоздал, слишком долго была открыта страничка в офлайне прежде чем прочел
Asterix Понял. Значит нужно просто сменить EIP и ESP. asmfan Ну, если учесть, что я пишу на АСМе, а Си не люблю, то наверняка этот вайл у меня есть. Просто я не знал, как называются константы. Great Ты же прочитал сам вопрос - "вместо валидной инфы вижу порнуху (в обоих случаях получения контекста - см. код)". Так что это было для проверки. Так же в процедуре ThreadProc я, перед вызовом исключения, заношу в регистр EBX значение 0x12345678 - тоже для проверки. rain В первую очередь. Не прочитав, не полез бы с вопросами. Мужики, дык на мой основной вопрос, собственно, ни кто не ответил... Попробуйте запустить мой код у себя. По идее, MessageBox должен вывести значение регистра EBX, равное 0x12345678. Но этого не происходит...
Именно поэтому ваш пример на Delphi ? ваш я не запускал, но мой вроде работает Код (Text): program SEH; uses Windows; type _SEH = record SafeEip:DWORD; // The offset where it's safe to continue execution PrevEsp:DWORD; // The previous value of esp PrevEbp:DWORD; // The previous value of ebp end; // // Exception disposition return values. // EXCEPTION_DISPOSITION = DWORD; const ExceptionContinueExecution = 0; ExceptionContinueSearch = 1; ExceptionNestedException = 2; ExceptionCollidedUnwind = 3; var format_string : PChar = 'EAX = %08lX' + #0; __seh : _SEH; label _SafePlace; {$O+} function _except_handler( ExceptionRecord:PExceptionRecord; EstablisherFrame:Pointer; ContextRecord:PContext; DispatcherContext:Pointer): EXCEPTION_DISPOSITION; cdecl; var Buff: PChar; _EAX: DWord; begin ContextRecord.Eip := __seh.SafeEip; ContextRecord.Esp := __seh.PrevEsp; ContextRecord.Ebp := __seh.PrevEbp; _EAX := ContextRecord.Eax; GetMem(Buff, 64); asm push _EAX push format_string push Buff call wsprintf add esp, 0Ch end; MessageBox(0, Buff, nil, MB_OK or MB_ICONINFORMATION); FreeMem(Buff); // Tell the OS to restart the faulting instruction Result := ExceptionContinueExecution; end; {$O-} begin asm push OFFSET _except_handler push DWORD PTR fs:[0] // address of next ERR structure mov fs:[0], esp // give FS:[0] the ERR address just made mov __seh.SafeEip, OFFSET _SafePlace mov __seh.PrevEsp, esp mov __seh.PrevEbp, ebp mov eax, $12345678 db 0CCh end; _SafePlace: asm pop DWORD PTR fs:[0] // restore next ERR structure to FS:[0] add esp, 4 // throw away rest of ERR structure end; end.
Asterix Немного неверно я выразился. Скажу так - пишу на всем, кроме Сей. На Сях читаю. Сейчас пойду тестировать предоставленный вами код. Да, я думаю, все же, не стоит на "Вы" - мы же тут все свои...
Потестировал. Все работает. Так что вопрос можно считать закрытым. Только вот не пойму - а в чем же концептуальная разница между приведенным и моим кодом? Ерунда, вообщем, какая-то...