1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qv4functiontable_p.h"
41 
42 #include <assembler/MacroAssemblerCodeRef.h>
43 
44 #include <QtCore/qdebug.h>
45 
46 #include <windows.h>
47 
48 QT_BEGIN_NAMESPACE
49 
50 namespace QV4 {
51 
52 enum UnwindOpcode: UINT8
53 {
54     UWOP_PUSH_NONVOL = 0, /* info == register number */
55     UWOP_ALLOC_LARGE,     /* no info, alloc size in next 2 slots */
56     UWOP_ALLOC_SMALL,     /* info == size of allocation / 8 - 1 */
57     UWOP_SET_FPREG,       /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
58     UWOP_SAVE_NONVOL,     /* info == register number, offset in next slot */
59     UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
60     UWOP_SAVE_XMM128 = 8, /* info == XMM reg number, offset in next slot */
61     UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
62     UWOP_PUSH_MACHFRAME   /* info == 0: no error-code, 1: error-code */
63 };
64 
65 enum Register : UINT8
66 {
67     RAX = 0,
68     RCX,
69     RDX,
70     RBX,
71     RSP,
72     RBP,
73     RSI,
74     RDI,
75     NONE = 15
76 };
77 
78 struct UnwindCode
79 {
UnwindCodeQV4::UnwindCode80     UnwindCode(UINT8 offset, UnwindOpcode operation, Register info)
81         : offset(offset), operation(operation), info(info)
82     {}
83 
84     UINT8 offset;
85     UINT8 operation: 4;
86     UINT8 info:      4;
87 };
88 
89 struct UnwindInfo
90 {
91     UINT8 Version : 3;
92     UINT8 Flags : 5;
93     UINT8 SizeOfProlog;
94     UINT8 CountOfUnwindCodes;
95     UINT8 FrameRegister : 4;
96     UINT8 FrameRegisterOffset : 4;
97     UnwindCode UnwindCodes[2];
98 };
99 
100 struct ExceptionHandlerRecord
101 {
102     RUNTIME_FUNCTION handler;
103     UnwindInfo info;
104 };
105 
generateFunctionTable(Function *,JSC::MacroAssemblerCodeRef * codeRef)106 void generateFunctionTable(Function *, JSC::MacroAssemblerCodeRef *codeRef)
107 {
108     ExceptionHandlerRecord *record = reinterpret_cast<ExceptionHandlerRecord *>(
109                 codeRef->executableMemory()->exceptionHandlerStart());
110 
111     record->info.Version             = 1;
112     record->info.Flags               = 0;
113     record->info.SizeOfProlog        = 4;
114     record->info.CountOfUnwindCodes  = 2;
115     record->info.FrameRegister       = RBP;
116     record->info.FrameRegisterOffset = 0;
117 
118     // Push frame pointer
119     record->info.UnwindCodes[1] = UnwindCode(1, UWOP_PUSH_NONVOL,  RBP);
120     // Set frame pointer from stack pointer
121     record->info.UnwindCodes[0] = UnwindCode(4,   UWOP_SET_FPREG, NONE);
122 
123     const quintptr codeStart = quintptr(codeRef->code().executableAddress());
124     const quintptr codeSize = codeRef->size();
125 
126     record->handler.BeginAddress = DWORD(codeStart - quintptr(record));
127     record->handler.EndAddress   = DWORD(codeStart + codeSize - quintptr(record));
128     record->handler.UnwindData   = offsetof(ExceptionHandlerRecord, info);
129 
130     if (!RtlAddFunctionTable(&record->handler, 1, DWORD64(record))) {
131         const unsigned int errorCode = GetLastError();
132         qWarning() << "Failed to install win64 unwind hook. Error code:" << errorCode;
133     }
134 }
135 
destroyFunctionTable(Function *,JSC::MacroAssemblerCodeRef * codeRef)136 void destroyFunctionTable(Function *, JSC::MacroAssemblerCodeRef *codeRef)
137 {
138     ExceptionHandlerRecord *record = reinterpret_cast<ExceptionHandlerRecord *>(
139                 codeRef->executableMemory()->exceptionHandlerStart());
140     if (!RtlDeleteFunctionTable(&record->handler)) {
141         const unsigned int errorCode = GetLastError();
142         qWarning() << "Failed to remove win64 unwind hook. Error code:" << errorCode;
143     }
144 }
145 
exceptionHandlerSize()146 size_t exceptionHandlerSize()
147 {
148     return sizeof(ExceptionHandlerRecord);
149 }
150 
151 } // QV4
152 
153 QT_END_NAMESPACE
154