1*0bd9e244Spfg /**************************************************************
2*0bd9e244Spfg  *
3*0bd9e244Spfg  * Licensed to the Apache Software Foundation (ASF) under one
4*0bd9e244Spfg  * or more contributor license agreements.  See the NOTICE file
5*0bd9e244Spfg  * distributed with this work for additional information
6*0bd9e244Spfg  * regarding copyright ownership.  The ASF licenses this file
7*0bd9e244Spfg  * to you under the Apache License, Version 2.0 (the
8*0bd9e244Spfg  * "License"); you may not use this file except in compliance
9*0bd9e244Spfg  * with the License.  You may obtain a copy of the License at
10*0bd9e244Spfg  *
11*0bd9e244Spfg  *   http://www.apache.org/licenses/LICENSE-2.0
12*0bd9e244Spfg  *
13*0bd9e244Spfg  * Unless required by applicable law or agreed to in writing,
14*0bd9e244Spfg  * software distributed under the License is distributed on an
15*0bd9e244Spfg  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*0bd9e244Spfg  * KIND, either express or implied.  See the License for the
17*0bd9e244Spfg  * specific language governing permissions and limitations
18*0bd9e244Spfg  * under the License.
19*0bd9e244Spfg  *
20*0bd9e244Spfg  *************************************************************/
21*0bd9e244Spfg 
22*0bd9e244Spfg 
23*0bd9e244Spfg 
24*0bd9e244Spfg #include <stdio.h>
25*0bd9e244Spfg #include <string.h>
26*0bd9e244Spfg #include <dlfcn.h>
27*0bd9e244Spfg #include <cxxabi.h>
28*0bd9e244Spfg #include <hash_map>
29*0bd9e244Spfg 
30*0bd9e244Spfg #include <rtl/strbuf.hxx>
31*0bd9e244Spfg #include <rtl/ustrbuf.hxx>
32*0bd9e244Spfg #include <osl/diagnose.h>
33*0bd9e244Spfg #include <osl/mutex.hxx>
34*0bd9e244Spfg 
35*0bd9e244Spfg #include <com/sun/star/uno/genfunc.hxx>
36*0bd9e244Spfg #include "com/sun/star/uno/RuntimeException.hpp"
37*0bd9e244Spfg #include <typelib/typedescription.hxx>
38*0bd9e244Spfg #include <uno/any2.h>
39*0bd9e244Spfg 
40*0bd9e244Spfg #include "share.hxx"
41*0bd9e244Spfg 
42*0bd9e244Spfg 
43*0bd9e244Spfg using namespace ::std;
44*0bd9e244Spfg using namespace ::osl;
45*0bd9e244Spfg using namespace ::rtl;
46*0bd9e244Spfg using namespace ::com::sun::star::uno;
47*0bd9e244Spfg using namespace ::__cxxabiv1;
48*0bd9e244Spfg 
49*0bd9e244Spfg extern sal_Int32 * pHack;
50*0bd9e244Spfg extern sal_Int32 nHack;
51*0bd9e244Spfg 
52*0bd9e244Spfg namespace CPPU_CURRENT_NAMESPACE
53*0bd9e244Spfg {
dummy_can_throw_anything(char const *)54*0bd9e244Spfg     void dummy_can_throw_anything( char const * )
55*0bd9e244Spfg     {
56*0bd9e244Spfg     }
57*0bd9e244Spfg 
58*0bd9e244Spfg     //===================================================================
toUNOname(char const * p)59*0bd9e244Spfg     static OUString toUNOname( char const * p ) SAL_THROW( () )
60*0bd9e244Spfg     {
61*0bd9e244Spfg #if OSL_DEBUG_LEVEL > 1
62*0bd9e244Spfg         char const * start = p;
63*0bd9e244Spfg #endif
64*0bd9e244Spfg 
65*0bd9e244Spfg         // example: N3com3sun4star4lang24IllegalArgumentExceptionE
66*0bd9e244Spfg 
67*0bd9e244Spfg         OUStringBuffer buf( 64 );
68*0bd9e244Spfg         OSL_ASSERT( 'N' == *p );
69*0bd9e244Spfg         ++p; // skip N
70*0bd9e244Spfg 
71*0bd9e244Spfg         while ('E' != *p)
72*0bd9e244Spfg         {
73*0bd9e244Spfg             // read chars count
74*0bd9e244Spfg             long n = (*p++ - '0');
75*0bd9e244Spfg             while ('0' <= *p && '9' >= *p)
76*0bd9e244Spfg             {
77*0bd9e244Spfg                 n *= 10;
78*0bd9e244Spfg                 n += (*p++ - '0');
79*0bd9e244Spfg             }
80*0bd9e244Spfg             buf.appendAscii( p, n );
81*0bd9e244Spfg             p += n;
82*0bd9e244Spfg             if ('E' != *p)
83*0bd9e244Spfg                 buf.append( (sal_Unicode)'.' );
84*0bd9e244Spfg         }
85*0bd9e244Spfg 
86*0bd9e244Spfg #if OSL_DEBUG_LEVEL > 1
87*0bd9e244Spfg         OUString ret( buf.makeStringAndClear() );
88*0bd9e244Spfg         OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
89*0bd9e244Spfg         fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
90*0bd9e244Spfg         return ret;
91*0bd9e244Spfg #else
92*0bd9e244Spfg         return buf.makeStringAndClear();
93*0bd9e244Spfg #endif
94*0bd9e244Spfg     }
95*0bd9e244Spfg 
96*0bd9e244Spfg     //=====================================================================
97*0bd9e244Spfg     class RTTI
98*0bd9e244Spfg     {
99*0bd9e244Spfg         typedef hash_map< OUString, type_info *, OUStringHash > t_rtti_map;
100*0bd9e244Spfg 
101*0bd9e244Spfg         Mutex m_mutex;
102*0bd9e244Spfg         t_rtti_map m_rttis;
103*0bd9e244Spfg         t_rtti_map m_generatedRttis;
104*0bd9e244Spfg 
105*0bd9e244Spfg         void * m_hApp;
106*0bd9e244Spfg 
107*0bd9e244Spfg     public:
108*0bd9e244Spfg         RTTI() SAL_THROW( () );
109*0bd9e244Spfg         ~RTTI() SAL_THROW( () );
110*0bd9e244Spfg 
111*0bd9e244Spfg         type_info * getRTTI(typelib_CompoundTypeDescription *) SAL_THROW( () );
112*0bd9e244Spfg     };
113*0bd9e244Spfg     //____________________________________________________________________
RTTI()114*0bd9e244Spfg     RTTI::RTTI() SAL_THROW( () )
115*0bd9e244Spfg         : m_hApp( dlopen( 0, RTLD_LAZY ) )
116*0bd9e244Spfg     {
117*0bd9e244Spfg     }
118*0bd9e244Spfg     //____________________________________________________________________
~RTTI()119*0bd9e244Spfg     RTTI::~RTTI() SAL_THROW( () )
120*0bd9e244Spfg     {
121*0bd9e244Spfg         dlclose( m_hApp );
122*0bd9e244Spfg     }
123*0bd9e244Spfg 
124*0bd9e244Spfg     //____________________________________________________________________
getRTTI(typelib_CompoundTypeDescription * pTypeDescr)125*0bd9e244Spfg     type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) SAL_THROW( () )
126*0bd9e244Spfg     {
127*0bd9e244Spfg         type_info * rtti;
128*0bd9e244Spfg 
129*0bd9e244Spfg         OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
130*0bd9e244Spfg 
131*0bd9e244Spfg         MutexGuard guard( m_mutex );
132*0bd9e244Spfg         t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
133*0bd9e244Spfg         if (iFind == m_rttis.end())
134*0bd9e244Spfg         {
135*0bd9e244Spfg             // RTTI symbol
136*0bd9e244Spfg             OStringBuffer buf( 64 );
137*0bd9e244Spfg             buf.append( RTL_CONSTASCII_STRINGPARAM("_ZTIN") );
138*0bd9e244Spfg             sal_Int32 index = 0;
139*0bd9e244Spfg             do
140*0bd9e244Spfg             {
141*0bd9e244Spfg                 OUString token( unoName.getToken( 0, '.', index ) );
142*0bd9e244Spfg                 buf.append( token.getLength() );
143*0bd9e244Spfg                 OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
144*0bd9e244Spfg                 buf.append( c_token );
145*0bd9e244Spfg             }
146*0bd9e244Spfg             while (index >= 0);
147*0bd9e244Spfg             buf.append( 'E' );
148*0bd9e244Spfg 
149*0bd9e244Spfg             OString symName( buf.makeStringAndClear() );
150*0bd9e244Spfg             rtti = (type_info *)dlsym( m_hApp, symName.getStr() );
151*0bd9e244Spfg 
152*0bd9e244Spfg             if (rtti)
153*0bd9e244Spfg             {
154*0bd9e244Spfg                 pair< t_rtti_map::iterator, bool > insertion(
155*0bd9e244Spfg                     m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
156*0bd9e244Spfg                 OSL_ENSURE( insertion.second, "### inserting new rtti failed?!" );
157*0bd9e244Spfg             }
158*0bd9e244Spfg             else
159*0bd9e244Spfg             {
160*0bd9e244Spfg                 // try to lookup the symbol in the generated rtti map
161*0bd9e244Spfg                 t_rtti_map::const_iterator iFind2( m_generatedRttis.find( unoName ) );
162*0bd9e244Spfg                 if (iFind2 == m_generatedRttis.end())
163*0bd9e244Spfg                 {
164*0bd9e244Spfg                     // we must generate it !
165*0bd9e244Spfg                     // symbol and rtti-name is nearly identical,
166*0bd9e244Spfg                     // the symbol is prefixed with _ZTI
167*0bd9e244Spfg                     char const * rttiName = symName.getStr() +4;
168*0bd9e244Spfg #if OSL_DEBUG_LEVEL > 1
169*0bd9e244Spfg                     fprintf( stderr,"generated rtti for %s\n", rttiName );
170*0bd9e244Spfg #endif
171*0bd9e244Spfg                     if (pTypeDescr->pBaseTypeDescription)
172*0bd9e244Spfg                     {
173*0bd9e244Spfg                         // ensure availability of base
174*0bd9e244Spfg                         type_info * base_rtti = getRTTI(
175*0bd9e244Spfg                             (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
176*0bd9e244Spfg                         rtti = new __si_class_type_info(
177*0bd9e244Spfg                             strdup( rttiName ), (__class_type_info *)base_rtti );
178*0bd9e244Spfg                     }
179*0bd9e244Spfg                     else
180*0bd9e244Spfg                     {
181*0bd9e244Spfg                         // this class has no base class
182*0bd9e244Spfg                         rtti = new __class_type_info( strdup( rttiName ) );
183*0bd9e244Spfg                     }
184*0bd9e244Spfg 
185*0bd9e244Spfg                     pair< t_rtti_map::iterator, bool > insertion(
186*0bd9e244Spfg                         m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
187*0bd9e244Spfg                     OSL_ENSURE( insertion.second, "### inserting new generated rtti failed?!" );
188*0bd9e244Spfg                 }
189*0bd9e244Spfg                 else // taking already generated rtti
190*0bd9e244Spfg                 {
191*0bd9e244Spfg                     rtti = iFind2->second;
192*0bd9e244Spfg                 }
193*0bd9e244Spfg             }
194*0bd9e244Spfg         }
195*0bd9e244Spfg         else
196*0bd9e244Spfg         {
197*0bd9e244Spfg             rtti = iFind->second;
198*0bd9e244Spfg         }
199*0bd9e244Spfg 
200*0bd9e244Spfg         return rtti;
201*0bd9e244Spfg     }
202*0bd9e244Spfg 
203*0bd9e244Spfg     //------------------------------------------------------------------
deleteException(void * pExc)204*0bd9e244Spfg     static void deleteException( void * pExc )
205*0bd9e244Spfg     {
206*0bd9e244Spfg         __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
207*0bd9e244Spfg         typelib_TypeDescription * pTD = 0;
208*0bd9e244Spfg         OUString unoName( toUNOname( header->exceptionType->name() ) );
209*0bd9e244Spfg         ::typelib_typedescription_getByName( &pTD, unoName.pData );
210*0bd9e244Spfg         OSL_ENSURE( pTD, "### unknown exception type! leaving out destruction => leaking!!!" );
211*0bd9e244Spfg         if (pTD)
212*0bd9e244Spfg         {
213*0bd9e244Spfg             ::uno_destructData( pExc, pTD, cpp_release );
214*0bd9e244Spfg             ::typelib_typedescription_release( pTD );
215*0bd9e244Spfg         }
216*0bd9e244Spfg     }
217*0bd9e244Spfg 
218*0bd9e244Spfg     //==================================================================
raiseException(uno_Any * pUnoExc,uno_Mapping * pUno2Cpp)219*0bd9e244Spfg     void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
220*0bd9e244Spfg     {
221*0bd9e244Spfg #if OSL_DEBUG_LEVEL > 1
222*0bd9e244Spfg         OString cstr(
223*0bd9e244Spfg             OUStringToOString(
224*0bd9e244Spfg                 *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
225*0bd9e244Spfg                 RTL_TEXTENCODING_ASCII_US ) );
226*0bd9e244Spfg         fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
227*0bd9e244Spfg #endif
228*0bd9e244Spfg         void * pCppExc;
229*0bd9e244Spfg         type_info * rtti;
230*0bd9e244Spfg 
231*0bd9e244Spfg         {
232*0bd9e244Spfg         // construct cpp exception object
233*0bd9e244Spfg         typelib_TypeDescription * pTypeDescr = 0;
234*0bd9e244Spfg         TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
235*0bd9e244Spfg         OSL_ASSERT( pTypeDescr );
236*0bd9e244Spfg         if (! pTypeDescr)
237*0bd9e244Spfg         {
238*0bd9e244Spfg             throw RuntimeException(
239*0bd9e244Spfg                 OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get typedescription for type ") ) +
240*0bd9e244Spfg                 *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
241*0bd9e244Spfg                 Reference< XInterface >() );
242*0bd9e244Spfg         }
243*0bd9e244Spfg 
244*0bd9e244Spfg         pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
245*0bd9e244Spfg         ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
246*0bd9e244Spfg 
247*0bd9e244Spfg         // destruct uno exception
248*0bd9e244Spfg         ::uno_any_destruct( pUnoExc, 0 );
249*0bd9e244Spfg         // avoiding locked counts
250*0bd9e244Spfg         static RTTI * s_rtti = 0;
251*0bd9e244Spfg         if (! s_rtti)
252*0bd9e244Spfg         {
253*0bd9e244Spfg             MutexGuard guard( Mutex::getGlobalMutex() );
254*0bd9e244Spfg             if (! s_rtti)
255*0bd9e244Spfg             {
256*0bd9e244Spfg #ifdef LEAK_STATIC_DATA
257*0bd9e244Spfg                 s_rtti = new RTTI();
258*0bd9e244Spfg #else
259*0bd9e244Spfg                 static RTTI rtti_data;
260*0bd9e244Spfg                 s_rtti = &rtti_data;
261*0bd9e244Spfg #endif
262*0bd9e244Spfg             }
263*0bd9e244Spfg         }
264*0bd9e244Spfg         rtti = (type_info *)s_rtti->getRTTI( (typelib_CompoundTypeDescription *) pTypeDescr );
265*0bd9e244Spfg         TYPELIB_DANGER_RELEASE( pTypeDescr );
266*0bd9e244Spfg         OSL_ENSURE( rtti, "### no rtti for throwing exception!" );
267*0bd9e244Spfg         if (! rtti)
268*0bd9e244Spfg         {
269*0bd9e244Spfg             throw RuntimeException(
270*0bd9e244Spfg                 OUString( RTL_CONSTASCII_USTRINGPARAM("no rtti for type ") ) +
271*0bd9e244Spfg                 *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
272*0bd9e244Spfg                 Reference< XInterface >() );
273*0bd9e244Spfg         }
274*0bd9e244Spfg         }
275*0bd9e244Spfg 
276*0bd9e244Spfg 
277*0bd9e244Spfg 	__cxa_throw( pCppExc, rtti, deleteException );
278*0bd9e244Spfg     }
279*0bd9e244Spfg 
280*0bd9e244Spfg #ifdef __ARM_EABI__
getAdjustedPtr(__cxa_exception * header)281*0bd9e244Spfg     static void* getAdjustedPtr(__cxa_exception* header)
282*0bd9e244Spfg     {
283*0bd9e244Spfg         return (void*)header->unwindHeader.barrier_cache.bitpattern[0];
284*0bd9e244Spfg     }
285*0bd9e244Spfg #else
getAdjustedPtr(__cxa_exception * header)286*0bd9e244Spfg     static void* getAdjustedPtr(__cxa_exception* header)
287*0bd9e244Spfg     {
288*0bd9e244Spfg         return header->adjustedPtr;
289*0bd9e244Spfg     }
290*0bd9e244Spfg #endif
291*0bd9e244Spfg 
292*0bd9e244Spfg     //===================================================================
fillUnoException(__cxa_exception * header,uno_Any * pUnoExc,uno_Mapping * pCpp2Uno)293*0bd9e244Spfg     void fillUnoException( __cxa_exception * header, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno )
294*0bd9e244Spfg     {
295*0bd9e244Spfg         if (! header)
296*0bd9e244Spfg         {
297*0bd9e244Spfg             RuntimeException aRE(
298*0bd9e244Spfg                 OUString( RTL_CONSTASCII_USTRINGPARAM("no exception header!") ),
299*0bd9e244Spfg                 Reference< XInterface >() );
300*0bd9e244Spfg             Type const & rType = ::getCppuType( &aRE );
301*0bd9e244Spfg             uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
302*0bd9e244Spfg #if OSL_DEBUG_LEVEL > 0
303*0bd9e244Spfg             OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
304*0bd9e244Spfg             OSL_ENSURE( 0, cstr.getStr() );
305*0bd9e244Spfg #endif
306*0bd9e244Spfg             return;
307*0bd9e244Spfg         }
308*0bd9e244Spfg 
309*0bd9e244Spfg         typelib_TypeDescription * pExcTypeDescr = 0;
310*0bd9e244Spfg         OUString unoName( toUNOname( header->exceptionType->name() ) );
311*0bd9e244Spfg #if OSL_DEBUG_LEVEL > 1
312*0bd9e244Spfg         OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
313*0bd9e244Spfg         fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
314*0bd9e244Spfg #endif
315*0bd9e244Spfg         typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
316*0bd9e244Spfg         if (0 == pExcTypeDescr)
317*0bd9e244Spfg         {
318*0bd9e244Spfg             RuntimeException aRE(
319*0bd9e244Spfg                 OUString( RTL_CONSTASCII_USTRINGPARAM("exception type not found: ") ) + unoName,
320*0bd9e244Spfg                 Reference< XInterface >() );
321*0bd9e244Spfg             Type const & rType = ::getCppuType( &aRE );
322*0bd9e244Spfg             uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
323*0bd9e244Spfg #if OSL_DEBUG_LEVEL > 0
324*0bd9e244Spfg             OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
325*0bd9e244Spfg             OSL_ENSURE( 0, cstr.getStr() );
326*0bd9e244Spfg #endif
327*0bd9e244Spfg         }
328*0bd9e244Spfg         else
329*0bd9e244Spfg         {
330*0bd9e244Spfg             // construct uno exception any
331*0bd9e244Spfg             uno_any_constructAndConvert( pUnoExc, getAdjustedPtr(header), pExcTypeDescr, pCpp2Uno );
332*0bd9e244Spfg             typelib_typedescription_release( pExcTypeDescr );
333*0bd9e244Spfg         }
334*0bd9e244Spfg     }
335*0bd9e244Spfg }
336*0bd9e244Spfg 
337*0bd9e244Spfg /* vi:set tabstop=4 shiftwidth=4 expandtab: */
338