include aoalib.inc include aoaExcepts.inc .code ; genericLSH is a generic language-specific ; handler that gets called by a procedure-specific ; handler. This procedure has the following ; parameters: ; ; RCX: pExceptionRecord (Windows supplies this) ; RDX: pEstablisherFrame (Windows supplies this) ; R8: pDispatcherContext (Windows supplies this) ; R9: pDispatcherContext (Windows supplies this) ; R10: pScopeTable (procedure-specific handler ; supplies this). rcxER textequ <(ExceptionRecord_t ptr [rcx])> rcxDC textequ <(DispatcherContext ptr [rcx])> r8SC textequ <(scopeTable ptr [r8])> genericLSH proc pExceptionRecord: qword, \ pEstablisherFrame: qword, \ pContextRecord: qword, \ pDispatcherContext:qword, \ pScopeTable: qword ; Note: 1 qword + 2 dwords leave stack 16-byte aligned. local scPtr: qword local count[2]: dword ; shadowStorage must always be last so it is on the ; bottom of the stack: local shadowStorage[64]:byte ; Try and use volatile registers throughout this ; procedure so we don't have to deal with saving ; and restoring them. Begin by saving the volatile ; (parameter) register values into the shadow locations ; on the stack. mov pExceptionRecord, rcx mov pEstablisherFrame, rdx mov pContextRecord, r8 mov pDispatcherContext, r9 mov pScopeTable, r10 ; If the exception is not continuable, quit the program. cmp rcxER.ExceptionFlags, EXCEPTION_NONCONTINUABLE jne isCont ; If it's non-continuable (why are we even here?), ; then quit the process ExitPgm: mov rcx, 1 call ExitProcess ; Bail if this is an unwind operation; this ; procedure-specific handler doesn't deal with that. isCont: mov eax, ExceptionContinueSearch test dword ptr rcxER.ExceptionFlags, \ EXCEPTION_UNWIND ;66h jnz exitLSH ; Set up for the search loop. On entry to this procedure, ; pScopeTable contained a pointer to a ScopeTable ; record that has the following form: ; ; count:dword ; ; scArray scopeTable count dup ({}) ; ; (scArray is a variable-sized array with 1 or more ; scopeTable records in it). ; ; Each scopeTable entry as the following: ; ; scopeTable struct ; exType dword 2 dup (?) ; beginAddress qword ? ; endAddress qword ? ; jumpTarget qword ? ; finallyCode qword ? ; scopeTable ends execExceptHndlr: mov rcx, pExceptionRecord mov edx, rcxER.ExceptionCode mov rcx, pDispatcherContext mov rcx, rcxDC.ControlPc mov r8, pScopeTable mov eax, [r8] ;Get element count add r8, 4 ;Point at 1st element mov scPtr, r8 mov count, eax ; For each element in the array of scopeTable records, ; see if the interrupted RIP address (held in RCX) ; is less than the beginAddress field, greater or ; equal to the endAddress field, or that the ; exception code (in edx) doesn't match the value ; in the exType field. If any of these conditions ; exist, move on to the next element of the scopeTable ; array. searchScps: ; See if we're within the range of the protected ; try block: cmp rcx, [r8].scopeTable.beginAddress jb cantHandle cmp rcx, [r8].scopeTable.endAddress jae cantHandle ; See if the exception type matches: cmp [r8].scopeTable.exType, 0 je HandleException cmp edx, [r8].scopeTable.exType je HandleException cantHandle: add r8, sizeof scopeTable dec count jnz searchScps ; If we ran out of entries in the scopeTable array: mov eax, ExceptionContinueSearch jmp exitLSH ; Call RtlUnwind to unwind the stack and transfer ; control to the actual exception handler code. ; ; RtlUnwind has the following parameters: ; ; RCX: target frame (pEstablisherFrame passed to this code) ; RDX: Address of the handler code (found at ; r8SC.jumpTarget) ; R8: pExceptionRecord (passed to this code) ; R9: Return value that is passed on to the ; exception handler in RAX. HandleException: mov rdx, r8SC.jumpTarget mov r8, pExceptionRecord mov rcx, pEstablisherFrame ; This code is going to pass the pointer to ; the exception record to the handler, as that's ; probably the most useful piece of information ; it can have. Remember, this value shows ; up in RAX in the actual exception handler. mov r9, r8 call RtlUnwind ; The code should never return from RtlUnwindEx ; unless there was an error. In that case, ; abort the program. mov rcx, 1 call ExitProcess ; Exit here if this procedure can't handle ; the exception. exitLSH:: ret genericLSH endp end