1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include <stdio.h> 29 #include <dlfcn.h> 30 #include <cxxabi.h> 31 #include <hash_map> 32 33 #include <rtl/strbuf.hxx> 34 #include <rtl/ustrbuf.hxx> 35 #include <osl/diagnose.h> 36 #include <osl/mutex.hxx> 37 38 #include <com/sun/star/uno/genfunc.hxx> 39 #include "com/sun/star/uno/RuntimeException.hpp" 40 #include <typelib/typedescription.hxx> 41 #include <uno/any2.h> 42 43 #include "share.hxx" 44 45 #ifdef TEST 46 #include "test/TestBridgeException.hpp" 47 #endif 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 //YD static handle to this dll, to allow rtti symbol lookup 57 static void* hmod; 58 59 //================================================================================================== 60 //YD required to run test programs, because exe cannot export symbols! 61 #ifdef TEST 62 using namespace ::test; 63 64 void dymmy_TestBridgeException() throw( ::test::TestBridgeException) 65 { 66 throw TestBridgeException(); 67 } 68 #endif 69 70 //================================================================================================== 71 namespace CPPU_CURRENT_NAMESPACE 72 { 73 74 void dummy_can_throw_anything( char const * ) 75 { 76 } 77 78 //================================================================================================== 79 static OUString toUNOname( char const * p ) SAL_THROW( () ) 80 { 81 #if OSL_DEBUG_LEVEL > 1 82 char const * start = p; 83 #endif 84 85 // example: N3com3sun4star4lang24IllegalArgumentExceptionE 86 87 OUStringBuffer buf( 64 ); 88 OSL_ASSERT( 'N' == *p ); 89 ++p; // skip N 90 91 while ('E' != *p) 92 { 93 // read chars count 94 long n = (*p++ - '0'); 95 while ('0' <= *p && '9' >= *p) 96 { 97 n *= 10; 98 n += (*p++ - '0'); 99 } 100 buf.appendAscii( p, n ); 101 p += n; 102 if ('E' != *p) 103 buf.append( (sal_Unicode)'.' ); 104 } 105 106 #if OSL_DEBUG_LEVEL > 1 107 OUString ret( buf.makeStringAndClear() ); 108 OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) ); 109 fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() ); 110 return ret; 111 #else 112 return buf.makeStringAndClear(); 113 #endif 114 } 115 116 //================================================================================================== 117 class RTTI 118 { 119 typedef hash_map< OUString, type_info *, OUStringHash > t_rtti_map; 120 121 Mutex m_mutex; 122 t_rtti_map m_rttis; 123 t_rtti_map m_generatedRttis; 124 125 //void * m_hApp; 126 127 public: 128 RTTI() SAL_THROW( () ); 129 ~RTTI() SAL_THROW( () ); 130 131 type_info * getRTTI( typelib_CompoundTypeDescription * ) SAL_THROW( () ); 132 }; 133 //__________________________________________________________________________________________________ 134 RTTI::RTTI() SAL_THROW( () ) 135 // : m_hApp( dlopen( 0, RTLD_LAZY ) ) 136 { 137 } 138 //__________________________________________________________________________________________________ 139 RTTI::~RTTI() SAL_THROW( () ) 140 { 141 // dlclose( m_hApp ); 142 } 143 144 //__________________________________________________________________________________________________ 145 type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) SAL_THROW( () ) 146 { 147 type_info * rtti = NULL; 148 149 OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName; 150 151 MutexGuard guard( m_mutex ); 152 t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) ); 153 if (iFind == m_rttis.end()) 154 { 155 // RTTI symbol 156 OStringBuffer buf( 64 ); 157 buf.append( RTL_CONSTASCII_STRINGPARAM("__ZTIN") ); 158 sal_Int32 index = 0; 159 do 160 { 161 OUString token( unoName.getToken( 0, '.', index ) ); 162 buf.append( token.getLength() ); 163 OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) ); 164 buf.append( c_token ); 165 } 166 while (index >= 0); 167 buf.append( 'E' ); 168 169 OString symName( buf.makeStringAndClear() ); 170 //rtti = (type_info *)dlsym( m_hApp, symName.getStr() ); 171 if (hmod == NULL) 172 hmod = dlopen( "gcc3_uno.dll", 0); 173 174 if (hmod) 175 rtti = (type_info *)dlsym( hmod, symName.getStr() ); 176 177 if (rtti) 178 { 179 pair< t_rtti_map::iterator, bool > insertion( 180 m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) ); 181 OSL_ENSURE( insertion.second, "### inserting new rtti failed?!" ); 182 } 183 else 184 { 185 // try to lookup the symbol in the generated rtti map 186 t_rtti_map::const_iterator iFind( m_generatedRttis.find( unoName ) ); 187 if (iFind == m_generatedRttis.end()) 188 { 189 // we must generate it ! 190 // symbol and rtti-name is nearly identical, 191 // the symbol is prefixed with __ZTI 192 char const * rttiName = symName.getStr() +5; 193 #if OSL_DEBUG_LEVEL > 1 194 fprintf( stderr,"generated rtti for %s\n", rttiName ); 195 #endif 196 if (pTypeDescr->pBaseTypeDescription) 197 { 198 // ensure availability of base 199 type_info * base_rtti = getRTTI( 200 (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription ); 201 rtti = new __si_class_type_info( 202 strdup( rttiName ), (__class_type_info *)base_rtti ); 203 } 204 else 205 { 206 // this class has no base class 207 rtti = new __class_type_info( strdup( rttiName ) ); 208 } 209 210 pair< t_rtti_map::iterator, bool > insertion( 211 m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) ); 212 OSL_ENSURE( insertion.second, "### inserting new generated rtti failed?!" ); 213 } 214 else // taking already generated rtti 215 { 216 rtti = iFind->second; 217 } 218 } 219 } 220 else 221 { 222 rtti = iFind->second; 223 } 224 225 return rtti; 226 } 227 228 //-------------------------------------------------------------------------------------------------- 229 static void deleteException( void * pExc ) 230 { 231 __cxa_exception const * header = ((__cxa_exception const *)pExc - 1); 232 typelib_TypeDescription * pTD = 0; 233 OUString unoName( toUNOname( header->exceptionType->name() ) ); 234 ::typelib_typedescription_getByName( &pTD, unoName.pData ); 235 OSL_ENSURE( pTD, "### unknown exception type! leaving out destruction => leaking!!!" ); 236 if (pTD) 237 { 238 ::uno_destructData( pExc, pTD, cpp_release ); 239 ::typelib_typedescription_release( pTD ); 240 } 241 } 242 243 //================================================================================================== 244 void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ) 245 { 246 #if OSL_DEBUG_LEVEL > 1 247 OString cstr( 248 OUStringToOString( 249 *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ), 250 RTL_TEXTENCODING_ASCII_US ) ); 251 fprintf( stderr, "> uno exception occured: %s\n", cstr.getStr() ); 252 #endif 253 void * pCppExc; 254 type_info * rtti; 255 256 { 257 // construct cpp exception object 258 typelib_TypeDescription * pTypeDescr = 0; 259 TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType ); 260 OSL_ASSERT( pTypeDescr ); 261 if (! pTypeDescr) 262 { 263 throw RuntimeException( 264 OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get typedescription for type ") ) + 265 *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ), 266 Reference< XInterface >() ); 267 } 268 269 pCppExc = __cxa_allocate_exception( pTypeDescr->nSize ); 270 ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp ); 271 272 // destruct uno exception 273 ::uno_any_destruct( pUnoExc, 0 ); 274 // avoiding locked counts 275 static RTTI * s_rtti = 0; 276 if (! s_rtti) 277 { 278 MutexGuard guard( Mutex::getGlobalMutex() ); 279 if (! s_rtti) 280 { 281 #ifdef LEAK_STATIC_DATA 282 s_rtti = new RTTI(); 283 #else 284 static RTTI rtti_data; 285 s_rtti = &rtti_data; 286 #endif 287 } 288 } 289 rtti = (type_info *)s_rtti->getRTTI( (typelib_CompoundTypeDescription *) pTypeDescr ); 290 TYPELIB_DANGER_RELEASE( pTypeDescr ); 291 OSL_ENSURE( rtti, "### no rtti for throwing exception!" ); 292 if (! rtti) 293 { 294 throw RuntimeException( 295 OUString( RTL_CONSTASCII_USTRINGPARAM("no rtti for type ") ) + 296 *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ), 297 Reference< XInterface >() ); 298 } 299 } 300 301 __cxa_throw( pCppExc, rtti, deleteException ); 302 } 303 304 //================================================================================================== 305 void fillUnoException( __cxa_exception * header, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno ) 306 { 307 if (! header) 308 { 309 RuntimeException aRE( 310 OUString( RTL_CONSTASCII_USTRINGPARAM("no exception header!") ), 311 Reference< XInterface >() ); 312 Type const & rType = ::getCppuType( &aRE ); 313 uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno ); 314 #if OSL_DEBUG_LEVEL > 0 315 OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) ); 316 OSL_ENSURE( 0, cstr.getStr() ); 317 #endif 318 return; 319 } 320 321 typelib_TypeDescription * pExcTypeDescr = 0; 322 OUString unoName( toUNOname( header->exceptionType->name() ) ); 323 #if OSL_DEBUG_LEVEL > 1 324 OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) ); 325 fprintf( stderr, "> c++ exception occured: %s\n", cstr_unoName.getStr() ); 326 #endif 327 typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData ); 328 if (0 == pExcTypeDescr) 329 { 330 RuntimeException aRE( 331 OUString( RTL_CONSTASCII_USTRINGPARAM("exception type not found: ") ) + unoName, 332 Reference< XInterface >() ); 333 Type const & rType = ::getCppuType( &aRE ); 334 uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno ); 335 #if OSL_DEBUG_LEVEL > 0 336 OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) ); 337 OSL_ENSURE( 0, cstr.getStr() ); 338 #endif 339 } 340 else 341 { 342 // construct uno exception any 343 uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno ); 344 typelib_typedescription_release( pExcTypeDescr ); 345 } 346 } 347 348 } 349 350