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 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_bridges.hxx"
30 
31 #include <cstddef>
32 #include <dlfcn.h>
33 #include <new.h>
34 #include <typeinfo>
35 #include <list>
36 #include <map>
37 #include <rtl/alloc.h>
38 #include <osl/diagnose.h>
39 
40 #include <rtl/strbuf.hxx>
41 #include <typelib/typedescription.hxx>
42 #include <com/sun/star/uno/Any.hxx>
43 
44 #include "bridges/cpp_uno/shared/arraypointer.hxx"
45 
46 #include "cc50_solaris_intel.hxx"
47 
48 #include <hash.cxx>
49 
50 // need a += operator for OString and sal_Char
51 namespace rtl
52 {
53 	inline OString& operator+=( OString& rString, sal_Char cAdd )
54 	{
55 		sal_Char add[2];
56 		add[0] = cAdd;
57 		add[1] = 0;
58 		return rString += add;
59 	}
60 }
61 
62 using namespace std;
63 using namespace osl;
64 using namespace rtl;
65 using namespace com::sun::star::uno;
66 
67 namespace CPPU_CURRENT_NAMESPACE
68 {
69 
70 static OString toUNOname( const OString & rRTTIname )
71 {
72 	OString aRet;
73 
74 	const sal_Char* pRTTI = rRTTIname.getStr();
75 	const sal_Char* pOrg  = pRTTI;
76 	const sal_Char* pLast = pRTTI;
77 
78 	while( 1 )
79 	{
80 		if( *pRTTI == ':' || ! *pRTTI )
81 		{
82 			if( aRet.getLength() )
83 				aRet += ".";
84 			aRet += rRTTIname.copy( pLast - pOrg, pRTTI - pLast );
85 			while( *pRTTI == ':' )
86 				pRTTI++;
87 			pLast = pRTTI;
88 			if( ! *pRTTI )
89 				break;
90 		}
91 		else
92 			pRTTI++;
93 	}
94 
95 	return aRet;
96 }
97 //==================================================================================================
98 static OString toRTTIname( const OString & rUNOname )
99 {
100 	OStringBuffer aRet( rUNOname.getLength()*2 );
101 
102     sal_Int32 nIndex = 0;
103     do
104     {
105         if( nIndex > 0 )
106             aRet.append( "::" );
107         aRet.append( rUNOname.getToken( 0, '.', nIndex ) );
108     } while( nIndex != -1 );
109 
110 	return aRet.makeStringAndClear();
111 }
112 //==================================================================================================
113 
114 static OString toRTTImangledname( const OString & rRTTIname )
115 {
116 	if( ! rRTTIname.getLength() )
117 		return OString();
118 
119 	OStringBuffer aRet( rRTTIname.getLength()*2 );
120 
121     aRet.append( "__1n" );
122     sal_Int32 nIndex = 0;
123     do
124     {
125         OString aToken( rRTTIname.getToken( 0, ':', nIndex ) );
126         int nBytes = aToken.getLength();
127         if( nBytes )
128         {
129             if( nBytes  > 25 )
130             {
131                 aRet.append( (sal_Char)( nBytes/26 + 'a' ) );
132                 aRet.append( (sal_Char)( nBytes%26 + 'A' ) );
133             }
134             else
135                 aRet.append( (sal_Char)( nBytes + 'A' ) );
136             for (sal_Int32 i = 0; i < aToken.getLength(); ++i) {
137                 char c = aToken[i];
138                 if (c == 'Q') {
139                     aRet.append("QdD");
140                 } else {
141                     aRet.append(c);
142                 }
143             }
144         }
145     } while( nIndex != -1 );
146 
147 	aRet.append( '_' );
148 
149 	return aRet.makeStringAndClear();
150 }
151 
152 //##################################################################################################
153 //#### RTTI simulation #############################################################################
154 //##################################################################################################
155 
156 class RTTIHolder
157 {
158 	std::map< OString, void* > aAllRTTI;
159 public:
160 	~RTTIHolder();
161 
162 	void* getRTTI( const OString& rTypename );
163 	void* getRTTI_UnoName( const OString& rUnoTypename )
164 		{ return getRTTI( toRTTIname( rUnoTypename ) ); }
165 
166 	void* insertRTTI( const OString& rTypename );
167 	void* insertRTTI_UnoName( const OString& rTypename )
168 		{ return insertRTTI( toRTTIname( rTypename ) ); }
169 	void* generateRTTI( typelib_CompoundTypeDescription* pCompTypeDescr );
170 };
171 
172 RTTIHolder::~RTTIHolder()
173 {
174 	for ( std::map< OString, void* >::const_iterator iPos( aAllRTTI.begin() );
175 		  iPos != aAllRTTI.end(); ++iPos )
176 	{
177         delete[] static_cast< char * >(iPos->second);
178 	}
179 }
180 
181 #if OSL_DEBUG_LEVEL > 1
182 #include <stdio.h>
183 #endif
184 
185 void* RTTIHolder::getRTTI( const OString& rTypename )
186 {
187 	std::map< OString, void* >::iterator element;
188 
189 	element = aAllRTTI.find( rTypename );
190 	if( element != aAllRTTI.end() )
191 		return (*element).second;
192 
193 	// create rtti structure
194 	element = aAllRTTI.find( rTypename );
195 	if( element != aAllRTTI.end() )
196 		return (*element).second;
197 
198 	return NULL;
199 }
200 
201 static long nMagicId = 1;
202 
203 void* RTTIHolder::insertRTTI( const OString& rTypename )
204 {
205 	OString aMangledName( toRTTImangledname( rTypename ) );
206 	NIST_Hash aHash( aMangledName.getStr(), aMangledName.getLength() );
207 
208 
209 	// rSuperTypename MUST exist !!!
210     std::size_t const RTTI_SIZE = 19; // 14???
211 	void** pRTTI = reinterpret_cast< void ** >(
212         new char[RTTI_SIZE * sizeof (void *) + strlen(rTypename.getStr()) + 1]);
213 	pRTTI[  0 ] = reinterpret_cast< void * >(RTTI_SIZE * sizeof (void *));
214 	pRTTI[  1 ] = NULL;
215 	pRTTI[  2 ] = (void*)(7*sizeof(void*));
216 	pRTTI[  3 ] = (void*)aHash.getHash()[0];
217 	pRTTI[  4 ] = (void*)aHash.getHash()[1];
218 	pRTTI[  5 ] = (void*)aHash.getHash()[2];
219 	pRTTI[  6 ] = (void*)aHash.getHash()[3];
220 	pRTTI[  7 ] = NULL;
221 	pRTTI[  8 ] = NULL;
222 
223 	pRTTI[  9 ] = pRTTI[ 3 ];
224 	pRTTI[ 10 ] = pRTTI[ 4 ];
225 	pRTTI[ 11 ] = pRTTI[ 5 ];
226 	pRTTI[ 12 ] = pRTTI[ 6 ];
227 	pRTTI[ 13 ] = (void*)0x80000000;
228     strcpy(reinterpret_cast< char * >(pRTTI + RTTI_SIZE), rTypename.getStr());
229 
230 	aAllRTTI[ rTypename ] = (void*)pRTTI;
231 #if OSL_DEBUG_LEVEL > 1
232 	fprintf( stderr,
233 			 "generating base RTTI for type %s:\n"
234 			 "   mangled: %s\n"
235 			 "   hash: %.8x %.8x %.8x %.8x\n",
236 			 rTypename.getStr(),
237 			 aMangledName.getStr(),
238 			 pRTTI[ 3 ], pRTTI[ 4 ], pRTTI[ 5 ], pRTTI[ 6 ]
239 			 );
240 #endif
241 	return pRTTI;
242 }
243 
244 void* RTTIHolder::generateRTTI( typelib_CompoundTypeDescription * pCompTypeDescr )
245 {
246 	OString aUNOCompTypeName( OUStringToOString( pCompTypeDescr->aBase.pTypeName, RTL_TEXTENCODING_ASCII_US ) );
247 	OString aRTTICompTypeName( toRTTIname( aUNOCompTypeName ) );
248 
249 	void* pHaveRTTI = getRTTI( aRTTICompTypeName );
250 	if( pHaveRTTI )
251 		return pHaveRTTI;
252 
253 	if( ! pCompTypeDescr->pBaseTypeDescription )
254 		// this is a base type
255 		return insertRTTI( aRTTICompTypeName );
256 
257 	// get base class RTTI
258 	void* pSuperRTTI = generateRTTI( pCompTypeDescr->pBaseTypeDescription );
259 	OSL_ENSURE( pSuperRTTI, "could not generate RTTI for supertype !" );
260 
261 	// find out the size to allocate for RTTI
262 	void** pInherit = (void**)((sal_uInt32)pSuperRTTI + ((sal_uInt32*)pSuperRTTI)[2] + 8);
263 	int nInherit;
264 	for( nInherit = 1; pInherit[ nInherit*5-1 ] != (void*)0x80000000; nInherit++ )
265 		;
266 
267 	OString aMangledName( toRTTImangledname( aRTTICompTypeName ) );
268 	NIST_Hash aHash( aMangledName.getStr(), aMangledName.getLength() );
269 
270     std::size_t const rttiSize = 14 + nInherit * 5;
271 	void** pRTTI = reinterpret_cast< void ** >(
272         new char[
273             rttiSize * sizeof (void *)
274             + strlen(aRTTICompTypeName.getStr()) + 1]);
275 	pRTTI[  0 ] = reinterpret_cast< void * >(rttiSize * sizeof (void *));
276 	pRTTI[  1 ] = NULL;
277 	pRTTI[  2 ] = (void*)(7*sizeof(void*));
278 	pRTTI[  3 ] = (void*)aHash.getHash()[0];
279 	pRTTI[  4 ] = (void*)aHash.getHash()[1];
280 	pRTTI[  5 ] = (void*)aHash.getHash()[2];
281 	pRTTI[  6 ] = (void*)aHash.getHash()[3];
282 	pRTTI[  7 ] = NULL;
283 	pRTTI[  8 ] = NULL;
284 
285 	memcpy( pRTTI+9, pInherit, 4*nInherit*5 );
286 	pRTTI[ 8 +nInherit*5 ] = NULL;
287 	pRTTI[ 9 +nInherit*5 ] = pRTTI[ 3 ];
288 	pRTTI[ 10+nInherit*5 ] = pRTTI[ 4 ];
289 	pRTTI[ 11+nInherit*5 ] = pRTTI[ 5 ];
290 	pRTTI[ 12+nInherit*5 ] = pRTTI[ 6 ];
291 	pRTTI[ 13+nInherit*5 ] = (void*)0x80000000;
292     strcpy(
293         reinterpret_cast< char * >(pRTTI + rttiSize),
294         aRTTICompTypeName.getStr());
295 
296 	aAllRTTI[ aRTTICompTypeName ] = (void*)pRTTI;
297 
298 #if OSL_DEBUG_LEVEL > 1
299 	fprintf( stderr,
300 			 "generating struct RTTI for type %s:\n"
301 			 "   mangled: %s\n"
302 			 "   hash: %.8x %.8x %.8X %.8x\n",
303 			 aRTTICompTypeName.getStr(),
304 			 aMangledName.getStr(),
305 			 pRTTI[ 3 ], pRTTI[ 4 ], pRTTI[ 5 ], pRTTI[ 6 ]
306 			 );
307 #endif
308 
309 	return pRTTI;
310 }
311 
312 //__________________________________________________________________________________________________
313 
314 static void deleteException(
315     void* pExc, unsigned char* thunk, typelib_TypeDescription* pType )
316 {
317  	uno_destructData(
318         pExc, pType, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
319  	typelib_typedescription_release( pType );
320     delete[] thunk;
321 }
322 
323 //__________________________________________________________________________________________________
324 
325 //##################################################################################################
326 //#### exported ####################################################################################
327 //##################################################################################################
328 
329 void cc50_solaris_intel_raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
330 {
331 #if OSL_DEBUG_LEVEL > 1
332     OString cstr(
333         OUStringToOString(
334             *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
335             RTL_TEXTENCODING_ASCII_US ) );
336     fprintf( stderr, "> uno exception occured: %s\n", cstr.getStr() );
337 #endif
338     bridges::cpp_uno::shared::ArrayPointer< unsigned char > thunkPtr(
339         new unsigned char[24]);
340 	typelib_TypeDescription * pTypeDescr = 0;
341 	// will be released by deleteException
342 	typelib_typedescriptionreference_getDescription( &pTypeDescr, pUnoExc->pType );
343 
344 	void* pRTTI;
345 	{
346 	static ::osl::Mutex aMutex;
347 	::osl::Guard< ::osl::Mutex > guard( aMutex );
348 
349 	static RTTIHolder * s_pRTTI = 0;
350 	if (! s_pRTTI)
351 	{
352 #ifdef LEAK_STATIC_DATA
353 		s_pRTTI = new RTTIHolder();
354 #else
355 		static RTTIHolder s_aRTTI;
356 		s_pRTTI = &s_aRTTI;
357 #endif
358 	}
359 
360 	pRTTI = s_pRTTI->generateRTTI( (typelib_CompoundTypeDescription *)pTypeDescr );
361 	}
362 
363 	// a must be
364 	OSL_ENSURE( sizeof(sal_Int32) == sizeof(void *), "### pointer size differs from sal_Int32!" );
365 
366 	void * pCppExc = __Crun::ex_alloc( pTypeDescr->nSize );
367 	uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
368 
369 	// destruct uno exception
370 	uno_any_destruct( pUnoExc, 0 );
371 
372     unsigned char * thunk = thunkPtr.release();
373     // movl %esp, %ecx:
374     thunk[0] = 0x8B;
375     thunk[1] = 0xCC;
376     // pushl pTypeDescr:
377     thunk[2] = 0x68;
378     *reinterpret_cast< void ** >(thunk + 3) = pTypeDescr;
379     // pushl thunk:
380     thunk[7] = 0x68;
381     *reinterpret_cast< void ** >(thunk + 8) = thunk;
382     // pushl 4(%ecx):
383     thunk[12] = 0xFF;
384     thunk[13] = 0x71;
385     thunk[14] = 0x04;
386     // call deleteException:
387     thunk[15] = 0xE8;
388 #pragma disable_warn
389     void * d = reinterpret_cast< void * >(deleteException);
390 #pragma enable_warn
391     *reinterpret_cast< std::ptrdiff_t * >(thunk + 16) =
392         static_cast< unsigned char * >(d) - (thunk + 20);
393     // addl $12, %esp:
394     thunk[20] = 0x83;
395     thunk[21] = 0xC4;
396     thunk[22] = 0x0C;
397     // ret:
398     thunk[23] = 0xC3;
399 
400 #pragma disable_warn
401     void (* f)(void *) = reinterpret_cast< void (*)(void *) >(thunk);
402 #pragma enable_warn
403 	__Crun::ex_throw(pCppExc, (const __Crun::static_type_info*)pRTTI, f);
404 }
405 
406 void cc50_solaris_intel_fillUnoException(
407 	void* pCppExc,
408 	const char* pInfo,
409 	uno_Any* pUnoExc,
410 	uno_Mapping * pCpp2Uno )
411 {
412     OSL_ASSERT( pInfo != 0 );
413     OString uno_name( toUNOname( pInfo ) );
414     OUString aName( OStringToOUString(
415                         uno_name, RTL_TEXTENCODING_ASCII_US ) );
416     typelib_TypeDescription * pExcTypeDescr = 0;
417     typelib_typedescription_getByName( &pExcTypeDescr, aName.pData );
418 
419     if (pExcTypeDescr == 0) // the thing that should not be
420     {
421         RuntimeException aRE(
422             OUString( RTL_CONSTASCII_USTRINGPARAM(
423                           "exception type not found: ") ) + aName,
424             Reference< XInterface >() );
425         Type const & rType = ::getCppuType( &aRE );
426         uno_type_any_constructAndConvert(
427             pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
428 #if OSL_DEBUG_LEVEL > 0
429         OString cstr( OUStringToOString(
430                           aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
431         OSL_ENSURE( 0, cstr.getStr() );
432 #endif
433         return;
434     }
435 
436 #if OSL_DEBUG_LEVEL > 1
437     fprintf( stderr, "> c++ exception occured: %s\n",
438              ::rtl::OUStringToOString(
439                  pExcTypeDescr->pTypeName,
440                  RTL_TEXTENCODING_ASCII_US ).getStr() );
441 #endif
442     // construct uno exception any
443     uno_any_constructAndConvert(
444         pUnoExc, pCppExc, pExcTypeDescr, pCpp2Uno );
445     typelib_typedescription_release( pExcTypeDescr );
446 }
447 
448 }
449 
450