LibreOffice Module bridges (master) 1
msvc_win32_x86-64/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// Interesting info can be found in:
21
22// MSDN, obviously
23
24// http://www.osronline.com/article.cfm?article=469
25
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/
30
31// Geoff Chappell's pages:
32// http://www.geoffchappell.com/studies/msvc/language/index.htm
33
34// The below is from ONTL's ntl/nt/exception.hxx, cleaned up to keep just the _M_X64 parts:
35
36#if 0
37
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.
43 */
44
45/*
46 * Copyright (c) 2011 <copyright holders> (The ONTL main
47 * developer(s) don't tell their real name(s) on the ONTL site.)
48 *
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.
52 *
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:
56 *
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.
61 *
62 * 2. Altered source versions must be plainly marked as such, and must not be
63 * misrepresented as being the original software.
64 *
65 * 3. This notice may not be removed or altered from any source
66 * distribution.
67 *
68 */
69
70typedef uint32_t rva_t;
71
73typedef void generic_function_t();
74
75struct ptrtomember // _PMD
76{
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
81
82 template<typename T>
83 T * operator()(T * const thisptr) const
84 {
85 uintptr_t tp = reinterpret_cast<uintptr_t>(thisptr);
86 uintptr_t ptr = tp + member_offset;
87 if ( vbtable_offset != -1 ) // !(vbtable_offset < 0)
88 {
89 ptr += *reinterpret_cast<mdiff_t*>( static_cast<intptr_t>(vdisp_offset + *reinterpret_cast<mdiff_t*>(tp + vbtable_offset)) )
90 + vbtable_offset;
91 }
92 return reinterpret_cast<T*>(ptr);
93 }
94};
95
96struct eobject
97{
98 typedef void (* dtor_ptr )(eobject*);
99 typedef void (* ctor_ptr )(eobject*, eobject*);
100 typedef void (* ctor_ptr2)(eobject*, eobject*, int);
101};
102
103struct catchabletype
104{
106 uint32_t memmoveable : 1;
108 uint32_t refonly : 1;
110 uint32_t hasvirtbase : 1;
112 rva_t typeinfo;
113
115 ptrtomember thiscast;
117 uint32_t object_size;
118
119 union
120 {
121 rva_t copyctor;
122 rva_t copyctor2;
123 };
124};
125
126#pragma pack(push, 4)
127struct catchabletypearray
128{
129 uint32_t size;
130 rva_t type[1];
131};
132#pragma pack(pop)
133
134#pragma pack(push, 4)
135struct throwinfo
136{
137 typedef exception_disposition __cdecl forwardcompathandler_t(...);
138
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;
146};
147#pragma pack(pop)
148
150struct ehandler
151{
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;
157
158 uint32_t :27;
159 uint32_t ishz : 1;
160
162 /*0x04*/ rva_t typeinfo; // dispType
163 /*0x08*/ int eobject_bpoffset; // dispCatchObj
165 /*0x0C*/ rva_t handler; // dispOfHandler
166 /*0x10*/ uint32_t frame; // dispFrame
167}
168
169// ___BuildCatchObject
177void
178 constructcatchobject(
179 cxxregistration * cxxreg,
180 const ehandler * const catchblock,
181 catchabletype * const convertible,
182 const dispatcher_context* const dispatch
183 )
184 const
185{
186 _EH_TRACE_ENTER();
187 // build helper
188 __try {
189 struct typeinfo_t { void* vtbl; void* spare; char name[1]; };
190 enum catchable_info { cidefault, cicomplex, civirtual } cinfo = cidefault;
191
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){
198 // just ref/pointer
199 *objplace = adjust_pointer(get_object(), convertible);
200 }else if(convertible->memmoveable){
201 // POD
202 std::memcpy(objplace, get_object(), convertible->object_size);
203 if(convertible->object_size == sizeof(void*) && *objplace)
204 *objplace = adjust_pointer((void*)*objplace, convertible);
205 }else{
206 // if copy ctor exists, call it; binary copy otherwise
207 if(convertible->copyctor){
208 cinfo = convertible->hasvirtbase ? civirtual : cicomplex;
209 }else{
210 std::memcpy(objplace, (const void*)adjust_pointer(get_object(), convertible), convertible->object_size);
211 }
212 }
213 }
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);
223 else
224 (eobject::ctor_ptr2(copyctor))(objthis, copyarg, 1);
225 }
226 }
227 __except(cxxregistration::unwindfilter(static_cast<nt::ntstatus>(_exception_code())))
228 {
229 nt::exception::inconsistency();
230 }
231 _EH_TRACE_LEAVE();
232}
233
234#endif // 0
235
236#include <sal/config.h>
237
238#include <memory>
239
240#include <malloc.h>
241#include <new.h>
242#include <typeinfo>
243#include <signal.h>
244
245#include <rtl/alloc.h>
246#include <rtl/strbuf.hxx>
247#include <rtl/ustrbuf.hxx>
248#include <sal/log.hxx>
249
250#include <com/sun/star/uno/Any.hxx>
251#include <msvc/amd64.hxx>
252#include <except.hxx>
253
254#pragma pack(push, 8)
255
256using namespace ::com::sun::star;
257
258static void* __cdecl copyConstruct(void* pExcThis, void* pSource,
259 typelib_TypeDescription* pTD) noexcept
260{
261 ::uno_copyData(pExcThis, pSource, pTD, uno::cpp_acquire);
262 return pExcThis;
263}
264
265static void* __cdecl destruct(void* pExcThis, typelib_TypeDescription* pTD) noexcept
266{
267 ::uno_destructData(pExcThis, pTD, uno::cpp_release);
268 return pExcThis;
269}
270
271const int codeSnippetSize = 40;
272
273static void GenerateConstructorTrampoline(unsigned char* code,
274 typelib_TypeDescription* pTD) noexcept
275{
276 unsigned char* p = code;
277
278 // mov r8, pTD
279 *p++ = 0x49;
280 *p++ = 0xB8;
281 *reinterpret_cast<void**>(p) = pTD;
282 p += 8;
283
284 // mov r11, copyConstruct
285 *p++ = 0x49;
286 *p++ = 0xBB;
287 *reinterpret_cast<void**>(p) = reinterpret_cast<void*>(&copyConstruct);
288 p += 8;
289
290 // jmp r11
291 *p++ = 0x41;
292 *p++ = 0xFF;
293 *p++ = 0xE3;
294
295 assert(p < code + codeSnippetSize);
296}
297
298static void GenerateDestructorTrampoline(unsigned char* code, typelib_TypeDescription* pTD) noexcept
299{
300 unsigned char* p = code;
301
302 // mov rdx, pTD
303 *p++ = 0x48;
304 *p++ = 0xBA;
305 *reinterpret_cast<void**>(p) = pTD;
306 p += 8;
307
308 // mov r11, destruct
309 *p++ = 0x49;
310 *p++ = 0xBB;
311 *reinterpret_cast<void**>(p) = reinterpret_cast<void*>(&destruct);
312 p += 8;
313
314 // jmp r11
315 *p++ = 0x41;
316 *p++ = 0xFF;
317 *p++ = 0xE3;
318
319 assert(p < code + codeSnippetSize);
320}
321
322ExceptionType::ExceptionType(unsigned char* pCode, sal_uInt64 pCodeBase,
323 typelib_TypeDescription* pTD) noexcept
324 : _n0(0)
325 , _n1(0)
326 , _n2(-1)
327 , _n3(0)
328 , _n4(pTD->nSize)
329 , exc_type_info(nullptr, "")
330{
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.
334
335 int len;
336 type_info* pRTTI = RTTInfos::get(pTD->pTypeName, &len);
337
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);
341
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);
345}
346
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.
357*/
358
360 : _n0(0)
361 , _n2(0)
362 , _pTD(pTD)
363{
364 typelib_CompoundTypeDescription* pCompTD;
365
366 // Count how many trampolines we need
367 int codeSize = codeSnippetSize;
368
369 // Info count
370 int nLen = 0;
371 for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
372 pCompTD = pCompTD->pBaseTypeDescription)
373 {
374 ++nLen;
375 codeSize += codeSnippetSize;
376 }
377
378 // Array with size (4) and all _pTypeInfo (4*nLen)
379 int typeInfoArraySize = 4 + 4 * nLen;
380
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);
385
386 nLen = 0;
387 for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
388 pCompTD = pCompTD->pBaseTypeDescription)
389 {
390 int typeInfoLen;
391 RTTInfos::get(pCompTD->aBase.pTypeName, &typeInfoLen);
392 // Mem has to be on 4-byte Boundary
393 if (typeInfoLen % 4 != 0)
394 {
395 int n = typeInfoLen / 4;
396 n++;
397 typeInfoLen = n * 4;
398 }
399 exceptionTypeSizeArray[nLen++] = typeInfoLen + sizeof(ExceptionType);
400 }
401
402 // Total ExceptionType related mem
403 int excTypeAddLen = 0;
404 for (int i = 0; i < nLen; i++)
405 {
406 excTypeAddLen += exceptionTypeSizeArray[i];
407 }
408
409 // Allocate mem for code and all dynamic data in one chunk to guarantee
410 // 32 bit offsets
411 const int totalSize = codeSize + typeInfoArraySize + excTypeAddLen;
412 unsigned char* pCode = _code = static_cast<unsigned char*>(std::malloc(totalSize));
413 int pCodeOffset = 0;
414
415 // New base of types array, starts after Trampoline D-Tor / C-Tors
416 DWORD* types = reinterpret_cast<DWORD*>(pCode + codeSize);
417
418 // New base of ExceptionType array, starts after types array
419 unsigned char* etMem = pCode + codeSize + typeInfoArraySize;
420 int etMemOffset = 0;
421
422 _codeBase = reinterpret_cast<sal_uInt64>(pCode)
423 & ~static_cast<sal_uInt64>(ExceptionInfos::allocationGranularity - 1);
424
425 DWORD old_protect;
426 bool success = VirtualProtect(pCode, codeSize, PAGE_EXECUTE_READWRITE, &old_protect);
427 (void)success;
428 assert(success && "VirtualProtect() failed!");
429
430 ::typelib_typedescription_acquire(pTD);
431
432 // Fill pCode with D-Tor code
434 _pDtor = static_cast<sal_Int32>(reinterpret_cast<sal_uInt64>(pCode) - _codeBase);
435 pCodeOffset += codeSnippetSize;
436
437 // Info count accompanied by type info ptrs: type, base type, base base type, ...
438 // Keep offset of types_array
439 _types = static_cast<sal_Int32>(reinterpret_cast<sal_uInt64>(types) - _codeBase);
440 // Fill types: (nLen, _offset to ExceptionType1, ...ExceptionType2, ...)
441 types[0] = nLen;
442
443 int nPos = 1;
444 for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
445 pCompTD = pCompTD->pBaseTypeDescription)
446 {
447 // Create instance in mem block with placement new
448 ExceptionType* et = new (etMem + etMemOffset) ExceptionType(
449 pCode + pCodeOffset, _codeBase, reinterpret_cast<typelib_TypeDescription*>(pCompTD));
450
451 // Next trampoline entry offset
452 pCodeOffset += codeSnippetSize;
453 // Next ExceptionType placement offset
454 etMemOffset += exceptionTypeSizeArray[nPos - 1];
455
456 // Keep offset of addresses of ET for D-Tor call in ~RaiseInfo
457 types[nPos++] = static_cast<DWORD>(reinterpret_cast<sal_uInt64>(et) - _codeBase);
458 }
459 // Final check: end of address calculation must be end of mem
460 assert(etMem + etMemOffset == pCode + totalSize);
461}
462
463#pragma pack(pop)
464
465/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static DWORD allocationGranularity
static type_info * get(OUString const &rUNOname, int *len=nullptr) noexcept
char const * name
void * p
sal_Int64 n
sal_uInt16 nPos
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:53
const int codeSnippetSize
static void *__cdecl destruct(void *pExcThis, typelib_TypeDescription *pTD) noexcept
static void GenerateDestructorTrampoline(unsigned char *code, typelib_TypeDescription *pTD) noexcept
static void GenerateConstructorTrampoline(unsigned char *code, typelib_TypeDescription *pTD) noexcept
static void *__cdecl copyConstruct(void *pExcThis, void *pSource, typelib_TypeDescription *pTD) noexcept
size
int i
sal_Unicode code
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
ExceptionType(unsigned char *pCode, sal_uInt64 pCodeBase, typelib_TypeDescription *pTD) noexcept
RaiseInfo(typelib_TypeDescription *pTD) noexcept
ResultType type