xref: /trunk/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/except.cxx (revision 9c15e1abd703a7953928d7a80655ae1a76a41f6d)
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 
21 // MARKER(update_precomp.py): autogen include statement, do not remove
22 #include "precompiled_bridges.hxx"
23 
24 #if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6))
25 #include <exception>
26 #endif
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <dlfcn.h>
32 #include <cxxabi.h>
33 #include <hash_map>
34 #include <sys/param.h>
35 
36 #include <rtl/strbuf.hxx>
37 #include <rtl/ustrbuf.hxx>
38 #include <osl/diagnose.h>
39 #include <osl/mutex.hxx>
40 
41 #include <com/sun/star/uno/genfunc.hxx>
42 #include "com/sun/star/uno/RuntimeException.hpp"
43 #include <typelib/typedescription.hxx>
44 #include <uno/any2.h>
45 
46 #include "share.hxx"
47 
48 
49 using namespace ::std;
50 using namespace ::osl;
51 using namespace ::rtl;
52 using namespace ::com::sun::star::uno;
53 using namespace ::__cxxabiv1;
54 
55 
56 namespace CPPU_CURRENT_NAMESPACE
57 {
58 
59 namespace {
60 
61 typedef hash_map< void *, typelib_TypeDescription * > ThrownTypes;
62 typedef hash_map< OUString, type_info *, OUStringHash > ObservedRttiMap;
63 
thrownTypes()64 ThrownTypes & thrownTypes()
65 {
66     static ThrownTypes types;
67     return types;
68 }
69 
observedRttis()70 ObservedRttiMap & observedRttis()
71 {
72     static ObservedRttiMap map;
73     return map;
74 }
75 
76 // Guards BOTH thrownTypes() and observedRttis().  Every access to either map
77 // must hold this one mutex; they are plain hash_maps, so an insertion racing a
78 // find or erase is undefined behaviour.  RTTI::m_mutex may be held while
79 // acquiring this one (see RTTI::getRTTI), never the other way round.
exceptionMapsMutex()80 Mutex & exceptionMapsMutex()
81 {
82     static Mutex mutex;
83     return mutex;
84 }
85 
86 // libc++ marks a type_info whose object is not unique across images by setting
87 // the top bit of type_info::__type_name; comparison then falls back to strcmp
88 // of the mangled name (see __non_unique_arm_rtti_bit_impl in <typeinfo>).  On
89 // arm64 Darwin clang emits the typeinfo of every keyless class -- which is every
90 // UNO exception -- hidden and therefore non-unique, so a synthesised object must
91 // set the bit too, or std::type_info::operator== degenerates to an address
92 // comparison and never matches the handler's real typeinfo.
93 sal_uIntPtr const NON_UNIQUE_RTTI_BIT =
94     static_cast< sal_uIntPtr >(1) << (8 * sizeof (sal_uIntPtr) - 1);
95 
siDonor()96 RttiSiClassLayout const * siDonor()
97 {
98     return reinterpret_cast< RttiSiClassLayout const * >( &typeid(RttiDonorDerived) );
99 }
classDonor()100 RttiClassLayout const * classDonor()
101 {
102     return reinterpret_cast< RttiClassLayout const * >( &typeid(RttiDonorBase) );
103 }
104 
105 // Refuse to synthesise unless the donors really have the layout we assume.
rttiDonorsUsable()106 bool rttiDonorsUsable()
107 {
108     return sizeof (void *) == 8
109         && siDonor()->pBase == static_cast< void const * >( classDonor() );
110 }
111 
112 // Mirror the platform's own convention rather than assuming it.
rttiIsNonUnique()113 bool rttiIsNonUnique()
114 {
115     return (siDonor()->nName & NON_UNIQUE_RTTI_BIT) != 0;
116 }
117 
118 }
119 
dummy_can_throw_anything(char const *)120 void dummy_can_throw_anything( char const * )
121 {
122 }
123 
124 //==================================================================================================
toUNOname(char const * p)125 static OUString toUNOname( char const * p ) SAL_THROW( () )
126 {
127 #if OSL_DEBUG_LEVEL > 1
128     char const * start = p;
129 #endif
130 
131     // example: N3com3sun4star4lang24IllegalArgumentExceptionE
132 
133     OUStringBuffer buf( 64 );
134     OSL_ASSERT( 'N' == *p );
135     ++p; // skip N
136 
137     while ('E' != *p)
138     {
139         // read chars count
140         long n = (*p++ - '0');
141         while ('0' <= *p && '9' >= *p)
142         {
143             n *= 10;
144             n += (*p++ - '0');
145         }
146         buf.appendAscii( p, n );
147         p += n;
148         if ('E' != *p)
149             buf.append( (sal_Unicode)'.' );
150     }
151 
152 #if OSL_DEBUG_LEVEL > 1
153     OUString ret( buf.makeStringAndClear() );
154     OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
155     fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
156     return ret;
157 #else
158     return buf.makeStringAndClear();
159 #endif
160 }
161 
162 //==================================================================================================
mangledRttiSymbol(OUString const & unoName)163 static OString mangledRttiSymbol( OUString const & unoName ) SAL_THROW( () )
164 {
165     OStringBuffer buf( 64 );
166     buf.append( RTL_CONSTASCII_STRINGPARAM("_ZTIN") );
167     sal_Int32 index = 0;
168     do
169     {
170         OUString token( unoName.getToken( 0, '.', index ) );
171         buf.append( token.getLength() );
172         OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
173         buf.append( c_token );
174     }
175     while (index >= 0);
176     buf.append( 'E' );
177     return buf.makeStringAndClear();
178 }
179 
180 //==================================================================================================
181 class RTTI
182 {
183     typedef hash_map< OUString, type_info *, OUStringHash > t_rtti_map;
184 
185     Mutex m_mutex;
186     t_rtti_map m_rttis;
187     t_rtti_map m_generatedRttis;
188 
189     type_info * synthesiseRTTI(
190         OString const & rSymbolName,
191         typelib_CompoundTypeDescription * pTypeDescr ) SAL_THROW( () );
192 
193 public:
194     RTTI() SAL_THROW( () );
195     ~RTTI() SAL_THROW( () );
196 
197     type_info * getRTTI( typelib_CompoundTypeDescription * ) SAL_THROW( () );
198 };
199 
200 //__________________________________________________________________________________________________
RTTI()201 RTTI::RTTI() SAL_THROW( () )
202 {
203 }
204 
205 //__________________________________________________________________________________________________
~RTTI()206 RTTI::~RTTI() SAL_THROW( () )
207 {
208 }
209 
210 //__________________________________________________________________________________________________
getRTTI(typelib_CompoundTypeDescription * pTypeDescr)211 type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) SAL_THROW( () )
212 {
213     OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
214 
215     // Recursive: synthesiseRTTI() re-enters getRTTI() for the base chain.
216     // osl::Mutex is a PTHREAD_MUTEX_RECURSIVE (sal/osl/unx/mutex.c), so this
217     // is safe.  Lock order against exceptionMapsMutex() is unchanged.
218     MutexGuard guard( m_mutex );
219 
220     {
221         MutexGuard observedGuard( exceptionMapsMutex() );
222         ObservedRttiMap::const_iterator observed( observedRttis().find( unoName ) );
223         if ( observed != observedRttis().end() )
224             return observed->second;
225     }
226 
227     t_rtti_map::const_iterator it = m_rttis.find( unoName );
228     if ( it != m_rttis.end() )
229         return it->second;
230 
231     OString mangled = mangledRttiSymbol( unoName );
232 
233     type_info * p = 0;
234     {
235         void * sym = dlsym( RTLD_DEFAULT, mangled.getStr() );
236         if ( sym )
237             p = *reinterpret_cast< type_info ** >( sym );
238     }
239 
240     if ( p )
241     {
242         m_rttis[ unoName ] = p;
243         return p;
244     }
245 
246     // Fallback: synthesise a type_info object.
247     OString symName = mangled;
248     p = synthesiseRTTI( symName, pTypeDescr );
249     m_rttis[ unoName ] = p;
250     return p;
251 }
252 
253 } // namespace CPPU_CURRENT_NAMESPACE
254