1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 <com/sun/star/uno/RuntimeException.hpp>
30 #include <com/sun/star/uno/genfunc.h>
31 #include <rtl/strbuf.hxx>
32 #include <rtl/ustrbuf.hxx>
33 #include <rtl/ustring.hxx>
34 #include <sal/log.hxx>
35 #include <sal/types.h>
36 #include <typelib/typeclass.h>
37 #include <typelib/typedescription.h>
39 #include <uno/mapping.h>
42 #include <osl/mutex.hxx>
43 #include <unordered_map>
47 OUString
toUnoName(char const * name
) {
50 bool scoped
= *name
== 'N';
55 assert(*name
>= '0' && *name
<= '9');
56 std::size_t n
= *name
++ - '0';
57 while (*name
>= '0' && *name
<= '9') {
58 n
= 10 * n
+ (*name
++ - '0');
60 b
.appendAscii(name
, n
);
72 return b
.makeStringAndClear();
77 Rtti(): app_(dlopen(0, RTLD_LAZY
)) {}
79 ~Rtti() { dlclose(app_
); }
81 std::type_info
* getRtti(typelib_TypeDescription
const & type
);
84 typedef std::unordered_map
<OUString
, std::type_info
*> Map
;
92 std::type_info
* Rtti::getRtti(typelib_TypeDescription
const & type
) {
93 OUString
unoName(type
.pTypeName
);
94 osl::MutexGuard
g(mutex_
);
95 Map::iterator
i(map_
.find(unoName
));
96 if (i
== map_
.end()) {
99 for (sal_Int32 j
= 0; j
!= -1;) {
102 unoName
.getToken(0, '.', j
), RTL_TEXTENCODING_ASCII_US
));
103 b
.append(t
.getLength());
107 OString
sym(b
.makeStringAndClear());
108 std::type_info
* rtti
= static_cast<std::type_info
*>(
109 dlsym(app_
, sym
.getStr()));
112 // Horrible but hopefully temporary hack.
114 // For some reason, with the Xcode 12 betas, when compiling for arm64-apple-macos, the
115 // symbols for the typeinfos for the UNO exception types
116 // (_ZTIN3com3sun4star3uno16RuntimeExceptionE etc) end up as "weak private external" in the
117 // object file, as displayed by "nm -f darwin". We try to look them up with dlsym() above,
118 // but that then fails. So use a hackaround... introduce separate real variables (see end of
119 // this file) that point to these typeinfos.
121 // When compiling for x86_64-apple-macos, the typeinfo symbols end up as "weak external"
126 const OString ptrSym
= "ptr" + sym
;
127 auto ptr
= static_cast<std::type_info
**>(dlsym(app_
, ptrSym
.getStr()));
131 SAL_WARN("bridges", dlerror());
136 char const * rttiName
= sym
.getStr() + std::strlen("_ZTI");
137 assert(type
.eTypeClass
== typelib_TypeClass_EXCEPTION
);
138 typelib_CompoundTypeDescription
const & ctd
139 = reinterpret_cast<typelib_CompoundTypeDescription
const &>(
141 if (ctd
.pBaseTypeDescription
== 0) {
142 rtti
= new __cxxabiv1::__class_type_info(strdup(rttiName
));
144 std::type_info
* base
= getRtti(
145 ctd
.pBaseTypeDescription
->aBase
);
146 rtti
= new __cxxabiv1::__si_class_type_info(
148 static_cast<__cxxabiv1::__class_type_info
*>(base
));
151 i
= map_
.insert(Map::value_type(unoName
, rtti
)).first
;
156 struct theRttiFactory
: public rtl::Static
<Rtti
, theRttiFactory
> {};
158 std::type_info
* getRtti(typelib_TypeDescription
const & type
) {
159 return theRttiFactory::get().getRtti(type
);
162 extern "C" void _GLIBCXX_CDTOR_CALLABI
deleteException(void * exception
) {
163 __cxxabiv1::__cxa_exception
* header
=
164 static_cast<__cxxabiv1::__cxa_exception
*>(exception
) - 1;
165 #if !defined MACOSX && defined _LIBCPPABI_VERSION // detect libc++abi
166 // First, the libcxxabi commit
167 // <http://llvm.org/viewvc/llvm-project?view=revision&revision=303175>
168 // "[libcxxabi] Align unwindHeader on a double-word boundary" towards
169 // LLVM 5.0 changed the size of __cxa_exception by adding
171 // __attribute__((aligned))
173 // to the final member unwindHeader, on x86-64 effectively adding a hole of
174 // size 8 in front of that member (changing its offset from 88 to 96,
175 // sizeof(__cxa_exception) from 120 to 128, and alignof(__cxa_exception)
176 // from 8 to 16); the "header1" hack below to dynamically determine whether we run against a
177 // LLVM 5 libcxxabi is to look at the exceptionDestructor member, which must
178 // point to this function (the use of __cxa_exception in mapException is
179 // unaffected, as it only accesses members towards the start of the struct,
180 // through a pointer known to actually point at the start). The libcxxabi commit
181 // <https://github.com/llvm/llvm-project/commit/9ef1daa46edb80c47d0486148c0afc4e0d83ddcf>
182 // "Insert padding before the __cxa_exception header to ensure the thrown" in LLVM 6
183 // removes the need for this hack, so the "header1" hack can be removed again once we can be
184 // sure that we only run against libcxxabi from LLVM >= 6.
186 // Second, the libcxxabi commit
187 // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
188 // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility" in LLVM 10 changed
189 // the layout of the start of __cxa_exception to
191 // [8 byte void *reserve]
192 // 8 byte size_t referenceCount
194 // so the "header2" hack below to dynamically determine whether we run against a LLVM >= 10
195 // libcxxabi is to look whether the exceptionDestructor (with its known value) has increased its
196 // offset by 8. As described in the definition of __cxa_exception
197 // (bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx), the "header2" hack (together with the
198 // "#ifdef MACOSX" in the definition of __cxa_exception and the corresponding hack in call in
199 // bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx) can be dropped once we can be sure
200 // that we only run against new libcxxabi that has the reserve member.
201 if (header
->exceptionDestructor
!= &deleteException
) {
202 auto const header1
= reinterpret_cast<__cxxabiv1::__cxa_exception
*>(
203 reinterpret_cast<char *>(header
) - 8);
204 if (header1
->exceptionDestructor
== &deleteException
) {
207 auto const header2
= reinterpret_cast<__cxxabiv1::__cxa_exception
*>(
208 reinterpret_cast<char *>(header
) + 8);
209 if (header2
->exceptionDestructor
== &deleteException
) {
217 assert(header
->exceptionDestructor
== &deleteException
);
218 OUString
unoName(toUnoName(header
->exceptionType
->name()));
219 typelib_TypeDescription
* td
= 0;
220 typelib_typedescription_getByName(&td
, unoName
.pData
);
222 uno_destructData(exception
, td
, &css::uno::cpp_release
);
223 typelib_typedescription_release(td
);
227 STRUCT_KIND_EMPTY
, STRUCT_KIND_FLOAT
, STRUCT_KIND_DOUBLE
, STRUCT_KIND_POD
,
231 StructKind
getStructKind(typelib_CompoundTypeDescription
const * type
) {
232 StructKind k
= type
->pBaseTypeDescription
== 0
233 ? STRUCT_KIND_EMPTY
: getStructKind(type
->pBaseTypeDescription
);
234 for (sal_Int32 i
= 0; i
!= type
->nMembers
; ++i
) {
235 StructKind k2
= StructKind();
236 switch (type
->ppTypeRefs
[i
]->eTypeClass
) {
237 case typelib_TypeClass_BOOLEAN
:
238 case typelib_TypeClass_BYTE
:
239 case typelib_TypeClass_SHORT
:
240 case typelib_TypeClass_UNSIGNED_SHORT
:
241 case typelib_TypeClass_LONG
:
242 case typelib_TypeClass_UNSIGNED_LONG
:
243 case typelib_TypeClass_HYPER
:
244 case typelib_TypeClass_UNSIGNED_HYPER
:
245 case typelib_TypeClass_CHAR
:
246 case typelib_TypeClass_ENUM
:
247 k2
= STRUCT_KIND_POD
;
249 case typelib_TypeClass_FLOAT
:
250 k2
= STRUCT_KIND_FLOAT
;
252 case typelib_TypeClass_DOUBLE
:
253 k2
= STRUCT_KIND_DOUBLE
;
255 case typelib_TypeClass_STRING
:
256 case typelib_TypeClass_TYPE
:
257 case typelib_TypeClass_ANY
:
258 case typelib_TypeClass_SEQUENCE
:
259 case typelib_TypeClass_INTERFACE
:
260 k2
= STRUCT_KIND_DTOR
;
262 case typelib_TypeClass_STRUCT
:
264 typelib_TypeDescription
* td
= 0;
265 TYPELIB_DANGER_GET(&td
, type
->ppTypeRefs
[i
]);
267 reinterpret_cast<typelib_CompoundTypeDescription
const *>(
269 TYPELIB_DANGER_RELEASE(td
);
276 case STRUCT_KIND_EMPTY
:
277 // this means an empty sub-object, which nevertheless obtains a byte
278 // of storage (TODO: does it?), so the full object cannot be a
279 // homogeneous collection of float or double
280 case STRUCT_KIND_POD
:
281 assert(k
!= STRUCT_KIND_DTOR
);
284 case STRUCT_KIND_FLOAT
:
285 case STRUCT_KIND_DOUBLE
:
286 if (k
== STRUCT_KIND_EMPTY
) {
288 } else if (k
!= k2
) {
289 assert(k
!= STRUCT_KIND_DTOR
);
293 case STRUCT_KIND_DTOR
:
294 return STRUCT_KIND_DTOR
;
302 namespace abi_aarch64
{
305 __cxxabiv1::__cxa_exception
* exception
, std::type_info
const * type
, uno_Any
* any
, uno_Mapping
* mapping
)
307 assert(exception
!= 0);
308 assert(type
!= nullptr);
309 OUString
unoName(toUnoName(type
->name()));
310 typelib_TypeDescription
* td
= 0;
311 typelib_typedescription_getByName(&td
, unoName
.pData
);
313 css::uno::RuntimeException
e("exception type not found: " + unoName
);
314 uno_type_any_constructAndConvert(
316 cppu::UnoType
<css::uno::RuntimeException
>::get().getTypeLibType(),
319 uno_any_constructAndConvert(any
, exception
->adjustedPtr
, td
, mapping
);
320 typelib_typedescription_release(td
);
324 void raiseException(uno_Any
* any
, uno_Mapping
* mapping
) {
325 typelib_TypeDescription
* td
= 0;
326 TYPELIB_DANGER_GET(&td
, any
->pType
);
328 throw css::uno::RuntimeException(
329 "no typedescription for " + OUString(any
->pType
->pTypeName
));
331 void * exc
= __cxxabiv1::__cxa_allocate_exception(td
->nSize
);
332 uno_copyAndConvertData(exc
, any
->pData
, td
, mapping
);
333 uno_any_destruct(any
, 0);
334 std::type_info
* rtti
= getRtti(*td
);
335 TYPELIB_DANGER_RELEASE(td
);
336 __cxxabiv1::__cxa_throw(exc
, rtti
, deleteException
);
339 ReturnKind
getReturnKind(typelib_TypeDescription
const * type
) {
340 switch (type
->eTypeClass
) {
346 case typelib_TypeClass_VOID
:
347 case typelib_TypeClass_BOOLEAN
:
348 case typelib_TypeClass_BYTE
:
349 case typelib_TypeClass_SHORT
:
350 case typelib_TypeClass_UNSIGNED_SHORT
:
351 case typelib_TypeClass_LONG
:
352 case typelib_TypeClass_UNSIGNED_LONG
:
353 case typelib_TypeClass_HYPER
:
354 case typelib_TypeClass_UNSIGNED_HYPER
:
355 case typelib_TypeClass_FLOAT
:
356 case typelib_TypeClass_DOUBLE
:
357 case typelib_TypeClass_CHAR
:
358 case typelib_TypeClass_ENUM
:
359 assert(type
->nSize
<= 16);
360 return RETURN_KIND_REG
;
361 case typelib_TypeClass_STRING
:
362 case typelib_TypeClass_TYPE
:
363 case typelib_TypeClass_ANY
:
364 case typelib_TypeClass_SEQUENCE
:
365 case typelib_TypeClass_INTERFACE
:
366 return RETURN_KIND_INDIRECT
;
367 case typelib_TypeClass_STRUCT
:
368 if (type
->nSize
> 16) {
369 return RETURN_KIND_INDIRECT
;
371 switch (getStructKind(
372 reinterpret_cast<typelib_CompoundTypeDescription
const *>(
375 case STRUCT_KIND_FLOAT
:
376 return RETURN_KIND_HFA_FLOAT
;
377 case STRUCT_KIND_DOUBLE
:
378 return RETURN_KIND_HFA_DOUBLE
;
379 case STRUCT_KIND_DTOR
:
380 return RETURN_KIND_INDIRECT
;
382 return RETURN_KIND_REG
;
391 // See the comment about the horrible hack above.
393 // This set of types are compiled based on what 'make check' needs, but I haven't been able to run
394 // it completely yet. And of course as such this hack isn't a viable long-term solution.
396 #include <com/sun/star/lang/IllegalArgumentException.hpp>
397 #include <com/sun/star/task/ClassifiedInteractionRequest.hpp>
398 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
399 #include <com/sun/star/ucb/InteractiveIOException.hpp>
400 #include <com/sun/star/ucb/NameClashException.hpp>
401 #include <com/sun/star/uno/Exception.hpp>
404 const std::type_info
* __attribute((visibility("default"),used
)) ptr_ZTIN3com3sun4star4lang24IllegalArgumentExceptionE
= &typeid(css::lang::IllegalArgumentException
);
405 const std::type_info
* __attribute((visibility("default"),used
)) ptr_ZTIN3com3sun4star3uno9ExceptionE
= &typeid(css::uno::Exception
);
406 const std::type_info
* __attribute((visibility("default"),used
)) ptr_ZTIN3com3sun4star3uno16RuntimeExceptionE
= &typeid(css::uno::RuntimeException
);
407 const std::type_info
* __attribute((visibility("default"),used
)) ptr_ZTIN3com3sun4star3ucb31InteractiveAugmentedIOExceptionE
= &typeid(css::ucb::InteractiveAugmentedIOException
);
408 const std::type_info
* __attribute((visibility("default"),used
)) ptr_ZTIN3com3sun4star3ucb22InteractiveIOExceptionE
= &typeid(css::ucb::InteractiveIOException
);
409 const std::type_info
* __attribute((visibility("default"),used
)) ptr_ZTIN3com3sun4star3ucb18NameClashExceptionE
= &typeid(css::ucb::NameClashException
);
410 const std::type_info
* __attribute((visibility("default"),used
)) ptr_ZTIN3com3sun4star4task28ClassifiedInteractionRequestE
= &typeid(css::task::ClassifiedInteractionRequest
);
415 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */