LibreOffice Module bridges (master)  1
msvc_win32_arm64/except.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <memory>
23 
24 #include <malloc.h>
25 #include <new.h>
26 #include <typeinfo>
27 #include <signal.h>
28 
29 #include <rtl/alloc.h>
30 #include <rtl/strbuf.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <sal/log.hxx>
33 
34 #include <com/sun/star/uno/Any.hxx>
35 #include <msvc/arm64.hxx>
36 #include <except.hxx>
37 
38 #pragma pack(push, 8)
39 
40 using namespace ::com::sun::star;
41 
42 static void* __cdecl copyConstruct(void* pExcThis, void* pSource,
43  typelib_TypeDescription* pTD) noexcept
44 {
45  ::uno_copyData(pExcThis, pSource, pTD, uno::cpp_acquire);
46  return pExcThis;
47 }
48 
49 static void* __cdecl destruct(void* pExcThis, typelib_TypeDescription* pTD) noexcept
50 {
51  ::uno_destructData(pExcThis, pTD, uno::cpp_release);
52  return pExcThis;
53 }
54 
55 const int nCodeSnippetSize = 28;
56 
57 static void GenerateCopyConstructorTrampoline(unsigned char* target,
58  typelib_TypeDescription* pTD) noexcept
59 {
60  // ldr x2, #12
61  // ldr x3, #20
62  // br x3
63  // pTD
64  // &copyConstruct
65  static const char code[] = "\x62\x00\x00\x58\x83\x00\x00\x58\x60\x00\x1f\xd6";
66  static_assert(sizeof(code) == 13);
67  static const unsigned int code_size = sizeof(code) - 1;
68 
69  memcpy(target, code, code_size);
70  *reinterpret_cast<void**>(target + code_size) = pTD;
71  *reinterpret_cast<void**>(target + code_size + 8) = &copyConstruct;
72 }
73 
74 static void GenerateDestructorTrampoline(unsigned char* target,
75  typelib_TypeDescription* pTD) noexcept
76 {
77  // ldr x1, #12
78  // ldr x2, #20
79  // br x2
80  // pTD
81  // &destruct
82  static const char code[] = "\x61\x00\x00\x58\x82\x00\x00\x58\x40\x00\x1f\xd6";
83  static_assert(sizeof(code) == 13);
84  static const unsigned int code_size = sizeof(code) - 1;
85 
86  memcpy(target, code, code_size);
87  *reinterpret_cast<void**>(target + code_size) = pTD;
88  *reinterpret_cast<void**>(target + code_size + 8) = &destruct;
89 }
90 
91 ExceptionType::ExceptionType(unsigned char* pCode, sal_uInt64 pCodeBase,
92  typelib_TypeDescription* pTD) noexcept
93  : _n0(0)
94  , _n1(0)
95  , _n2(-1)
96  , _n3(0)
97  , _n4(pTD->nSize)
98  , exc_type_info(nullptr, "")
99 {
100  // As _n0 is always initialized to zero, that means the
101  // hasvirtbase flag (see the ONTL catchabletype struct) is
102  // off, and thus the copyctor is of the ctor_ptr kind.
103 
104  int len;
105  type_info* pRTTI = RTTInfos::get(pTD->pTypeName, &len);
106 
107  memcpy(static_cast<void*>(&exc_type_info), static_cast<void*>(pRTTI), len);
108  _pTypeInfo = static_cast<sal_uInt32>(reinterpret_cast<sal_uInt64>(&exc_type_info) - pCodeBase);
110 
111  assert(pCodeBase <= reinterpret_cast<sal_uInt64>(pCode)
112  && (reinterpret_cast<sal_uInt64>(pCode) - pCodeBase < 0x100000000));
113  _pCopyCtor = static_cast<sal_uInt32>(reinterpret_cast<sal_uInt64>(pCode) - pCodeBase);
114 }
115 
116 /* Rewrite of 32-Bit-Code to work under 64 Bit:
117 * To use the 32 Bit offset values in the ExceptionType we have to
118 * allocate a single allocation block and use it for all code and date
119 * all offsets inside this area are guaranteed to be in 32 bit address range.
120 * So we have to calc total memory allocation size for D-tor, C-Tors,
121 * ExceptionType and type_info. ExceptionType is allocated via placement new
122 * to locate everything inside our mem block.
123 * There is one caveat: Struct type_info is kept in
124 * a map and was referenced from class ExceptionType. Therefore type_info now
125 * is also member of ExceptionType and can be referenced via 32 bit offset.
126 */
127 
129  : _n0(0)
130  , _n2(0)
131  , _pTD(pTD)
132 {
133  typelib_CompoundTypeDescription* pCompTD;
134 
135  // Count how many trampolines we need
136  int codeSize = nCodeSnippetSize;
137 
138  // Info count
139  int nLen = 0;
140  for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
141  pCompTD = pCompTD->pBaseTypeDescription)
142  {
143  ++nLen;
144  codeSize += nCodeSnippetSize;
145  }
146 
147  // Array with size (4) and all _pTypeInfo (4*nLen)
148  int typeInfoArraySize = 4 + 4 * nLen;
149 
150  // 2.Pass: Get the total needed memory for class ExceptionType
151  // (with embedded type_info) and keep the sizes for each instance
152  // is stored in allocated int array
153  auto exceptionTypeSizeArray = std::make_unique<int[]>(nLen);
154 
155  nLen = 0;
156  for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
157  pCompTD = pCompTD->pBaseTypeDescription)
158  {
159  int typeInfoLen;
160  RTTInfos::get(pCompTD->aBase.pTypeName, &typeInfoLen);
161  // Mem has to be on 4-byte Boundary
162  if (typeInfoLen % 4 != 0)
163  {
164  int n = typeInfoLen / 4;
165  n++;
166  typeInfoLen = n * 4;
167  }
168  exceptionTypeSizeArray[nLen++] = typeInfoLen + sizeof(ExceptionType);
169  }
170 
171  // Total ExceptionType related mem
172  int excTypeAddLen = 0;
173  for (int i = 0; i < nLen; i++)
174  {
175  excTypeAddLen += exceptionTypeSizeArray[i];
176  }
177 
178  // Allocate mem for code and all dynamic data in one chunk to guarantee
179  // 32 bit offsets
180  const int totalSize = codeSize + typeInfoArraySize + excTypeAddLen;
181  unsigned char* pCode = _code = static_cast<unsigned char*>(std::malloc(totalSize));
182  int pCodeOffset = 0;
183 
184  // New base of types array, starts after Trampoline D-Tor / C-Tors
185  DWORD* types = reinterpret_cast<DWORD*>(pCode + codeSize);
186 
187  // New base of ExceptionType array, starts after types array
188  unsigned char* etMem = pCode + codeSize + typeInfoArraySize;
189  int etMemOffset = 0;
190 
191  _codeBase = reinterpret_cast<sal_uInt64>(pCode)
192  & ~static_cast<sal_uInt64>(ExceptionInfos::allocationGranularity - 1);
193 
194  DWORD old_protect;
195  bool success = VirtualProtect(pCode, codeSize, PAGE_EXECUTE_READWRITE, &old_protect);
196  (void)success;
197  assert(success && "VirtualProtect() failed!");
198 
199  ::typelib_typedescription_acquire(pTD);
200 
201  // Fill pCode with D-Tor code
202  GenerateDestructorTrampoline(pCode, pTD);
203  _pDtor = static_cast<sal_Int32>(reinterpret_cast<sal_uInt64>(pCode) - _codeBase);
204  pCodeOffset += nCodeSnippetSize;
205 
206  // Info count accompanied by type info ptrs: type, base type, base base type, ...
207  // Keep offset of types_array
208  _types = static_cast<sal_Int32>(reinterpret_cast<sal_uInt64>(types) - _codeBase);
209  // Fill types: (nLen, _offset to ExceptionType1, ...ExceptionType2, ...)
210  types[0] = nLen;
211 
212  int nPos = 1;
213  for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
214  pCompTD = pCompTD->pBaseTypeDescription)
215  {
216  // Create instance in mem block with placement new
217  ExceptionType* et = new (etMem + etMemOffset) ExceptionType(
218  pCode + pCodeOffset, _codeBase, reinterpret_cast<typelib_TypeDescription*>(pCompTD));
219 
220  // Next trampoline entry offset
221  pCodeOffset += nCodeSnippetSize;
222  // Next ExceptionType placement offset
223  etMemOffset += exceptionTypeSizeArray[nPos - 1];
224 
225  // Keep offset of addresses of ET for D-Tor call in ~RaiseInfo
226  types[nPos++] = static_cast<DWORD>(reinterpret_cast<sal_uInt64>(et) - _codeBase);
227  }
228  // Final check: end of address calculation must be end of mem
229  assert(etMem + etMemOffset == pCode + totalSize);
230 }
231 
232 #pragma pack(pop)
233 
234 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static DWORD allocationGranularity
static void *__cdecl copyConstruct(void *pExcThis, void *pSource, typelib_TypeDescription *pTD) noexcept
ExceptionType(unsigned char *pCode, sal_uInt64 pCodeBase, typelib_TypeDescription *pTD)
sal_Int64 n
sal_Unicode code
static void GenerateDestructorTrampoline(unsigned char *target, typelib_TypeDescription *pTD) noexcept
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
int i
static void GenerateCopyConstructorTrampoline(unsigned char *target, typelib_TypeDescription *pTD) noexcept
RaiseInfo(typelib_TypeDescription *pTD)
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:52
static void *__cdecl destruct(void *pExcThis, typelib_TypeDescription *pTD) noexcept
static type_info * get(OUString const &rUNOname, int *len=nullptr)
const int nCodeSnippetSize
sal_uInt16 nPos
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo