30 #include <com/sun/star/uno/RuntimeException.hpp>
31 #include <com/sun/star/uno/genfunc.h>
33 #include <rtl/strbuf.hxx>
34 #include <rtl/ustrbuf.hxx>
35 #include <rtl/ustring.hxx>
37 #include <typelib/typeclass.h>
38 #include <typelib/typedescription.h>
40 #include <uno/mapping.h>
43 #include <osl/mutex.hxx>
44 #include <unordered_map>
48 OUString toUnoName(
char const *
name) {
49 assert(name !=
nullptr);
51 bool scoped = *name ==
'N';
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');
61 b.appendAscii(name, n);
73 return b.makeStringAndClear();
78 Rtti(): app_(dlopen(nullptr, RTLD_LAZY)) {}
80 ~Rtti() { dlclose(app_); }
85 typedef std::unordered_map<OUString, std::type_info *> Map;
94 OUString unoName(type.pTypeName);
95 osl::MutexGuard g(mutex_);
96 Map::iterator
i(
map_.find(unoName));
97 if (i ==
map_.end()) {
100 for (sal_Int32 j = 0; j != -1;) {
104 b.append(
t.getLength());
108 OString sym(b.makeStringAndClear());
109 std::type_info * rtti =
static_cast<std::type_info *
>(
110 dlsym(app_, sym.getStr()));
111 if (rtti ==
nullptr) {
112 char const * rttiName = strdup(sym.getStr() + std::strlen(
"_ZTI"));
113 if (rttiName ==
nullptr) {
114 throw std::bad_alloc();
120 rttiName =
reinterpret_cast<char const *
>(
121 reinterpret_cast<std::uintptr_t
>(rttiName) | 0x8000
'0000'0000
'0000);
123 assert(type.eTypeClass == typelib_TypeClass_EXCEPTION);
124 typelib_CompoundTypeDescription const & ctd
125 = reinterpret_cast<typelib_CompoundTypeDescription const &>(
127 if (ctd.pBaseTypeDescription == nullptr) {
128 rtti = new __cxxabiv1::__class_type_info(rttiName);
130 std::type_info * base = getRtti(
131 ctd.pBaseTypeDescription->aBase);
132 rtti = new __cxxabiv1::__si_class_type_info(
134 static_cast<__cxxabiv1::__class_type_info *>(base));
137 i = map_.insert(Map::value_type(unoName, rtti)).first;
142 struct theRttiFactory: public rtl::Static<Rtti, theRttiFactory> {};
144 std::type_info * getRtti(typelib_TypeDescription const & type) {
145 return theRttiFactory::get().getRtti(type);
148 extern "C" void _GLIBCXX_CDTOR_CALLABI deleteException(void * exception) {
149 __cxxabiv1::__cxa_exception * header =
150 static_cast<__cxxabiv1::__cxa_exception *>(exception) - 1;
151 #if !defined MACOSX && defined _LIBCPPABI_VERSION // detect libc++abi
152 // First, the libcxxabi commit
153 // <http://llvm.org/viewvc/llvm-project?view=revision&revision=303175>
154 // "[libcxxabi] Align unwindHeader on a double-word boundary" towards
155 // LLVM 5.0 changed the size of __cxa_exception by adding
157 // __attribute__((aligned))
159 // to the final member unwindHeader, on x86-64 effectively adding a hole of
160 // size 8 in front of that member (changing its offset from 88 to 96,
161 // sizeof(__cxa_exception) from 120 to 128, and alignof(__cxa_exception)
162 // from 8 to 16); the "header1" hack below to dynamically determine whether we run against a
163 // LLVM 5 libcxxabi is to look at the exceptionDestructor member, which must
164 // point to this function (the use of __cxa_exception in mapException is
165 // unaffected, as it only accesses members towards the start of the struct,
166 // through a pointer known to actually point at the start). The libcxxabi commit
167 // <https://github.com/llvm/llvm-project/commit/9ef1daa46edb80c47d0486148c0afc4e0d83ddcf>
168 // "Insert padding before the __cxa_exception header to ensure the thrown" in LLVM 6
169 // removes the need for this hack, so the "header1" hack can be removed again once we can be
170 // sure that we only run against libcxxabi from LLVM >= 6.
172 // Second, the libcxxabi commit
173 // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
174 // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility" in LLVM 10 changed
175 // the layout of the start of __cxa_exception to
177 // [8 byte void *reserve]
178 // 8 byte size_t referenceCount
180 // so the "header2" hack below to dynamically determine whether we run against a LLVM >= 10
181 // libcxxabi is to look whether the exceptionDestructor (with its known value) has increased its
182 // offset by 8. As described in the definition of __cxa_exception
183 // (bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx), the "header2" hack (together with the
184 // "#ifdef MACOSX" in the definition of __cxa_exception and the corresponding hack in call in
185 // bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx) can be dropped once we can be sure
186 // that we only run against new libcxxabi that has the reserve member.
187 if (header->exceptionDestructor != &deleteException) {
188 auto const header1 = reinterpret_cast<__cxxabiv1::__cxa_exception *>(
189 reinterpret_cast<char *>(header) - 8);
190 if (header1->exceptionDestructor == &deleteException) {
193 auto const header2 = reinterpret_cast<__cxxabiv1::__cxa_exception *>(
194 reinterpret_cast<char *>(header) + 8);
195 if (header2->exceptionDestructor == &deleteException) {
203 assert(header->exceptionDestructor == &deleteException);
204 OUString unoName(toUnoName(header->exceptionType->name()));
205 typelib_TypeDescription * td = nullptr;
206 typelib_typedescription_getByName(&td, unoName.pData);
207 assert(td != nullptr);
208 uno_destructData(exception, td, &css::uno::cpp_release);
209 typelib_typedescription_release(td);
213 STRUCT_KIND_EMPTY, STRUCT_KIND_FLOAT, STRUCT_KIND_DOUBLE, STRUCT_KIND_POD,
217 StructKind getStructKind(typelib_CompoundTypeDescription const * type) {
218 StructKind k = type->pBaseTypeDescription == nullptr
219 ? STRUCT_KIND_EMPTY : getStructKind(type->pBaseTypeDescription);
220 for (sal_Int32 i = 0; i != type->nMembers; ++i) {
221 StructKind k2 = StructKind();
222 switch (type->ppTypeRefs[i]->eTypeClass) {
223 case typelib_TypeClass_BOOLEAN:
224 case typelib_TypeClass_BYTE:
225 case typelib_TypeClass_SHORT:
226 case typelib_TypeClass_UNSIGNED_SHORT:
227 case typelib_TypeClass_LONG:
228 case typelib_TypeClass_UNSIGNED_LONG:
229 case typelib_TypeClass_HYPER:
230 case typelib_TypeClass_UNSIGNED_HYPER:
231 case typelib_TypeClass_CHAR:
232 case typelib_TypeClass_ENUM:
233 k2 = STRUCT_KIND_POD;
235 case typelib_TypeClass_FLOAT:
236 k2 = STRUCT_KIND_FLOAT;
238 case typelib_TypeClass_DOUBLE:
239 k2 = STRUCT_KIND_DOUBLE;
241 case typelib_TypeClass_STRING:
242 case typelib_TypeClass_TYPE:
243 case typelib_TypeClass_ANY:
244 case typelib_TypeClass_SEQUENCE:
245 case typelib_TypeClass_INTERFACE:
246 k2 = STRUCT_KIND_DTOR;
248 case typelib_TypeClass_STRUCT:
250 typelib_TypeDescription * td = nullptr;
251 TYPELIB_DANGER_GET(&td, type->ppTypeRefs[i]);
253 reinterpret_cast<typelib_CompoundTypeDescription const *>(
255 TYPELIB_DANGER_RELEASE(td);
262 case STRUCT_KIND_EMPTY:
263 // this means an empty sub-object, which nevertheless obtains a byte
264 // of storage (TODO: does it?), so the full object cannot be a
265 // homogeneous collection of float or double
266 case STRUCT_KIND_POD:
267 assert(k != STRUCT_KIND_DTOR);
270 case STRUCT_KIND_FLOAT:
271 case STRUCT_KIND_DOUBLE:
272 if (k == STRUCT_KIND_EMPTY) {
274 } else if (k != k2) {
275 assert(k != STRUCT_KIND_DTOR);
279 case STRUCT_KIND_DTOR:
280 return STRUCT_KIND_DTOR;
288 namespace abi_aarch64 {
291 __cxxabiv1::__cxa_exception * exception, std::type_info const * type, uno_Any * any, uno_Mapping * mapping)
293 assert(exception != nullptr);
294 assert(type != nullptr);
295 OUString unoName(toUnoName(type->name()));
296 typelib_TypeDescription * td = nullptr;
297 typelib_typedescription_getByName(&td, unoName.pData);
299 css::uno::RuntimeException e("exception type not found: " + unoName);
300 uno_type_any_constructAndConvert(
302 cppu::UnoType<css::uno::RuntimeException>::get().getTypeLibType(),
305 uno_any_constructAndConvert(any, exception->adjustedPtr, td, mapping);
306 typelib_typedescription_release(td);
310 void raiseException(uno_Any * any, uno_Mapping * mapping) {
311 typelib_TypeDescription * td = nullptr;
312 TYPELIB_DANGER_GET(&td, any->pType);
314 throw css::uno::RuntimeException(
315 "no typedescription for " + OUString::unacquired(&any->pType->pTypeName));
317 void * exc = __cxxabiv1::__cxa_allocate_exception(td->nSize);
318 uno_copyAndConvertData(exc, any->pData, td, mapping);
319 uno_any_destruct(any, nullptr);
320 std::type_info * rtti = getRtti(*td);
321 TYPELIB_DANGER_RELEASE(td);
322 __cxxabiv1::__cxa_throw(exc, rtti, deleteException);
325 ReturnKind getReturnKind(typelib_TypeDescription const * type) {
326 switch (type->eTypeClass) {
332 case typelib_TypeClass_VOID:
333 case typelib_TypeClass_BOOLEAN:
334 case typelib_TypeClass_BYTE:
335 case typelib_TypeClass_SHORT:
336 case typelib_TypeClass_UNSIGNED_SHORT:
337 case typelib_TypeClass_LONG:
338 case typelib_TypeClass_UNSIGNED_LONG:
339 case typelib_TypeClass_HYPER:
340 case typelib_TypeClass_UNSIGNED_HYPER:
341 case typelib_TypeClass_FLOAT:
342 case typelib_TypeClass_DOUBLE:
343 case typelib_TypeClass_CHAR:
344 case typelib_TypeClass_ENUM:
345 assert(type->nSize <= 16);
346 return RETURN_KIND_REG;
347 case typelib_TypeClass_STRING:
348 case typelib_TypeClass_TYPE:
349 case typelib_TypeClass_ANY:
350 case typelib_TypeClass_SEQUENCE:
351 case typelib_TypeClass_INTERFACE:
352 return RETURN_KIND_INDIRECT;
353 case typelib_TypeClass_STRUCT:
354 if (type->nSize > 16) {
355 return RETURN_KIND_INDIRECT;
357 switch (getStructKind(
358 reinterpret_cast<typelib_CompoundTypeDescription const *>(
361 case STRUCT_KIND_FLOAT:
362 return RETURN_KIND_HFA_FLOAT;
363 case STRUCT_KIND_DOUBLE:
364 return RETURN_KIND_HFA_DOUBLE;
365 case STRUCT_KIND_DTOR:
366 return RETURN_KIND_INDIRECT;
368 return RETURN_KIND_REG;
375 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::type_info * getRtti(typelib_TypeDescription const &type)
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
std::map< OUString, rtl::Reference< Entity > > const & map_
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
struct _typelib_TypeDescription typelib_TypeDescription