Module: wine Branch: master Commit: 3aa266f8f369b064e4298d86b364da3962ef3106 URL: http://source.winehq.org/git/wine.git/?a=commit;h=3aa266f8f369b064e4298d86b3...
Author: Alexandre Julliard julliard@winehq.org Date: Fri May 22 12:47:15 2009 +0200
ntdll: Implement RtlUnwindEx for x86_64.
---
dlls/ntdll/signal_x86_64.c | 92 ++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 89 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 673c2ec..1748221 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -1462,10 +1462,17 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc, /******************************************************************* * RtlUnwindEx (NTDLL.@) */ -void WINAPI RtlUnwindEx( ULONG64 frame, ULONG64 target_ip, EXCEPTION_RECORD *rec, +void WINAPI RtlUnwindEx( ULONG64 end_frame, ULONG64 target_ip, EXCEPTION_RECORD *rec, ULONG64 retval, CONTEXT *context, UNWIND_HISTORY_TABLE *table ) { EXCEPTION_RECORD record; + ULONG64 frame; + RUNTIME_FUNCTION *dir, *info; + PEXCEPTION_ROUTINE handler; + DISPATCHER_CONTEXT dispatch; + CONTEXT new_context; + LDR_MODULE *module; + DWORD size;
/* build an exception record, if we do not have one */ if (!rec) @@ -1478,9 +1485,88 @@ void WINAPI RtlUnwindEx( ULONG64 frame, ULONG64 target_ip, EXCEPTION_RECORD *rec rec = &record; }
- rec->ExceptionFlags |= EH_UNWINDING | (frame ? 0 : EH_EXIT_UNWIND); + rec->ExceptionFlags |= EH_UNWINDING | (end_frame ? 0 : EH_EXIT_UNWIND); + + FIXME( "code=%x flags=%x end_frame=%lx target_ip=%lx\n", + rec->ExceptionCode, rec->ExceptionFlags, end_frame, target_ip ); + + frame = context->Rsp; + while (frame != end_frame) + { + /* FIXME: should use the history table to make things faster */ + + if (LdrFindEntryForAddress( (void *)context->Rip, &module )) + { + ERR( "no module found for rip %p, can't unwind exception\n", (void *)context->Rip ); + raise_status( STATUS_BAD_FUNCTION_TABLE, rec ); + } + if (!(dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE, + IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size ))) + { + ERR( "module %s doesn't contain exception data, can't unwind exception\n", + debugstr_w(module->BaseDllName.Buffer) ); + raise_status( STATUS_BAD_FUNCTION_TABLE, rec ); + } + if (!(info = find_function_info( context->Rip, module->BaseAddress, dir, size ))) + { + /* leaf function */ + context->Rip = *(ULONG64 *)context->Rsp; + context->Rsp += sizeof(ULONG64); + continue; + } + + new_context = *context; + + handler = RtlVirtualUnwind( UNW_FLAG_UHANDLER, (ULONG64)module->BaseAddress, context->Rip, + info, &new_context, &dispatch.HandlerData, &frame, NULL ); + + if ((frame & 7) || + frame < (ULONG64)NtCurrentTeb()->Tib.StackLimit || + frame >= (ULONG64)NtCurrentTeb()->Tib.StackBase) + { + ERR( "invalid frame %lx\n", frame ); + raise_status( STATUS_BAD_STACK, rec ); + } + + if (end_frame && (frame > end_frame)) + { + ERR( "invalid frame %lx/%lx\n", frame, end_frame ); + raise_status( STATUS_INVALID_UNWIND_TARGET, rec ); + } + + if (handler) + { + dispatch.ControlPc = context->Rip; + dispatch.ImageBase = (ULONG64)module->BaseAddress; + dispatch.FunctionEntry = info; + dispatch.EstablisherFrame = frame; + dispatch.TargetIp = target_ip; + dispatch.ContextRecord = context; + dispatch.LanguageHandler = handler; + dispatch.HistoryTable = table; + dispatch.ScopeIndex = 0; /* FIXME */
- FIXME( "code=%x flags=%x not implemented on x86_64\n", rec->ExceptionCode, rec->ExceptionFlags ); + TRACE( "calling handler %p (rec=%p, frame=%lx context=%p, dispatch=%p)\n", + handler, rec, frame, context, &dispatch ); + + switch( handler( rec, frame, context, &dispatch )) + { + case ExceptionContinueSearch: + break; + case ExceptionCollidedUnwind: + FIXME( "ExceptionCollidedUnwind not supported yet\n" ); + break; + default: + raise_status( STATUS_INVALID_DISPOSITION, rec ); + break; + } + } + *context = new_context; + } + context->Rax = retval; + context->Rip = target_ip; + TRACE( "returning to %lx stack %lx\n", context->Rip, context->Rsp ); + set_cpu_context( context ); }