1 /* 2 This is a C++ run-time library for Windows kernel-mode drivers. 3 Copyright (C) 2004 Bo Branten. 4 */ 5 6 /* 7 The following is a modified subset of wine/dlls/msvcrt/cpp.c 8 from version wine20040505. 9 */ 10 11 /* 12 * msvcrt.dll C++ objects 13 * 14 * Copyright 2000 Jon Griffiths 15 * Copyright 2003 Alexandre Julliard 16 * 17 * This library is free software; you can redistribute it and/or 18 * modify it under the terms of the GNU Lesser General Public 19 * License as published by the Free Software Foundation; either 20 * version 2.1 of the License, or (at your option) any later version. 21 * 22 * This library is distributed in the hope that it will be useful, 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 25 * Lesser General Public License for more details. 26 * 27 * You should have received a copy of the GNU Lesser General Public 28 * License along with this library; if not, write to the Free Software 29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 30 */ 31 32 #include <exception> 33 #include <typeinfo> 34 35 extern "C" unsigned char __stdcall IsBadReadPtr(const void*, unsigned int); 36 37 typedef void (*v_table_ptr)(); 38 39 typedef struct _cpp_object 40 { 41 v_table_ptr* vtable; 42 } cpp_object; 43 44 typedef struct _rtti_base_descriptor 45 { 46 type_info* type_descriptor; 47 int num_base_classes; 48 int base_class_offset; 49 unsigned int flags; 50 int unknown1; 51 int unknown2; 52 } rtti_base_descriptor; 53 54 typedef struct _rtti_base_array 55 { 56 const rtti_base_descriptor* bases[3]; /* First element is the class itself */ 57 } rtti_base_array; 58 59 typedef struct _rtti_object_hierachy 60 { 61 int unknown1; 62 int unknown2; 63 int array_len; /* Size of the array pointed to by 'base_classes' */ 64 const rtti_base_array* base_classes; 65 } rtti_object_hierachy; 66 67 typedef struct _rtti_object_locator 68 { 69 int unknown1; 70 int base_class_offset; 71 unsigned int flags; 72 type_info* type_descriptor; 73 const rtti_object_hierachy* type_hierachy; 74 } rtti_object_locator; 75 76 /* Get type info from an object (internal) */ 77 static const rtti_object_locator* RTTI_GetObjectLocator(void* inptr) 78 { 79 cpp_object* cppobj = (cpp_object*) inptr; 80 const rtti_object_locator* obj_locator = 0; 81 82 if (!IsBadReadPtr(cppobj, sizeof(void*)) && 83 !IsBadReadPtr(cppobj->vtable - 1, sizeof(void*)) && 84 !IsBadReadPtr((void*)cppobj->vtable[-1], sizeof(rtti_object_locator))) 85 { 86 obj_locator = (rtti_object_locator*) cppobj->vtable[-1]; 87 } 88 89 return obj_locator; 90 } 91 92 /****************************************************************** 93 * __RTtypeid (MSVCRT.@) 94 * 95 * Retrieve the Run Time Type Information (RTTI) for a C++ object. 96 * 97 * PARAMS 98 * cppobj [I] C++ object to get type information for. 99 * 100 * RETURNS 101 * Success: A type_info object describing cppobj. 102 * Failure: If the object to be cast has no RTTI, a __non_rtti_object 103 * exception is thrown. If cppobj is NULL, a bad_typeid exception 104 * is thrown. In either case, this function does not return. 105 * 106 * NOTES 107 * This function is usually called by compiler generated code as a result 108 * of using one of the C++ dynamic cast statements. 109 */ 110 extern "C" void* __cdecl __RTtypeid(void* inptr) 111 { 112 cpp_object* cppobj = (cpp_object*) inptr; 113 const rtti_object_locator* obj_locator = RTTI_GetObjectLocator(cppobj); 114 115 if (!obj_locator) 116 { 117 if (!cppobj) 118 { 119 throw std::bad_typeid(); 120 } 121 else 122 { 123 throw std::__non_rtti_object(""); 124 } 125 } 126 127 return obj_locator->type_descriptor; 128 } 129 130 /****************************************************************** 131 * __RTDynamicCast (MSVCRT.@) 132 * 133 * Dynamically cast a C++ object to one of its base classes. 134 * 135 * PARAMS 136 * inptr [I] Any C++ object to cast 137 * unknown [I] Reserved, set to 0 138 * SrcType [I] type_info object describing cppobj 139 * TargetType [I] type_info object describing the base class to cast to 140 * isReference [I] TRUE = throw an exception if the cast fails, FALSE = don't 141 * 142 * RETURNS 143 * Success: The address of cppobj, cast to the object described by dst. 144 * Failure: NULL, If the object to be cast has no RTTI, or dst is not a 145 * valid cast for cppobj. If isReference is TRUE, a bad_cast exception 146 * is thrown and this function does not return. 147 * 148 * NOTES 149 * This function is usually called by compiler generated code as a result 150 * of using one of the C++ dynamic cast statements. 151 */ 152 extern "C" void* __cdecl __RTDynamicCast(void* inptr, long unknown, void* SrcType, void* TargetType, int isReference) 153 { 154 cpp_object* cppobj = (cpp_object*) inptr; 155 type_info* src = (type_info*) SrcType; 156 type_info* dst = (type_info*) TargetType; 157 const rtti_object_locator* obj_locator; 158 159 if (unknown) 160 { 161 //DbgPrint("Unknown parameter is non-zero: please report\n"); 162 } 163 164 if (!cppobj) 165 { 166 return 0; 167 } 168 169 obj_locator = RTTI_GetObjectLocator(cppobj); 170 171 /* To cast an object at runtime: 172 * 1.Find out the true type of the object from the typeinfo at vtable[-1] 173 * 2.Search for the destination type in the class hierarchy 174 * 3.If destination type is found, return base object address + dest offset 175 * Otherwise, fail the cast 176 */ 177 if (obj_locator) 178 { 179 int count = 0; 180 const rtti_object_hierachy* obj_bases = obj_locator->type_hierachy; 181 const rtti_base_descriptor* const * base_desc = obj_bases->base_classes->bases; 182 int src_offset = obj_locator->base_class_offset, dst_offset = -1; 183 184 while (count < obj_bases->array_len) 185 { 186 const type_info* typ = (*base_desc)->type_descriptor; 187 188 if (typ == dst) 189 { 190 dst_offset = (*base_desc)->base_class_offset; 191 break; 192 } 193 base_desc++; 194 count++; 195 } 196 if (dst_offset >= 0) 197 { 198 return (void*)((unsigned long)cppobj - src_offset + dst_offset); 199 } 200 } 201 202 /* VC++ sets isReference to 1 when the result of a dynamic_cast is assigned 203 * to a reference, since references cannot be NULL. 204 */ 205 if (isReference) 206 { 207 throw std::bad_cast(); 208 } 209 210 return 0; 211 } 212 213 /****************************************************************** 214 * __RTCastToVoid (MSVCRT.@) 215 * 216 * Dynamically cast a C++ object to a void*. 217 * 218 * PARAMS 219 * cppobj [I] The C++ object to cast 220 * 221 * RETURNS 222 * Success: The base address of the object as a void*. 223 * Failure: NULL, if cppobj is NULL or has no RTTI. 224 * 225 * NOTES 226 * This function is usually called by compiler generated code as a result 227 * of using one of the C++ dynamic cast statements. 228 */ 229 extern "C" void* __cdecl __RTCastToVoid(void* inptr) 230 { 231 cpp_object* cppobj = (cpp_object*) inptr; 232 const rtti_object_locator* obj_locator = RTTI_GetObjectLocator(cppobj); 233 234 if (!obj_locator) 235 { 236 return 0; 237 } 238 239 /* Casts to void* simply cast to the base object */ 240 return (void*)((unsigned long)cppobj - obj_locator->base_class_offset); 241 }