1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4functiontable_p.h"
#include <assembler/MacroAssemblerCodeRef.h>
#include <QtCore/qdebug.h>
#include <qt_windows.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
enum UnwindOpcode: UINT8
{
UWOP_PUSH_NONVOL = 0, /* info == register number */
UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
UWOP_SAVE_XMM128 = 8, /* info == XMM reg number, offset in next slot */
UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
};
enum Register : UINT8
{
RAX = 0,
RCX,
RDX,
RBX,
RSP,
RBP,
RSI,
RDI,
NONE = 15
};
struct UnwindCode
{
UnwindCode(UINT8 offset, UnwindOpcode operation, Register info)
: offset(offset), operation(operation), info(info)
{}
UINT8 offset;
UINT8 operation: 4;
UINT8 info: 4;
};
struct UnwindInfo
{
UINT8 Version : 3;
UINT8 Flags : 5;
UINT8 SizeOfProlog;
UINT8 CountOfUnwindCodes;
UINT8 FrameRegister : 4;
UINT8 FrameRegisterOffset : 4;
UnwindCode UnwindCodes[2];
};
struct ExceptionHandlerRecord
{
RUNTIME_FUNCTION handler;
UnwindInfo info;
};
void generateFunctionTable(Function *, JSC::MacroAssemblerCodeRef *codeRef)
{
ExceptionHandlerRecord *record = reinterpret_cast<ExceptionHandlerRecord *>(
codeRef->executableMemory()->exceptionHandlerStart());
record->info.Version = 1;
record->info.Flags = 0;
record->info.SizeOfProlog = 4;
record->info.CountOfUnwindCodes = 2;
record->info.FrameRegister = RBP;
record->info.FrameRegisterOffset = 0;
// Push frame pointer
record->info.UnwindCodes[1] = UnwindCode(1, UWOP_PUSH_NONVOL, RBP);
// Set frame pointer from stack pointer
record->info.UnwindCodes[0] = UnwindCode(4, UWOP_SET_FPREG, NONE);
const quintptr codeStart = quintptr(codeRef->code().executableAddress());
const quintptr codeSize = codeRef->size();
record->handler.BeginAddress = DWORD(codeStart - quintptr(record));
record->handler.EndAddress = DWORD(codeStart + codeSize - quintptr(record));
record->handler.UnwindData = offsetof(ExceptionHandlerRecord, info);
if (!RtlAddFunctionTable(&record->handler, 1, DWORD64(record))) {
const unsigned int errorCode = GetLastError();
qWarning() << "Failed to install win64 unwind hook. Error code:" << errorCode;
}
}
void destroyFunctionTable(Function *, JSC::MacroAssemblerCodeRef *codeRef)
{
ExceptionHandlerRecord *record = reinterpret_cast<ExceptionHandlerRecord *>(
codeRef->executableMemory()->exceptionHandlerStart());
if (!RtlDeleteFunctionTable(&record->handler)) {
const unsigned int errorCode = GetLastError();
qWarning() << "Failed to remove win64 unwind hook. Error code:" << errorCode;
}
}
size_t exceptionHandlerSize()
{
return sizeof(ExceptionHandlerRecord);
}
} // QV4
QT_END_NAMESPACE
|