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 // Interesting info can be found in:
24 // http://www.osronline.com/article.cfm?article=469
26 // ONTL, "Open NT Native Template Library", a C++ STL-like library
27 // that can be used even when writing Windows drivers. This is some
28 // quite badass code. The author has done impressive heavy spelunking
29 // of MSVCR structures. http://code.google.com/p/ontl/
31 // Geoff Chappell's pages:
32 // http://www.geoffchappell.com/studies/msvc/language/index.htm
34 // The below is from ONTL's ntl/nt/exception.hxx, cleaned up to keep just the _M_X64 parts:
38 /* This information until the corresponding '#endif // 0' is covered
39 * by ONTL's license, which is said to be the "zlib/libpng license"
40 * below, which as far as I see is permissive enough to allow this
41 * information to be included here in this source file. Note that no
42 * actual code from ONTL below gets compiled into the object file.
46 * Copyright (c) 2011 <copyright holders> (The ONTL main
47 * developer(s) don't tell their real name(s) on the ONTL site.)
49 * This software is provided 'as-is', without any express or implied
50 * warranty. In no event will the authors be held liable for any damages
51 * arising from the use of this software.
53 * Permission is granted to anyone to use this software for any purpose,
54 * including commercial applications, and to alter it and redistribute it
55 * freely, subject to the following restrictions:
57 * 1. The origin of this software must not be misrepresented; you must not
58 * claim that you wrote the original software. If you use this software
59 * in a product, an acknowledgment in the product documentation would be
60 * appreciated but is not required.
62 * 2. Altered source versions must be plainly marked as such, and must not be
63 * misrepresented as being the original software.
65 * 3. This notice may not be removed or altered from any source
70 typedef uint32_t rva_t
;
72 ///\note the calling convention should not matter since this has no arguments
73 typedef void generic_function_t();
75 struct ptrtomember
// _PMD
77 typedef __w64
int32_t mdiff_t
;
78 mdiff_t member_offset
;
79 mdiff_t vbtable_offset
; // -1 if not a virtual base
80 mdiff_t vdisp_offset
; // offset to the displacement value inside the vbtable
83 T
* operator()(T
* const thisptr
) const
85 uintptr_t tp
= reinterpret_cast<uintptr_t>(thisptr
);
86 uintptr_t ptr
= tp
+ member_offset
;
87 if ( vbtable_offset
!= -1 ) // !(vbtable_offset < 0)
89 ptr
+= *reinterpret_cast<mdiff_t
*>( static_cast<intptr_t>(vdisp_offset
+ *reinterpret_cast<mdiff_t
*>(tp
+ vbtable_offset
)) )
92 return reinterpret_cast<T
*>(ptr
);
98 typedef void (* dtor_ptr
)(eobject
*);
99 typedef void (* ctor_ptr
)(eobject
*, eobject
*);
100 typedef void (* ctor_ptr2
)(eobject
*, eobject
*, int);
105 /** is simple type */
106 uint32_t memmoveable
: 1;
107 /** catchable as reference only */
108 uint32_t refonly
: 1;
109 /** class with virtual base */
110 uint32_t hasvirtbase
: 1;
111 /** offset to the type descriptor */
114 /** catch type instance location within a thrown object */
115 ptrtomember thiscast
;
116 /** size of the simple type or offset into buffer of \c this pointer for catch object */
117 uint32_t object_size
;
126 #pragma pack(push, 4)
127 struct catchabletypearray
134 #pragma pack(push, 4)
137 typedef exception_disposition __cdecl
forwardcompathandler_t(...);
139 /* 0x00 */ uint32_t econst
: 1;
140 /* 0x00 */ uint32_t evolatile
: 1;
141 /* 0x00 */ uint32_t : 1;
142 /* 0x00 */ uint32_t e8
: 1;
143 /* 0x04 */ rva_t exception_dtor
;
144 /* 0x08 */ rva_t forwardcompathandler
;
145 /* 0x0C */ rva_t catchabletypearray
; ///< types able to catch the exception.
149 /// This type represents the catch clause
152 // union { uint32_t adjectives; void * ptr; };
153 uint32_t isconst
: 1;
154 uint32_t isvolatile
: 1;
155 uint32_t isunaligned
: 1;// guess it is not used on x86
156 uint32_t isreference
: 1;
161 /** offset to the type descriptor of this catch object */
162 /*0x04*/ rva_t typeinfo
; // dispType
163 /*0x08*/ int eobject_bpoffset
; // dispCatchObj
164 /** offset to the catch clause funclet */
165 /*0x0C*/ rva_t handler
; // dispOfHandler
166 /*0x10*/ uint32_t frame
; // dispFrame
169 // ___BuildCatchObject
170 /// 15.3/16 When the exception-declaration specifies a class type, a copy
171 /// constructor is used to initialize either the object declared
172 /// in the exception-declaration or,
173 /// if the exception-declaration does not specify a name,
174 /// a temporary object of that type.
175 ///\note This is the question may we optimize out the last case.
176 ///\warning If the copy constructor throws an exception, std::unexpected would be called
178 constructcatchobject(
179 cxxregistration
* cxxreg
,
180 const ehandler
* const catchblock
,
181 catchabletype
* const convertible
,
182 const dispatcher_context
* const dispatch
189 struct typeinfo_t
{ void* vtbl
; void* spare
; char name
[1]; };
190 enum catchable_info
{ cidefault
, cicomplex
, civirtual
} cinfo
= cidefault
;
192 const typeinfo_t
* ti
= catchblock
->typeinfo
? dispatch
->va
<typeinfo_t
*>(catchblock
->typeinfo
) : NULL
;
193 if(ti
&& *ti
->name
&& (catchblock
->eobject_bpoffset
|| catchblock
->ishz
)){
194 eobject
** objplace
= catchblock
->ishz
195 ? reinterpret_cast<eobject
**>(cxxreg
)
196 : reinterpret_cast<eobject
**>(catchblock
->eobject_bpoffset
+ cxxreg
->fp
.FramePointers
);
197 if(catchblock
->isreference
){
199 *objplace
= adjust_pointer(get_object(), convertible
);
200 }else if(convertible
->memmoveable
){
202 std::memcpy(objplace
, get_object(), convertible
->object_size
);
203 if(convertible
->object_size
== sizeof(void*) && *objplace
)
204 *objplace
= adjust_pointer((void*)*objplace
, convertible
);
206 // if copy ctor exists, call it; binary copy otherwise
207 if(convertible
->copyctor
){
208 cinfo
= convertible
->hasvirtbase
? civirtual
: cicomplex
;
210 std::memcpy(objplace
, (const void*)adjust_pointer(get_object(), convertible
), convertible
->object_size
);
214 // end of build helper
215 if(cinfo
!= cidefault
){
216 eobject
* objthis
= catchblock
->ishz
217 ? reinterpret_cast<eobject
*>(cxxreg
)
218 : reinterpret_cast<eobject
*>(catchblock
->eobject_bpoffset
+ cxxreg
->fp
.FramePointers
);
219 void* copyctor
= thrown_va(convertible
->copyctor
);
220 eobject
* copyarg
= adjust_pointer(get_object(), convertible
);
221 if(cinfo
== cicomplex
)
222 (eobject::ctor_ptr (copyctor
))(objthis
, copyarg
);
224 (eobject::ctor_ptr2(copyctor
))(objthis
, copyarg
, 1);
227 __except(cxxregistration::unwindfilter(static_cast<nt::ntstatus
>(_exception_code())))
229 nt::exception::inconsistency();
236 #include <sal/config.h>
245 #include <rtl/alloc.h>
246 #include <rtl/strbuf.hxx>
247 #include <rtl/ustrbuf.hxx>
248 #include <sal/log.hxx>
250 #include <com/sun/star/uno/Any.hxx>
251 #include <msvc/amd64.hxx>
252 #include <except.hxx>
254 #pragma pack(push, 8)
256 using namespace ::com::sun::star
;
258 static void* __cdecl
copyConstruct(void* pExcThis
, void* pSource
,
259 typelib_TypeDescription
* pTD
) noexcept
261 ::uno_copyData(pExcThis
, pSource
, pTD
, uno::cpp_acquire
);
265 static void* __cdecl
destruct(void* pExcThis
, typelib_TypeDescription
* pTD
) noexcept
267 ::uno_destructData(pExcThis
, pTD
, uno::cpp_release
);
271 const int codeSnippetSize
= 40;
273 static void GenerateConstructorTrampoline(unsigned char* code
,
274 typelib_TypeDescription
* pTD
) noexcept
276 unsigned char* p
= code
;
281 *reinterpret_cast<void**>(p
) = pTD
;
284 // mov r11, copyConstruct
287 *reinterpret_cast<void**>(p
) = reinterpret_cast<void*>(©Construct
);
295 assert(p
< code
+ codeSnippetSize
);
298 static void GenerateDestructorTrampoline(unsigned char* code
, typelib_TypeDescription
* pTD
) noexcept
300 unsigned char* p
= code
;
305 *reinterpret_cast<void**>(p
) = pTD
;
311 *reinterpret_cast<void**>(p
) = reinterpret_cast<void*>(&destruct
);
319 assert(p
< code
+ codeSnippetSize
);
322 ExceptionType::ExceptionType(unsigned char* pCode
, sal_uInt64 pCodeBase
,
323 typelib_TypeDescription
* pTD
) noexcept
329 , exc_type_info(nullptr, "")
331 // As _n0 is always initialized to zero, that means the
332 // hasvirtbase flag (see the ONTL catchabletype struct) is
333 // off, and thus the copyctor is of the ctor_ptr kind.
336 type_info
* pRTTI
= RTTInfos::get(pTD
->pTypeName
, &len
);
338 memcpy(static_cast<void*>(&exc_type_info
), static_cast<void*>(pRTTI
), len
);
339 _pTypeInfo
= static_cast<sal_uInt32
>(reinterpret_cast<sal_uInt64
>(&exc_type_info
) - pCodeBase
);
340 GenerateConstructorTrampoline(pCode
, pTD
);
342 assert(pCodeBase
<= reinterpret_cast<sal_uInt64
>(pCode
)
343 && (reinterpret_cast<sal_uInt64
>(pCode
) - pCodeBase
< 0x100000000));
344 _pCopyCtor
= static_cast<sal_uInt32
>(reinterpret_cast<sal_uInt64
>(pCode
) - pCodeBase
);
347 /* Rewrite of 32-Bit-Code to work under 64 Bit:
348 * To use the 32 Bit offset values in the ExceptionType we have to
349 * allocate a single allocation block and use it for all code and date
350 * all offsets inside this area are guaranteed to be in 32 bit address range.
351 * So we have to calc total memory allocation size for D-tor, C-Tors,
352 * ExceptionType and type_info. ExceptionType is allocated via placement new
353 * to locate everything inside our mem block.
354 * There is one caveat: Struct type_info is kept in
355 * a map and was referenced from class ExceptionType. Therefore type_info now
356 * is also member of ExceptionType and can be referenced via 32 bit offset.
359 RaiseInfo::RaiseInfo(typelib_TypeDescription
* pTD
) noexcept
364 typelib_CompoundTypeDescription
* pCompTD
;
366 // Count how many trampolines we need
367 int codeSize
= codeSnippetSize
;
371 for (pCompTD
= reinterpret_cast<typelib_CompoundTypeDescription
*>(pTD
); pCompTD
;
372 pCompTD
= pCompTD
->pBaseTypeDescription
)
375 codeSize
+= codeSnippetSize
;
378 // Array with size (4) and all _pTypeInfo (4*nLen)
379 int typeInfoArraySize
= 4 + 4 * nLen
;
381 // 2.Pass: Get the total needed memory for class ExceptionType
382 // (with embedded type_info) and keep the sizes for each instance
383 // is stored in allocated int array
384 auto exceptionTypeSizeArray
= std::make_unique
<int[]>(nLen
);
387 for (pCompTD
= reinterpret_cast<typelib_CompoundTypeDescription
*>(pTD
); pCompTD
;
388 pCompTD
= pCompTD
->pBaseTypeDescription
)
391 RTTInfos::get(pCompTD
->aBase
.pTypeName
, &typeInfoLen
);
392 // Mem has to be on 4-byte Boundary
393 if (typeInfoLen
% 4 != 0)
395 int n
= typeInfoLen
/ 4;
399 exceptionTypeSizeArray
[nLen
++] = typeInfoLen
+ sizeof(ExceptionType
);
402 // Total ExceptionType related mem
403 int excTypeAddLen
= 0;
404 for (int i
= 0; i
< nLen
; i
++)
406 excTypeAddLen
+= exceptionTypeSizeArray
[i
];
409 // Allocate mem for code and all dynamic data in one chunk to guarantee
411 const int totalSize
= codeSize
+ typeInfoArraySize
+ excTypeAddLen
;
412 unsigned char* pCode
= _code
= static_cast<unsigned char*>(std::malloc(totalSize
));
413 assert(pCode
&& "Don't handle OOM conditions");
416 // New base of types array, starts after Trampoline D-Tor / C-Tors
417 DWORD
* types
= reinterpret_cast<DWORD
*>(pCode
+ codeSize
);
419 // New base of ExceptionType array, starts after types array
420 unsigned char* etMem
= pCode
+ codeSize
+ typeInfoArraySize
;
423 _codeBase
= reinterpret_cast<sal_uInt64
>(pCode
)
424 & ~static_cast<sal_uInt64
>(ExceptionInfos::allocationGranularity
- 1);
427 bool success
= VirtualProtect(pCode
, codeSize
, PAGE_EXECUTE_READWRITE
, &old_protect
);
429 assert(success
&& "VirtualProtect() failed!");
431 ::typelib_typedescription_acquire(pTD
);
433 // Fill pCode with D-Tor code
434 GenerateDestructorTrampoline(pCode
, pTD
);
435 _pDtor
= static_cast<sal_Int32
>(reinterpret_cast<sal_uInt64
>(pCode
) - _codeBase
);
436 pCodeOffset
+= codeSnippetSize
;
438 // Info count accompanied by type info ptrs: type, base type, base base type, ...
439 // Keep offset of types_array
440 _types
= static_cast<sal_Int32
>(reinterpret_cast<sal_uInt64
>(types
) - _codeBase
);
441 // Fill types: (nLen, _offset to ExceptionType1, ...ExceptionType2, ...)
445 for (pCompTD
= reinterpret_cast<typelib_CompoundTypeDescription
*>(pTD
); pCompTD
;
446 pCompTD
= pCompTD
->pBaseTypeDescription
)
448 // Create instance in mem block with placement new
449 ExceptionType
* et
= new (etMem
+ etMemOffset
) ExceptionType(
450 pCode
+ pCodeOffset
, _codeBase
, reinterpret_cast<typelib_TypeDescription
*>(pCompTD
));
452 // Next trampoline entry offset
453 pCodeOffset
+= codeSnippetSize
;
454 // Next ExceptionType placement offset
455 etMemOffset
+= exceptionTypeSizeArray
[nPos
- 1];
457 // Keep offset of addresses of ET for D-Tor call in ~RaiseInfo
458 types
[nPos
++] = static_cast<DWORD
>(reinterpret_cast<sal_uInt64
>(et
) - _codeBase
);
460 // Final check: end of address calculation must be end of mem
461 assert(etMem
+ etMemOffset
== pCode
+ totalSize
);
466 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */