summaryrefslogtreecommitdiffstats
path: root/bridges/source/cpp_uno/msvc_win32_arm64/except.cxx
blob: 8cc380c5d79b985e16befb346d995d996355dd4b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <sal/config.h>

#include <memory>

#include <malloc.h>
#include <new.h>
#include <typeinfo>
#include <signal.h>

#include <rtl/alloc.h>
#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>

#include <com/sun/star/uno/Any.hxx>
#include <msvc/arm64.hxx>
#include <except.hxx>

#pragma pack(push, 8)

using namespace ::com::sun::star;

static void* __cdecl copyConstruct(void* pExcThis, void* pSource,
                                   typelib_TypeDescription* pTD) noexcept
{
    ::uno_copyData(pExcThis, pSource, pTD, uno::cpp_acquire);
    return pExcThis;
}

static void* __cdecl destruct(void* pExcThis, typelib_TypeDescription* pTD) noexcept
{
    ::uno_destructData(pExcThis, pTD, uno::cpp_release);
    return pExcThis;
}

const int nCodeSnippetSize = 28;

static void GenerateCopyConstructorTrampoline(unsigned char* target,
                                              typelib_TypeDescription* pTD) noexcept
{
    // ldr x2, #12
    // ldr x3, #20
    // br x3
    // pTD
    // &copyConstruct
    static const char code[] = "\x62\x00\x00\x58\x83\x00\x00\x58\x60\x00\x1f\xd6";
    static_assert(sizeof(code) == 13);
    static const unsigned int code_size = sizeof(code) - 1;

    memcpy(target, code, code_size);
    *reinterpret_cast<void**>(target + code_size) = pTD;
    *reinterpret_cast<void**>(target + code_size + 8) = &copyConstruct;
}

static void GenerateDestructorTrampoline(unsigned char* target,
                                         typelib_TypeDescription* pTD) noexcept
{
    // ldr x1, #12
    // ldr x2, #20
    // br x2
    // pTD
    // &destruct
    static const char code[] = "\x61\x00\x00\x58\x82\x00\x00\x58\x40\x00\x1f\xd6";
    static_assert(sizeof(code) == 13);
    static const unsigned int code_size = sizeof(code) - 1;

    memcpy(target, code, code_size);
    *reinterpret_cast<void**>(target + code_size) = pTD;
    *reinterpret_cast<void**>(target + code_size + 8) = &destruct;
}

ExceptionType::ExceptionType(unsigned char* pCode, sal_uInt64 pCodeBase,
                             typelib_TypeDescription* pTD) noexcept
    : _n0(0)
    , _n1(0)
    , _n2(-1)
    , _n3(0)
    , _n4(pTD->nSize)
    , exc_type_info(nullptr, "")
{
    // As _n0 is always initialized to zero, that means the
    // hasvirtbase flag (see the ONTL catchabletype struct) is
    // off, and thus the copyctor is of the ctor_ptr kind.

    int len;
    type_info* pRTTI = RTTInfos::get(pTD->pTypeName, &len);

    memcpy(static_cast<void*>(&exc_type_info), static_cast<void*>(pRTTI), len);
    _pTypeInfo = static_cast<sal_uInt32>(reinterpret_cast<sal_uInt64>(&exc_type_info) - pCodeBase);
    GenerateCopyConstructorTrampoline(pCode, pTD);

    assert(pCodeBase <= reinterpret_cast<sal_uInt64>(pCode)
           && (reinterpret_cast<sal_uInt64>(pCode) - pCodeBase < 0x100000000));
    _pCopyCtor = static_cast<sal_uInt32>(reinterpret_cast<sal_uInt64>(pCode) - pCodeBase);
}

/* Rewrite of 32-Bit-Code to work under 64 Bit:
* To use the 32 Bit offset values in the ExceptionType we have to
* allocate a single allocation block and use it for all code and date
* all offsets inside this area are guaranteed to be in 32 bit address range.
* So we have to calc total memory allocation size for D-tor, C-Tors,
* ExceptionType and type_info. ExceptionType is allocated via placement new
* to locate everything inside our mem block.
* There is one caveat: Struct type_info is kept in
* a map and was referenced from class ExceptionType. Therefore type_info now
* is also member of ExceptionType and can be referenced via 32 bit offset.
*/

RaiseInfo::RaiseInfo(typelib_TypeDescription* pTD) noexcept
    : _n0(0)
    , _n2(0)
    , _pTD(pTD)
{
    typelib_CompoundTypeDescription* pCompTD;

    // Count how many trampolines we need
    int codeSize = nCodeSnippetSize;

    // Info count
    int nLen = 0;
    for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
         pCompTD = pCompTD->pBaseTypeDescription)
    {
        ++nLen;
        codeSize += nCodeSnippetSize;
    }

    // Array with size (4) and all _pTypeInfo (4*nLen)
    int typeInfoArraySize = 4 + 4 * nLen;

    // 2.Pass: Get the total needed memory for class ExceptionType
    // (with embedded type_info) and keep the sizes for each instance
    // is stored in allocated int array
    auto exceptionTypeSizeArray = std::make_unique<int[]>(nLen);

    nLen = 0;
    for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
         pCompTD = pCompTD->pBaseTypeDescription)
    {
        int typeInfoLen;
        RTTInfos::get(pCompTD->aBase.pTypeName, &typeInfoLen);
        // Mem has to be on 4-byte Boundary
        if (typeInfoLen % 4 != 0)
        {
            int n = typeInfoLen / 4;
            n++;
            typeInfoLen = n * 4;
        }
        exceptionTypeSizeArray[nLen++] = typeInfoLen + sizeof(ExceptionType);
    }

    // Total ExceptionType related mem
    int excTypeAddLen = 0;
    for (int i = 0; i < nLen; i++)
    {
        excTypeAddLen += exceptionTypeSizeArray[i];
    }

    // Allocate mem for code and all dynamic data in one chunk to guarantee
    // 32 bit offsets
    const int totalSize = codeSize + typeInfoArraySize + excTypeAddLen;
    unsigned char* pCode = _code = static_cast<unsigned char*>(std::malloc(totalSize));
    int pCodeOffset = 0;

    // New base of types array, starts after Trampoline D-Tor / C-Tors
    DWORD* types = reinterpret_cast<DWORD*>(pCode + codeSize);

    // New base of ExceptionType array, starts after types array
    unsigned char* etMem = pCode + codeSize + typeInfoArraySize;
    int etMemOffset = 0;

    _codeBase = reinterpret_cast<sal_uInt64>(pCode)
                & ~static_cast<sal_uInt64>(ExceptionInfos::allocationGranularity - 1);

    DWORD old_protect;
    bool success = VirtualProtect(pCode, codeSize, PAGE_EXECUTE_READWRITE, &old_protect);
    (void)success;
    assert(success && "VirtualProtect() failed!");

    ::typelib_typedescription_acquire(pTD);

    // Fill pCode with D-Tor code
    GenerateDestructorTrampoline(pCode, pTD);
    _pDtor = static_cast<sal_Int32>(reinterpret_cast<sal_uInt64>(pCode) - _codeBase);
    pCodeOffset += nCodeSnippetSize;

    // Info count accompanied by type info ptrs: type, base type, base base type, ...
    // Keep offset of types_array
    _types = static_cast<sal_Int32>(reinterpret_cast<sal_uInt64>(types) - _codeBase);
    // Fill types: (nLen, _offset to ExceptionType1, ...ExceptionType2, ...)
    types[0] = nLen;

    int nPos = 1;
    for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
         pCompTD = pCompTD->pBaseTypeDescription)
    {
        // Create instance in mem block with placement new
        ExceptionType* et = new (etMem + etMemOffset) ExceptionType(
            pCode + pCodeOffset, _codeBase, reinterpret_cast<typelib_TypeDescription*>(pCompTD));

        // Next trampoline entry offset
        pCodeOffset += nCodeSnippetSize;
        // Next ExceptionType placement offset
        etMemOffset += exceptionTypeSizeArray[nPos - 1];

        // Keep offset of addresses of ET for D-Tor call in ~RaiseInfo
        types[nPos++] = static_cast<DWORD>(reinterpret_cast<sal_uInt64>(et) - _codeBase);
    }
    // Final check: end of address calculation must be end of mem
    assert(etMem + etMemOffset == pCode + totalSize);
}

#pragma pack(pop)

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */