sl@0: // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "ARM EABI LICENCE.txt" sl@0: // which accompanies this distribution, and is available sl@0: // in kernel/eka/compsupp. sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32/compsupp/symaehabi/symbian_rtti.cpp sl@0: // sl@0: // sl@0: sl@0: #include "cxxabi.h" sl@0: #include "unwind_env.h" sl@0: #include "unwinder.h" sl@0: #include "symbian_support.h" sl@0: sl@0: // For information about these classes, se sl@0: // www.codesourcery.com/public/cxx-abi/abi.html#rtti. sl@0: using abi::__class_type_info; sl@0: using abi::__si_class_type_info; sl@0: using abi::__vmi_class_type_info; sl@0: using abi::__base_class_type_info; sl@0: sl@0: sl@0: // Given base class info (aBaseInfo) and a derived object pointer (aDerivedObj), sl@0: // this function implements "cast to base" and stores result in aBaseObj. This sl@0: // essentially sets aBaseObj to point to a memory location that represents sl@0: // aDerivedObj as the given base class. This function requires that aBaseInfo sl@0: // describes a base class of the aDerivedObj's class. sl@0: static void _CastUp(const __base_class_type_info& aBaseInfo, TAny** aDerivedObj, TAny** aBaseObj) sl@0: { sl@0: // Guard against a null pointer for aDerivedObj sl@0: if ( ! (*aDerivedObj) ) sl@0: { sl@0: *aBaseObj = NULL; sl@0: return; sl@0: } sl@0: sl@0: TInt offset = aBaseInfo.__offset_flags >> aBaseInfo.__offset_shift; sl@0: sl@0: if (aBaseInfo.__offset_flags & aBaseInfo.__virtual_mask) sl@0: { sl@0: // For virtual bases, look up offset in vtable + offset. sl@0: sl@0: // Get vtbl pointer as the first 4 bytes of **aDerivedObj sl@0: TUint32* vptr = (TUint32*) ( *( (TUint32*) (*aDerivedObj) ) ); sl@0: sl@0: offset = *( vptr + offset / sizeof(TUint32) ); sl@0: } sl@0: sl@0: // Apply the offset. sl@0: *aBaseObj = (TAny*) ( ( (TUint8*) *aDerivedObj ) + offset ); sl@0: } sl@0: sl@0: sl@0: // For a description of this function, see comments in unwind_env.h. sl@0: extern "C" TBool _DoDerivedToBaseConversion(const std::type_info* aDerivedType, sl@0: const std::type_info* aBaseType, sl@0: TAny** aDerivedObj, sl@0: TAny** aBaseObj) sl@0: { sl@0: sl@0: const std::type_info& type_base_type = typeid(*aBaseType); sl@0: const std::type_info& type_derived_type = typeid(*aDerivedType); sl@0: sl@0: // We must proceed depending on the type of the type_info objects for derived sl@0: // class. sl@0: if ( type_derived_type == typeid(__si_class_type_info) ) sl@0: { sl@0: // The __si_class_type_info means that the derived type has a single, sl@0: // public, non-virtual base, and that the base is at offset zero. We should sl@0: // be able to simply compare the base type from __si_class_type_info with sl@0: // aBaseType sl@0: sl@0: const __si_class_type_info* derived = (const __si_class_type_info*) aDerivedType; sl@0: sl@0: if ( *(derived->__base_type) == *aBaseType ) sl@0: { sl@0: // The types match, work done. sl@0: *aBaseObj = *aDerivedObj; sl@0: return true; sl@0: } sl@0: else sl@0: { sl@0: // The types don't match. We should proceed to comparison with the any sl@0: // classes. In this case there is a single base as follows: sl@0: const __class_type_info* bType = derived->__base_type; sl@0: sl@0: // No pointer adjustment required for __si_class_type_info. sl@0: return _DoDerivedToBaseConversion(bType, aBaseType, aDerivedObj, aBaseObj); sl@0: } sl@0: } sl@0: else if ( type_derived_type == typeid(__vmi_class_type_info) ) sl@0: { sl@0: // The __vmi_class_type_info is for all other scenarios. We get an array of sl@0: // bases which we need to traverse and do comparison on. sl@0: sl@0: const __vmi_class_type_info* derived = (const __vmi_class_type_info*)aDerivedType; sl@0: sl@0: const unsigned count = derived->__base_count; sl@0: sl@0: for ( unsigned i = 0; i < count; i++ ) sl@0: { sl@0: // Get the base info for this base class sl@0: const __base_class_type_info bInfo = derived->__base_info[i]; sl@0: sl@0: if ( ! ( bInfo.__offset_flags & bInfo.__public_mask) ) sl@0: { sl@0: // The base is non-public base, so the remainder of the hierarchy sl@0: // above this base is of no interest sl@0: continue; sl@0: } sl@0: sl@0: // Get the class type info for this base sl@0: const __class_type_info* bType = bInfo.__base_type; sl@0: sl@0: // First check if the type from the list corresponds to requested base sl@0: // type. sl@0: if ( (*bType) == (*aBaseType) ) sl@0: { sl@0: // Match! Convert the pointer to point to the base. sl@0: _CastUp(bInfo, aDerivedObj, aBaseObj); sl@0: return true; sl@0: } sl@0: sl@0: // No match, we must now recursively delve into superclasses of bType. sl@0: // To do that, we need to advance the derived class pointer to point to sl@0: // the current base class as in bInfo. sl@0: TAny* newDerivedPtr; sl@0: _CastUp(bInfo, aDerivedObj, &newDerivedPtr); sl@0: sl@0: // Now go recursive, substituting aDerivedObj with adjusted pointer and bType instead of aDerivedType sl@0: TBool result = _DoDerivedToBaseConversion(bType, aBaseType, (TAny**)(&newDerivedPtr), aBaseObj); sl@0: sl@0: // Return only if the match is found, otherwise continue with the loop sl@0: if ( result ) sl@0: { sl@0: // Match came back from recursion, pass up. sl@0: return true; sl@0: } sl@0: sl@0: // No match from recursion, advance to next base. sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // assert(0); sl@0: } sl@0: sl@0: // No match was found for aBaseType in the aDerivedType's ancestry. sl@0: return false; sl@0: } sl@0: