Techwiki:SEH64

From ReactOS Wiki
Jump to: navigation, search

Function Table

The function table can be found in the .pdata section of the executable. It is an array of RUNTIME_FUNCTION structures. NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION] is the corresponding data directory entry. Its VirtualAddress member points to the beginning of this section, its Size member divided by sizeof(RUNTIME_FUNCTION) gives the number of entries.

typedef struct _RUNTIME_FUNCTION
{
    ULONG BeginAddress;
    ULONG EndAddress;
    ULONG UnwindData;
} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;

BeginAddress is the RVA of the beginning of the corresponding function. EndAddress is the RVA of the end of the corresponding function. UnwindData is the RVA of the UNWIND_INFO structure belonging to this function.

All RUNTIME_FUNCTION entries are sorted, beginning with the smallest address and never overlapping. There may be gaps though. If an address is not found inside the table, it is supposed to be a leaf function and RSP points to the functions return address.

The table that corresponds to a certain address can be found using

PRUNTIME_FUNCTION
NTAPI
RtlLookupFunctionTable(
    IN DWORD64 ControlPc,
    OUT PDWORD64 ImageBase,
    OUT PULONG Length);

The function entry can be found by using

PRUNTIME_FUNCTION
NTAPI
RtlLookupFunctionEntry(
    IN DWORD64 ControlPc,
    OUT PDWORD64 ImageBase,
    OUT PUNWIND_HISTORY_TABLE HistoryTable);

Unwind Data

The UnwindData member of the RUNTIME_FUNCTION entry is the RVA of an UNWIND_INFO structure.

typedef struct _UNWIND_INFO
{
    UBYTE Version:3;
    UBYTE Flags:5;
    UBYTE SizeOfProlog;
    UBYTE CountOfCodes;
    UBYTE FrameRegister:4;
    UBYTE FrameOffset:4;
    UNWIND_CODE UnwindCode[1];
/*  union
    {
        OPTIONAL ULONG ExceptionHandler;
        OPTIONAL ULONG FunctionEntry;
    };
    OPTIONAL ULONG ExceptionData[];
*/
} UNWIND_INFO, *PUNWIND_INFO;

Version

Should be 1

Flags

Can be can be one of the following values
#define UNW_FLAG_NHANDLER 0
#define UNW_FLAG_EHANDLER 1
#define UNW_FLAG_UHANDLER 2
#define UNW_FLAG_FHANDLER 3 // inofficial
#define UNW_FLAG_CHAININFO 4

SizeOfProlog

Size of the functions prolog in bytes.

CountOfCodes

Number of UNWIND_CODE entries in this structure.

FrameRegister

FrameOffset

ExceptionHandler

RVA of the language specific handler. See below.

ExceptionData

This data is specific to the language specific handler and a pointer to this data is passed to the handler in the DISPATCHER_CONTEXT structure.

The exception handler for RtlpExecuteHandlerForUnwind (RtlpUnwindHandler) has a Flags value of 3. The handler is responsible for collided unwinds, see http://www.nynaeve.net/?p=107

The Language specific handler

This function must correspond to the following prototype:

typedef EXCEPTION_DISPOSITION
(*PEXCEPTION_ROUTINE)(
    IN PEXCEPTION_RECORD ExceptionRecord,
    IN ULONG64 EstablisherFrame,
    IN OUT PCONTEXT ContextRecord,
    IN OUT PDISPATCHER_CONTEXT DispatcherContext);

_C_specific_handler

In this case ExceptionData is a SCOPE_TABLE structure.

typedef struct _SCOPE_TABLE {
    ULONG Count;
    struct
    {
        ULONG BeginAddress;
        ULONG EndAddress;
        ULONG HandlerAddress;
        ULONG JumpTarget;
    } ScopeRecord[1];
} SCOPE_TABLE, *PSCOPE_TABLE;

_CxxFrameHandler3

This function is exported by msvcr90.dll. It is used with C++ exceptions (try/catch). In this case the Flags field in the UNWIND_INFO structure is 3. http://multitouchvista.codeplex.com/Thread/View.aspx?ThreadId=51520

int
__CxxFrameHandler3(
    EHExceptionRecord * pExcept,
    EHRegistrationNode * pRN,
    void * pContext,
    void * pDC);

struct EHExceptionRecord
{
    EXCEPTION_RECORD ExceptionRecord;
    ???
};

struct EHRegistrationNode (FIXME: this is x86)
{
  EHRegistrationNode *prev;
  DWORD ehhandler_code;
  DWORD id;
  DWORD saved_ebp;
};

The ExceptionData is an RVA to a FuncInfo structure in the rdata segment. Pointers are in fact RVAs.

struct FuncInfo
{
    DWORD magicNumber;              // compiler version
    int maxState;                   // number of entries in unwind table
    UnwindMapEntry* pUnwindMap;     // table of unwind destructors
    DWORD nTryBlocks;               // number of try blocks in the function
    TryBlockMapEntry* pTryBlockMap; // mapping of catch blocks to try blocks
    DWORD nIPMapEntries;            // not used on x86
    DATA3* pIPtoStateMap;           // not used on x86
    union
    {
        ESTypeList* pESTypeList;    // VC7+ only, expected exceptions list (function "throw" specifier) 
        int EHFlags;                // VC8+ only, bit 0 set if function was compiled with /EHs
    }
};
#define MAGIC_VC  0x19930520 // up to VC6
#define MAGIC_VC7 0x19930521 // VC7.x(2002-2003)
#define MAGIC_VC8 0x19930522 // VC8 (2005)
struct UnwindMapEntry
{
    int toState;        // target state
    void (*action)();   // action to perform (unwind funclet address)
};
struct TryBlockMapEntry
{
    int tryLow;
    int tryHigh;    // this try {} covers states ranging from tryLow to tryHigh
    int catchHigh;  // highest state inside catch handlers of this try
    int nCatches;   // number of catch handlers
    HandlerType* pHandlerArray; //catch handlers table
};
struct HandlerType
{
    DWORD adjectives;// 0x01: const, 0x02: volatile, 0x08: reference
    TypeDescriptor* pType;// RTTI descriptor of the exception type. 0=any (ellipsis)
    int dispCatchObj;// ebp-based offset of the exception object in the function stack. 0 = no object (catch by type)
    void* addressOfHandler;// address of the catch handler code. returns address where to continues execution (i.e. code after the try block)
    ??? DWORD dw4;// 0x38
};
typedef struct
{
    RVA ThrowingFunction;
    DWORD dw04; // 0xffffffff
    RVA ScopeBegin;
    DWORD dw0c; // 0x0
    RVA EndScope;
    DWORD dw14; // 0xffffffff
    RVA Sub1;
    DWORD dw1c; // 0
    RVA Sub2;
    DWORD dw1c; // 1
    RVA Sub3;
    DWORD dw1c; // 0
    ... more RVA/DWORD combinations for more catch blocks
} DATA3;

References