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