C++
  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  }