LibreOffice Module bridges (master) 1
gcc3_linux_aarch64/abi.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 <cassert>
23#include <cstddef>
24#include <cstdint>
25#include <cstring>
26#include <typeinfo>
27
28#include <dlfcn.h>
29
30#include <com/sun/star/uno/RuntimeException.hpp>
31#include <com/sun/star/uno/genfunc.h>
32#include <o3tl/string_view.hxx>
33#include <rtl/strbuf.hxx>
34#include <rtl/ustrbuf.hxx>
35#include <rtl/ustring.hxx>
36#include <sal/types.h>
37#include <typelib/typeclass.h>
38#include <typelib/typedescription.h>
39#include <uno/any2.h>
40#include <uno/mapping.h>
41
42#include "abi.hxx"
43#include <osl/mutex.hxx>
44#include <unordered_map>
45
46namespace {
47
48OUString toUnoName(char const * name) {
49 assert(name != nullptr);
50 OUStringBuffer b;
51 bool scoped = *name == 'N';
52 if (scoped) {
53 ++name;
54 }
55 for (;;) {
56 assert(*name >= '0' && *name <= '9');
57 std::size_t n = *name++ - '0';
58 while (*name >= '0' && *name <= '9') {
59 n = 10 * n + (*name++ - '0');
60 }
61 b.appendAscii(name, n);
62 name += n;
63 if (!scoped) {
64 assert(*name == 0);
65 break;
66 }
67 if (*name == 'E') {
68 assert(name[1] == 0);
69 break;
70 }
71 b.append('.');
72 }
73 return b.makeStringAndClear();
74}
75
76class Rtti {
77public:
78 Rtti(): app_(dlopen(nullptr, RTLD_LAZY)) {}
79
80 ~Rtti() { dlclose(app_); }
81
82 std::type_info * getRtti(typelib_TypeDescription const & type);
83
84private:
85 typedef std::unordered_map<OUString, std::type_info *> Map;
86
87 void * app_;
88
89 osl::Mutex mutex_;
90 Map map_;
91};
92
93std::type_info * Rtti::getRtti(typelib_TypeDescription const & type) {
94 OUString unoName(type.pTypeName);
95 osl::MutexGuard g(mutex_);
96 Map::iterator i(map_.find(unoName));
97 if (i == map_.end()) {
98 OStringBuffer b("_ZTIN");
99 for (sal_Int32 j = 0; j != -1;) {
100 OString t(
102 o3tl::getToken(unoName, 0, '.', j), RTL_TEXTENCODING_ASCII_US));
103 b.append(OString::number(t.getLength()) + t);
104 }
105 b.append('E');
106 OString sym(b.makeStringAndClear());
107 std::type_info * rtti = static_cast<std::type_info *>(
108 dlsym(app_, sym.getStr()));
109 if (rtti == nullptr) {
110 char const * rttiName = strdup(sym.getStr() + std::strlen("_ZTI"));
111 if (rttiName == nullptr) {
112 throw std::bad_alloc();
113 }
114#if defined MACOSX
115 // For the Apple ARM64 ABI, if the most significant ("non-unique RTTI") bit is set, it
116 // means that the instance of the name is not unique (and thus RTTI equality needs to be
117 // determined by string comparison rather than by pointer comparison):
118 rttiName = reinterpret_cast<char const *>(
119 reinterpret_cast<std::uintptr_t>(rttiName) | 0x8000'0000'0000'0000);
120#endif
121 assert(type.eTypeClass == typelib_TypeClass_EXCEPTION);
122 typelib_CompoundTypeDescription const & ctd
123 = reinterpret_cast<typelib_CompoundTypeDescription const &>(
124 type);
125 if (ctd.pBaseTypeDescription == nullptr) {
126 rtti = new __cxxabiv1::__class_type_info(rttiName);
127 } else {
128 std::type_info * base = getRtti(
129 ctd.pBaseTypeDescription->aBase);
131 rttiName,
132 static_cast<__cxxabiv1::__class_type_info *>(base));
133 }
134 }
135 i = map_.insert(Map::value_type(unoName, rtti)).first;
136 }
137 return i->second;
138}
139
140struct theRttiFactory: public rtl::Static<Rtti, theRttiFactory> {};
141
142std::type_info * getRtti(typelib_TypeDescription const & type) {
143 return theRttiFactory::get().getRtti(type);
144}
145
146extern "C" void _GLIBCXX_CDTOR_CALLABI deleteException(void * exception) {
148 static_cast<__cxxabiv1::__cxa_exception *>(exception) - 1;
149#if !defined MACOSX && defined _LIBCPPABI_VERSION // detect libc++abi
150 // First, the libcxxabi commit
151 // <http://llvm.org/viewvc/llvm-project?view=revision&revision=303175>
152 // "[libcxxabi] Align unwindHeader on a double-word boundary" towards
153 // LLVM 5.0 changed the size of __cxa_exception by adding
154 //
155 // __attribute__((aligned))
156 //
157 // to the final member unwindHeader, on x86-64 effectively adding a hole of
158 // size 8 in front of that member (changing its offset from 88 to 96,
159 // sizeof(__cxa_exception) from 120 to 128, and alignof(__cxa_exception)
160 // from 8 to 16); the "header1" hack below to dynamically determine whether we run against a
161 // LLVM 5 libcxxabi is to look at the exceptionDestructor member, which must
162 // point to this function (the use of __cxa_exception in mapException is
163 // unaffected, as it only accesses members towards the start of the struct,
164 // through a pointer known to actually point at the start). The libcxxabi commit
165 // <https://github.com/llvm/llvm-project/commit/9ef1daa46edb80c47d0486148c0afc4e0d83ddcf>
166 // "Insert padding before the __cxa_exception header to ensure the thrown" in LLVM 6
167 // removes the need for this hack, so the "header1" hack can be removed again once we can be
168 // sure that we only run against libcxxabi from LLVM >= 6.
169 //
170 // Second, the libcxxabi commit
171 // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
172 // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility" in LLVM 10 changed
173 // the layout of the start of __cxa_exception to
174 //
175 // [8 byte void *reserve]
176 // 8 byte size_t referenceCount
177 //
178 // so the "header2" hack below to dynamically determine whether we run against a LLVM >= 10
179 // libcxxabi is to look whether the exceptionDestructor (with its known value) has increased its
180 // offset by 8. As described in the definition of __cxa_exception
181 // (bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx), the "header2" hack (together with the
182 // "#ifdef MACOSX" in the definition of __cxa_exception and the corresponding hack in call in
183 // bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx) can be dropped once we can be sure
184 // that we only run against new libcxxabi that has the reserve member.
185 if (header->exceptionDestructor != &deleteException) {
186 auto const header1 = reinterpret_cast<__cxxabiv1::__cxa_exception *>(
187 reinterpret_cast<char *>(header) - 8);
188 if (header1->exceptionDestructor == &deleteException) {
189 header = header1;
190 } else {
191 auto const header2 = reinterpret_cast<__cxxabiv1::__cxa_exception *>(
192 reinterpret_cast<char *>(header) + 8);
193 if (header2->exceptionDestructor == &deleteException) {
194 header = header2;
195 } else {
196 assert(false);
197 }
198 }
199 }
200#endif
201 assert(header->exceptionDestructor == &deleteException);
202 OUString unoName(toUnoName(header->exceptionType->name()));
203 typelib_TypeDescription * td = nullptr;
204 typelib_typedescription_getByName(&td, unoName.pData);
205 assert(td != nullptr);
206 uno_destructData(exception, td, &css::uno::cpp_release);
208}
209
210enum StructKind {
213};
214
215StructKind getStructKind(typelib_CompoundTypeDescription const * type) {
216 StructKind k = type->pBaseTypeDescription == nullptr
217 ? STRUCT_KIND_EMPTY : getStructKind(type->pBaseTypeDescription);
218 for (sal_Int32 i = 0; i != type->nMembers; ++i) {
219 StructKind k2 = StructKind();
220 switch (type->ppTypeRefs[i]->eTypeClass) {
221 case typelib_TypeClass_BOOLEAN:
222 case typelib_TypeClass_BYTE:
223 case typelib_TypeClass_SHORT:
224 case typelib_TypeClass_UNSIGNED_SHORT:
225 case typelib_TypeClass_LONG:
226 case typelib_TypeClass_UNSIGNED_LONG:
227 case typelib_TypeClass_HYPER:
228 case typelib_TypeClass_UNSIGNED_HYPER:
229 case typelib_TypeClass_CHAR:
230 case typelib_TypeClass_ENUM:
231 k2 = STRUCT_KIND_POD;
232 break;
233 case typelib_TypeClass_FLOAT:
235 break;
236 case typelib_TypeClass_DOUBLE:
238 break;
239 case typelib_TypeClass_STRING:
240 case typelib_TypeClass_TYPE:
241 case typelib_TypeClass_ANY:
242 case typelib_TypeClass_SEQUENCE:
243 case typelib_TypeClass_INTERFACE:
244 k2 = STRUCT_KIND_DTOR;
245 break;
246 case typelib_TypeClass_STRUCT:
247 {
248 typelib_TypeDescription * td = nullptr;
249 TYPELIB_DANGER_GET(&td, type->ppTypeRefs[i]);
250 k2 = getStructKind(
251 reinterpret_cast<typelib_CompoundTypeDescription const *>(
252 td));
253 TYPELIB_DANGER_RELEASE(td);
254 break;
255 }
256 default:
257 assert(false);
258 }
259 switch (k2) {
261 // this means an empty sub-object, which nevertheless obtains a byte
262 // of storage (TODO: does it?), so the full object cannot be a
263 // homogeneous collection of float or double
264 case STRUCT_KIND_POD:
265 assert(k != STRUCT_KIND_DTOR);
266 k = STRUCT_KIND_POD;
267 break;
270 if (k == STRUCT_KIND_EMPTY) {
271 k = k2;
272 } else if (k != k2) {
273 assert(k != STRUCT_KIND_DTOR);
274 k = STRUCT_KIND_POD;
275 }
276 break;
277 case STRUCT_KIND_DTOR:
278 return STRUCT_KIND_DTOR;
279 }
280 }
281 return k;
282}
283
284}
285
286namespace abi_aarch64 {
287
289 __cxxabiv1::__cxa_exception * exception, std::type_info const * type, uno_Any * any, uno_Mapping * mapping)
290{
291 assert(exception != nullptr);
292 assert(type != nullptr);
293 OUString unoName(toUnoName(type->name()));
294 typelib_TypeDescription * td = nullptr;
295 typelib_typedescription_getByName(&td, unoName.pData);
296 if (td == nullptr) {
297 css::uno::RuntimeException e("exception type not found: " + unoName);
299 any, &e,
301 mapping);
302 } else {
303 uno_any_constructAndConvert(any, exception->adjustedPtr, td, mapping);
305 }
306}
307
308void raiseException(uno_Any * any, uno_Mapping * mapping) {
309 typelib_TypeDescription * td = nullptr;
310 TYPELIB_DANGER_GET(&td, any->pType);
311 if (td == nullptr) {
312 throw css::uno::RuntimeException(
313 "no typedescription for " + OUString::unacquired(&any->pType->pTypeName));
314 }
315 void * exc = __cxxabiv1::__cxa_allocate_exception(td->nSize);
316 uno_copyAndConvertData(exc, any->pData, td, mapping);
317 uno_any_destruct(any, nullptr);
318 std::type_info * rtti = getRtti(*td);
319 TYPELIB_DANGER_RELEASE(td);
321}
322
324 switch (type->eTypeClass) {
325 default:
326 assert(false);
327#ifdef NDEBUG
328 [[fallthrough]];
329#endif
330 case typelib_TypeClass_VOID:
331 case typelib_TypeClass_BOOLEAN:
332 case typelib_TypeClass_BYTE:
333 case typelib_TypeClass_SHORT:
334 case typelib_TypeClass_UNSIGNED_SHORT:
335 case typelib_TypeClass_LONG:
336 case typelib_TypeClass_UNSIGNED_LONG:
337 case typelib_TypeClass_HYPER:
338 case typelib_TypeClass_UNSIGNED_HYPER:
339 case typelib_TypeClass_FLOAT:
340 case typelib_TypeClass_DOUBLE:
341 case typelib_TypeClass_CHAR:
342 case typelib_TypeClass_ENUM:
343 assert(type->nSize <= 16);
344 return RETURN_KIND_REG;
345 case typelib_TypeClass_STRING:
346 case typelib_TypeClass_TYPE:
347 case typelib_TypeClass_ANY:
348 case typelib_TypeClass_SEQUENCE:
349 case typelib_TypeClass_INTERFACE:
351 case typelib_TypeClass_STRUCT:
352 if (type->nSize > 16) {
354 }
355 switch (getStructKind(
356 reinterpret_cast<typelib_CompoundTypeDescription const *>(
357 type)))
358 {
363 case STRUCT_KIND_DTOR:
365 default:
366 return RETURN_KIND_REG;
367 }
368 }
369}
370
371}
372
373/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr sal_Int8 header[]
XPropertyListType t
const Any & any
void SAL_CALL uno_type_any_constructAndConvert(uno_Any *pDest, void *pSource, typelib_TypeDescriptionReference *pType, uno_Mapping *mapping) SAL_THROW_EXTERN_C()
void SAL_CALL uno_any_constructAndConvert(uno_Any *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_Mapping *mapping) SAL_THROW_EXTERN_C()
void SAL_CALL uno_any_destruct(uno_Any *pValue, uno_ReleaseFunc release) SAL_THROW_EXTERN_C()
std::mutex mutex_
void SAL_CALL uno_destructData(void *pValue, typelib_TypeDescription *pTypeDescr, uno_ReleaseFunc release) SAL_THROW_EXTERN_C()
void SAL_CALL uno_copyAndConvertData(void *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_Mapping *mapping) SAL_THROW_EXTERN_C()
void const * base
char const * name
#define _GLIBCXX_CDTOR_CALLABI
sal_Int64 n
struct _uno_Mapping uno_Mapping
Definition: msvc/except.hxx:33
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:53
struct _uno_Any uno_Any
Definition: msvc/except.hxx:32
@ STRUCT_KIND_FLOAT
@ STRUCT_KIND_DTOR
@ STRUCT_KIND_DOUBLE
@ STRUCT_KIND_POD
@ STRUCT_KIND_EMPTY
static StructKind getStructKind(typelib_CompoundTypeDescription const *type)
static void deleteException(void *pExc)
void __cxa_throw(void *thrown_exception, std::type_info *tinfo, void(*dest)(void *)) __attribute__((noreturn))
void * __cxa_allocate_exception(size_t thrown_size)
ReturnKind getReturnKind(typelib_TypeDescription const *type)
void raiseException(uno_Any *any, uno_Mapping *mapping)
void mapException(__cxxabiv1::__cxa_exception *exception, std::type_info const *type, uno_Any *any, uno_Mapping *mapping)
int i
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
std::type_info * getRtti(typelib_TypeDescription const &type)
Definition: rtti.cxx:265
std::map< OUString, rtl::Reference< Entity > > const & map_
void SAL_CALL typelib_typedescription_release(typelib_TypeDescription *pTD) SAL_THROW_EXTERN_C()
void SAL_CALL typelib_typedescription_getByName(typelib_TypeDescription **ppRet, rtl_uString *pName) SAL_THROW_EXTERN_C()
ResultType type