1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
29 #include <rtl/alloc.h>
30 #include <rtl/strbuf.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <sal/log.hxx>
34 #include <com/sun/star/uno/Any.hxx>
35 #include <msvc/arm64.hxx>
40 using namespace ::com::sun::star
;
42 static void* __cdecl
copyConstruct(void* pExcThis
, void* pSource
,
43 typelib_TypeDescription
* pTD
) noexcept
45 ::uno_copyData(pExcThis
, pSource
, pTD
, uno::cpp_acquire
);
49 static void* __cdecl
destruct(void* pExcThis
, typelib_TypeDescription
* pTD
) noexcept
51 ::uno_destructData(pExcThis
, pTD
, uno::cpp_release
);
55 const int nCodeSnippetSize
= 28;
57 static void GenerateCopyConstructorTrampoline(unsigned char* target
,
58 typelib_TypeDescription
* pTD
) noexcept
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;
69 memcpy(target
, code
, code_size
);
70 *reinterpret_cast<void**>(target
+ code_size
) = pTD
;
71 *reinterpret_cast<void**>(target
+ code_size
+ 8) = ©Construct
;
74 static void GenerateDestructorTrampoline(unsigned char* target
,
75 typelib_TypeDescription
* pTD
) noexcept
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;
86 memcpy(target
, code
, code_size
);
87 *reinterpret_cast<void**>(target
+ code_size
) = pTD
;
88 *reinterpret_cast<void**>(target
+ code_size
+ 8) = &destruct
;
91 ExceptionType::ExceptionType(unsigned char* pCode
, sal_uInt64 pCodeBase
,
92 typelib_TypeDescription
* pTD
) noexcept
98 , exc_type_info(nullptr, "")
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.
105 type_info
* pRTTI
= RTTInfos::get(pTD
->pTypeName
, &len
);
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
);
109 GenerateCopyConstructorTrampoline(pCode
, pTD
);
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
);
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.
128 RaiseInfo::RaiseInfo(typelib_TypeDescription
* pTD
) noexcept
133 typelib_CompoundTypeDescription
* pCompTD
;
135 // Count how many trampolines we need
136 int codeSize
= nCodeSnippetSize
;
140 for (pCompTD
= reinterpret_cast<typelib_CompoundTypeDescription
*>(pTD
); pCompTD
;
141 pCompTD
= pCompTD
->pBaseTypeDescription
)
144 codeSize
+= nCodeSnippetSize
;
147 // Array with size (4) and all _pTypeInfo (4*nLen)
148 int typeInfoArraySize
= 4 + 4 * nLen
;
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
);
156 for (pCompTD
= reinterpret_cast<typelib_CompoundTypeDescription
*>(pTD
); pCompTD
;
157 pCompTD
= pCompTD
->pBaseTypeDescription
)
160 RTTInfos::get(pCompTD
->aBase
.pTypeName
, &typeInfoLen
);
161 // Mem has to be on 4-byte Boundary
162 if (typeInfoLen
% 4 != 0)
164 int n
= typeInfoLen
/ 4;
168 exceptionTypeSizeArray
[nLen
++] = typeInfoLen
+ sizeof(ExceptionType
);
171 // Total ExceptionType related mem
172 int excTypeAddLen
= 0;
173 for (int i
= 0; i
< nLen
; i
++)
175 excTypeAddLen
+= exceptionTypeSizeArray
[i
];
178 // Allocate mem for code and all dynamic data in one chunk to guarantee
180 const int totalSize
= codeSize
+ typeInfoArraySize
+ excTypeAddLen
;
181 unsigned char* pCode
= _code
= static_cast<unsigned char*>(std::malloc(totalSize
));
184 // New base of types array, starts after Trampoline D-Tor / C-Tors
185 DWORD
* types
= reinterpret_cast<DWORD
*>(pCode
+ codeSize
);
187 // New base of ExceptionType array, starts after types array
188 unsigned char* etMem
= pCode
+ codeSize
+ typeInfoArraySize
;
191 _codeBase
= reinterpret_cast<sal_uInt64
>(pCode
)
192 & ~static_cast<sal_uInt64
>(ExceptionInfos::allocationGranularity
- 1);
195 bool success
= VirtualProtect(pCode
, codeSize
, PAGE_EXECUTE_READWRITE
, &old_protect
);
197 assert(success
&& "VirtualProtect() failed!");
199 ::typelib_typedescription_acquire(pTD
);
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
;
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, ...)
213 for (pCompTD
= reinterpret_cast<typelib_CompoundTypeDescription
*>(pTD
); pCompTD
;
214 pCompTD
= pCompTD
->pBaseTypeDescription
)
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
));
220 // Next trampoline entry offset
221 pCodeOffset
+= nCodeSnippetSize
;
222 // Next ExceptionType placement offset
223 etMemOffset
+= exceptionTypeSizeArray
[nPos
- 1];
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
);
228 // Final check: end of address calculation must be end of mem
229 assert(etMem
+ etMemOffset
== pCode
+ totalSize
);
234 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */