UNW_FLAG_NHANDLER = 0
UNW_FLAG_EHANDLER = 1
UNW_FLAG_UHANDLER = 2
UNW_FLAG_CHAININFO = 4
__SEH64_REG.rax = 0
__SEH64_REG.rcx = 1
__SEH64_REG.rdx = 2
__SEH64_REG.rbx = 3
__SEH64_REG.rsp = 4
__SEH64_REG.rbp = 5
__SEH64_REG.rsi = 6
__SEH64_REG.rdi = 7
__SEH64_REG.r8 = 8
__SEH64_REG.r9 = 9
__SEH64_REG.r10 = 10
__SEH64_REG.r11 = 11
__SEH64_REG.r12 = 12
__SEH64_REG.r13 = 13
__SEH64_REG.r14 = 14
__SEH64_REG.r15 = 15
virtual at -510
__SEH64_UNWIND_CODE::
dw 255 dup(?)
assert ($ = 0)
end virtual
; The UNWIND_INFO structure tells how the portion of code should be handled. Here's the declaration I found on MSDN:
; typedef union _UNWIND_CODE {
; struct {
; UBYTE CodeOffset;
; UBYTE UnwindOp : 4;
; UBYTE OpInfo : 4;
; };
; USHORT FrameOffset;
; } UNWIND_CODE, *PUNWIND_CODE;
;
; typedef struct _UNWIND_INFO {
; UBYTE Version : 3;
; UBYTE Flags : 5;
; UBYTE SizeOfProlog;
; UBYTE CountOfCodes;
; UBYTE FrameRegister : 4;
; UBYTE FrameOffset : 4;
; UNWIND_CODE UnwindCode[1];
; /* UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
; * union {
; * OPTIONAL ULONG ExceptionHandler;
; * OPTIONAL ULONG FunctionEntry;
; * };
; * OPTIONAL ULONG ExceptionData[];
; */
macro .seh_proc func {
local ..func, ..flags, ..frameptr, ..funcptr, ..funclabel, ..ucodes
..flags = 0
..frameptr = 0
..ucodes = 0
macro .seh_handler handler, flags \{
..flags = flags
..funcptr = rva handler
\}
macro .seh_pushreg reg \{
; UWOP_PUSH_NONVOL
\local ..label
..label:
..ucodes = ..ucodes + 1
store byte (..label - ..func) at __SEH64_UNWIND_CODE:(-2*..ucodes)
store byte (__SEH64_REG.\#reg * 16) at __SEH64_UNWIND_CODE:(-2*..ucodes+1)
\}
macro .seh_stackalloc size \{
\local ..label
..label:
if size <= 128
; UWOP_ALLOC_SMALL
..ucodes = ..ucodes + 1
store byte (..label - ..func) at __SEH64_UNWIND_CODE:(-2*..ucodes)
store byte ((size) * 2 - 14) at __SEH64_UNWIND_CODE:(-2*..ucodes+1)
else if size < 524288
; UWOP_ALLOC_LARGE (OpInfo = 0)
..ucodes = ..ucodes + 2
store byte (..label - ..func) at __SEH64_UNWIND_CODE:(-2*..ucodes)
store byte 1 at __SEH64_UNWIND_CODE:(-2*..ucodes+1)
store word ((size) / 8) at __SEH64_UNWIND_CODE:(-2*..ucodes+2)
else
; UWOP_ALLOC_LARGE (OpInfo = 1)
..ucodes = ..ucodes + 3
store byte (..label - ..func) at __SEH64_UNWIND_CODE:(-2*..ucodes)
store byte 17 at __SEH64_UNWIND_CODE:(-2*..ucodes+1)
store dword (size) at __SEH64_UNWIND_CODE:(-2*..ucodes+2)
end if
\}
macro .seh_setframe reg, offset \{
; UWOP_SET_FPREG
\local ..label
..label:
..ucodes = ..ucodes + 1
..frameptr = __SEH64_REG.\#reg + offset
store byte (..label - ..func) at __SEH64_UNWIND_CODE:(-2*..ucodes)
store byte (__SEH64_REG.\#reg * 16 + 3) at __SEH64_UNWIND_CODE:(-2*..ucodes+1)
\}
macro .seh_endprologue \{
\local ..endp, ..tmp
..endp:
virtual at 0
..funclabel#.uinfo::
db 1 + (..flags * 8)
db ..endp - ..func
db ..ucodes
db ..frameptr
repeat ..ucodes
load ..tmp word from __SEH64_UNWIND_CODE:((-..ucodes + % - 1) * 2)
dw ..tmp
end repeat
align 4
if ..flags <> UNW_FLAG_NHANDLER
dd ..funcptr
end if
..funclabel#.uinfo.size = $
end virtual
\}
macro .seh_endproc \{
\local ..endp
purge .seh_handler
purge .seh_pushreg
purge .seh_stackalloc
purge .seh_setframe
purge .seh_endprologue
purge .seh_endproc
..endp:
virtual at 0
..funclabel::
dd rva ..func, rva ..endp, rva ..funclabel#.uinfo.ptr
end virtual
__SEH64_FUNCTABL equ ..funclabel
\}
..func:
match any, func \{
func:
\}
}
macro .seh_fixup {
local sym, cmd, mem, i, t
data 3
irpv sym, __SEH64_FUNCTABL \{
irp mem, sym \\{
load t dword from mem:0
dd t
load t dword from mem:4
dd t
load t dword from mem:8
dd t
\\}
\}
end data
irpv sym, __SEH64_FUNCTABL \{
irp mem, sym \\{
i = 0
mem\\#.uinfo.ptr:
while i < mem\\#.uinfo.size
load t dword from mem\\#.uinfo:i
dd t
i = i + 4
end while
\\}
\}
}