1c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// Copyright (C) 2011 The Android Open Source Project 2c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// All rights reserved. 3c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// 4c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// Redistribution and use in source and binary forms, with or without 5c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// modification, are permitted provided that the following conditions 6c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// are met: 7c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// 1. Redistributions of source code must retain the above copyright 8c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// notice, this list of conditions and the following disclaimer. 9c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// 2. Redistributions in binary form must reproduce the above copyright 10c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// notice, this list of conditions and the following disclaimer in the 11c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// documentation and/or other materials provided with the distribution. 12c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// 3. Neither the name of the project nor the names of its contributors 13c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// may be used to endorse or promote products derived from this software 14c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// without specific prior written permission. 15c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// 16c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 17c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 20c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// SUCH DAMAGE. 27c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// 28c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// dynamic_cast.cc: RTTI support. 29c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// 30c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// References: 31c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// Itanium C++ ABI at http://www.codesourcery.com/public/cxx-abi/abi.html 32c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// IHI0041A C++ Application Binary Interface for the ARM architecture. 33c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner// 34c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 35c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner#include <cxxabi.h> 36c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 37c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner#include <cstddef> 38c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner#include <cassert> 39c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 40c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turnernamespace 41c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner{ 42c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Adjust a pointer by an offset. 43c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 44c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* 45c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner adjust_pointer(const void* p, std::ptrdiff_t off) 46c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 47c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // FIXME: should we align pointer after adjustment? 48c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const char *cp = reinterpret_cast<const char*>(p) + off; 49c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return reinterpret_cast<const void*>(cp); 50c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 51c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 52c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Return the vtable pointer of a polymorphic object pointed by p. 53c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 54c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner inline const void* 55c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner get_vtable(const void* p) 56c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 57c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return *reinterpret_cast<void*const*>(p); 58c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 59c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 60c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Return a pointer to a __class_type_info in a vtable. 61c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 62c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner inline const abi::__class_type_info* 63c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner get_class_type_info(const void* vtable) 64c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 65c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* type_info_ptr = adjust_pointer(vtable, -sizeof(void*)); 66c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return *reinterpret_cast<abi::__class_type_info*const*>(type_info_ptr); 67c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 68c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 69c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Return offset to object in a vtable. 70c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 71c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner inline std::ptrdiff_t 72c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner get_offset_to_top(const void* vtable) 73c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 74c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* type_info_ptr_address = adjust_pointer(vtable, -sizeof(void*)); 75c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* offset_to_top_address = 76c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner adjust_pointer(type_info_ptr_address, -sizeof(std::ptrdiff_t)); 77c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return *reinterpret_cast<const std::ptrdiff_t*>(offset_to_top_address); 78c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 79c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 80c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Return the virtual pointer to the most derived object of referred by a 81c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // pointer p. 82c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 83c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* 84c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner get_most_derived_object(const void* p) 85c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 86c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* vtable = get_vtable(p); 87c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner std::ptrdiff_t offset_to_top = get_offset_to_top(vtable); 88c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return adjust_pointer(p, offset_to_top); 89c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 90c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 91c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // We assume that -1 cannot be a valid pointer to object. 92c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void * const ambiguous_object = 93c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner reinterpret_cast<const void*>(-1); 94c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 95c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Return a pointer to the subobject described by base_info. 96c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 97c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* 98c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner get_subobject(const void* object, 99c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* vtable, 100c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__base_class_type_info* base_info) 101c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 102c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner long offset = base_info->offset(); 103c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (base_info->is_virtual()) 104c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 105c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const std::ptrdiff_t* virtual_base_offset_address = 106c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner static_cast<const std::ptrdiff_t*> (adjust_pointer(vtable, offset)); 107c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner offset = *virtual_base_offset_address; 108c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 109c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return adjust_pointer(object, offset); 110c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 111c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 112c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Helper of __dyanmic_cast to walk the type tree of an object. 113c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 114c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void * 115c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner walk_object(const void *object, 116c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__class_type_info *type, 117c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void *match_object, 118c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__class_type_info *match_type) 119c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 120c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (*type == *match_type) 121c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return (match_object == NULL || object == match_object) ? object : NULL; 122c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 123c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner switch(type->code()) 124c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 125c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner case abi::__class_type_info::CLASS_TYPE_INFO_CODE: 126c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // This isn't not the class you're looking for. 127c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return NULL; 128c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 129c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner case abi::__class_type_info::SI_CLASS_TYPE_INFO_CODE: 130c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // derived type has a single public base at offset 0. 131c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 132c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__si_class_type_info* ti = 133c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner static_cast<const abi::__si_class_type_info*>(type); 134c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return walk_object(object, ti->__base_type, match_object, 135c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner match_type); 136c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 137c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 138c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner case abi::__class_type_info::VMI_CLASS_TYPE_INFO_CODE: 139c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 140c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* vtable = get_vtable(object); 141c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__vmi_class_type_info* ti = 142c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner static_cast<const abi::__vmi_class_type_info*>(type); 143c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 144c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Look at all direct bases. 145c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* result = NULL; 146c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner for (unsigned i = 0; i < ti->__base_count; ++i) 147c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 148c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (!ti->__base_info[i].is_public()) 149c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner continue; 150c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 151c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void *subobject = 152c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner get_subobject(object, vtable, &ti->__base_info[i]); 153c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* walk_subobject_result = 154c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner walk_object(subobject, ti->__base_info[i].__base_type, 155c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner match_object, match_type); 156c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 157c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (walk_subobject_result == ambiguous_object) 158c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return ambiguous_object; 159c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner else if (walk_subobject_result != NULL) 160c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 161c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (result == NULL) 162c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 163c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner result = walk_subobject_result; 164c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 165c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner else if (result != walk_subobject_result) 166c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return ambiguous_object; 167c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 168c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 169c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return result; 170c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 171c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 172c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner default: 173c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner assert(0); 174c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 175c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return NULL; 176c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 177c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 178c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Bookkeeping structure for derived-to-base cast in the general case. 179c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner struct cast_context 180c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 181c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner public: 182c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* object; 183c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__class_type_info *src_type; 184c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__class_type_info *dst_type; 185c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner std::ptrdiff_t src2dst_offset; 186c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 187c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* dst_object; 188c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* result; 189c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 190c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner cast_context(const void* obj, const abi::__class_type_info *src, 191c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__class_type_info *dst, std::ptrdiff_t offset) 192c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner : object(obj), src_type(src), dst_type(dst), src2dst_offset(offset), 193c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner dst_object(NULL), result(NULL) 194c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { } 195c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner }; 196c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 197c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // based-to-derive cast in the general case. 198c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 199c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner void 200c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner base_to_derived_cast(const void *object, 201c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__class_type_info *type, 202c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner cast_context* context) 203c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 204c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* saved_dst_object = context->dst_object; 205c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner bool is_dst_type = *type == *context->dst_type; 206c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (is_dst_type) 207c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner context->dst_object = object; 208c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 209c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (object == context->object 210c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner && context->dst_object != NULL 211c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner && *type == *context->src_type) 212c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 213c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (context->result == NULL) 214c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner context->result = context->dst_object; 215c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner else if (context->result != context->dst_object) 216c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner context->result = ambiguous_object; 217c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner context->dst_object = saved_dst_object; 218c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return; 219c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 220c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 221c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner switch(type->code()) 222c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 223c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner case abi::__class_type_info::CLASS_TYPE_INFO_CODE: 224c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // This isn't not the class you're looking for. 225c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner break; 226c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 227c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner case abi::__class_type_info::SI_CLASS_TYPE_INFO_CODE: 228c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // derived type has a single public base at offset 0. 229c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 230c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__si_class_type_info* ti = 231c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner static_cast<const abi::__si_class_type_info*>(type); 232c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner base_to_derived_cast(object, ti->__base_type, context); 233c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner break; 234c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 235c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 236c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner case abi::__class_type_info::VMI_CLASS_TYPE_INFO_CODE: 237c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 238c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* vtable = get_vtable(object); 239c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__vmi_class_type_info* ti = 240c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner static_cast<const abi::__vmi_class_type_info*>(type); 241c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 242c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Look at all direct bases. 243c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner for (unsigned i = 0; i < ti->__base_count; ++i) 244c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 245c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (!ti->__base_info[i].is_public()) 246c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner continue; 247c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 248c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void *subobject = 249c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner get_subobject(object, vtable, &ti->__base_info[i]); 250c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner base_to_derived_cast(subobject, ti->__base_info[i].__base_type, 251c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner context); 252c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 253c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // FIXME: Use flags in base_info to optimize search. 254c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (context->result == ambiguous_object) 255c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner break; 256c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 257c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner break; 258c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 259c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 260c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner default: 261c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner assert(0); 262c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 263c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner context->dst_object = saved_dst_object; 264c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 265c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner} // namespace 266c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 267c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turnernamespace __cxxabiv1 268c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner{ 269c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner#define DYNAMIC_CAST_NO_HINT -1 270c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner#define DYNAMIC_CAST_NOT_PUBLIC_BASE -2 271c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner#define DYNAMIC_CAST_MULTIPLE_PUBLIC_NONVIRTUAL_BASE -3 272c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 273c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner /* v: source address to be adjusted; nonnull, and since the 274c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * source object is polymorphic, *(void**)v is a virtual pointer. 275c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * src: static type of the source object. 276c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * dst: destination type (the "T" in "dynamic_cast<T>(v)"). 277c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * src2dst_offset: a static hint about the location of the 278c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * source subobject with respect to the complete object; 279c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * special negative values are: 280c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * -1: no hint 281c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * -2: src is not a public base of dst 282c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * -3: src is a multiple public base type but never a 283c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * virtual base type 284c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * otherwise, the src type is a unique public nonvirtual 285c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * base type of dst at offset src2dst_offset from the 286c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner * origin of dst. 287c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner */ 288c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner extern "C" void* 289c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner __dynamic_cast (const void *v, 290c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__class_type_info *src, 291c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__class_type_info *dst, 292c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner std::ptrdiff_t src2dst_offset) 293c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 294c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* most_derived_object = get_most_derived_object(v); 295c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* vtable = get_vtable(most_derived_object); 296c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const abi::__class_type_info* most_derived_class_type_info = 297c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner get_class_type_info(vtable); 298c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 299c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // If T is not a public base type of the most derived class referred 300c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // by v, the cast always fails. 301c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner void* t_object = 302c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const_cast<void*>(walk_object(most_derived_object, 303c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner most_derived_class_type_info, NULL, dst)); 304c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (t_object == NULL) 305c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return NULL; 306c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 307c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // C++ ABI 2.9.7 The dynamic_cast Algorithm: 308c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // 309c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // If, in the most derived object pointed (referred) to by v, v points 310c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // (refers) to a public base class subobject of a T object [note: this can 311c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // be checked at compile time], and if only one object of type T is derived 312c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // from the subobject pointed (referred) to by v, the result is a pointer 313c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // (an lvalue referring) to that T object. 314c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 315c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // We knew that src is not a public base, so base-to-derived cast 316c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // is not possible. This works even if there are multiple subobjects 317c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // of type T in the most derived object. 318c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (src2dst_offset != DYNAMIC_CAST_NOT_PUBLIC_BASE) 319c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner { 320c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // If it is known that v points to a public base class subobject 321c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // of a T object, simply adjust the pointer by the offset. 322c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (t_object != ambiguous_object && src2dst_offset >= 0) 323b5300299788c51394c7f57b32c7e073605e4e22dDavid 'Digit' Turner return const_cast<void*>(adjust_pointer(v, -src2dst_offset)); 324c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 325c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // If there is only one T type subobject, we only need to look at 326c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // there. Otherwise, look for the subobject referred by v in the 327c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // most derived object. 328c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner cast_context context(v, src, dst, src2dst_offset); 329c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (t_object != ambiguous_object) 330c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner base_to_derived_cast(t_object, dst, &context); 331c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner else 332c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner base_to_derived_cast(most_derived_object, 333c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner most_derived_class_type_info, &context); 334c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 335c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (context.result != NULL && context.result != ambiguous_object) 336c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return const_cast<void*>(context.result); 337c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 338c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 339c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // C++ ABI 2.9.7 The dynamic_cast Algorithm: 340c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // 341c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Otherwise, if v points (refers) to a public base class subobject of the 342c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // most derived object, and the type of the most derived object has an 343c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // unambiguous public base class of type T, the result is a pointer (an 344c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // lvalue referring) to the T subobject of the most derived object. 345c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Otherwise, the run-time check fails. 346c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 347c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // Check to see if T is a unambiguous public base class. 348c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner if (t_object == ambiguous_object) 349c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return NULL; 350c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner 351c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner // See if v refers to a public base class subobject. 352c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner const void* v_object = 353c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner walk_object(most_derived_object, most_derived_class_type_info, v, src); 354c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner return v_object == v ? t_object : NULL; 355c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner } 356c38f5f527a59f1d849371d662f8882d325edc3bfDavid 'Digit' Turner} // namespace __cxxabiv1 357