00001
00002
00003
00004
00005 #ifndef VTABLEINFO_HPP
00006 #define VTABLEINFO_HPP
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include <string.h>
00042 #include <pi/compiler.h>
00043
00044 #if defined(_MSC_VER) || defined(__INTEL_COMPILER)
00045
00046
00047
00048
00049 #define GET_ADDR_VIA_CALL
00050 #endif
00051
00052
00053
00054 #define VTP_N_ENTRIES_BEFORE 4
00055
00056
00057 #define VT_VINDEX_IDENTITY_FUNC 1
00058
00059
00060
00061 extern void *g_do_TFA;
00062 extern void *g_do_RA1;
00063
00064
00065
00066 #define MAX_VTABLE_SEARCH 256
00067
00068
00069 int VTableIndex(int ix);
00070
00071
00072
00073 void *VTGetReturnAddress();
00074
00075
00076 template<class Base,class ARG>
00077 struct VTblSizerBase : public Base {
00078 VTblSizerBase() : Base( (ARG)0 ) { }
00079 };
00080
00081
00082 template<class Base>
00083 struct VTblSizerBase<Base,void> : public Base {
00084 VTblSizerBase() : Base() { }
00085 };
00086
00087 template<class Base,class ARG>
00088 struct VTblSizer : public VTblSizerBase<Base,ARG> {
00089 virtual int AVFunc( ){
00090
00091
00092
00093
00094
00095 g_do_RA1 = VTGetReturnAddress();
00096
00097
00098 static int st_counter;
00099
00100
00101
00102
00103
00104
00105
00106 {
00107 #ifdef MSVC_INLINE_ASM
00108
00109
00110
00111
00112 __asm{
00113
00114 mov eax, AVFunc
00115 mov g_do_TFA, eax
00116 }
00117 #elif defined(GNU_INLINE_ASM)
00118
00119 #else
00120
00121 #endif
00122 }
00123
00124 return ++st_counter;
00125 }
00126 };
00127
00128
00129 template <class C>
00130 int GetVIndex( int (C::*mfn)(), void **vtbl ){
00131
00132 void **ppvfn = reinterpret_cast<void**>(&mfn);
00133 void *pvfn = ppvfn ? *ppvfn : NULL;
00134
00135
00136 int mfn_size = sizeof(mfn);
00137
00138 #if defined(__GNUC__) || defined(__VISAGECPP__) || defined(__xlc__) || defined(__xlC__)
00139
00140 if( mfn_size==sizeof(void*)+sizeof(int) ){
00141 int i = *(int*)&mfn;
00142
00143
00144
00145
00146
00147 return (i>0 && i&1) ? i/4 : -1;
00148 }
00149
00150 #elif defined(__BORLANDC__) || defined(__TURBOC__) || defined(__WATCOMC__)
00151 if( mfn_size==sizeof(void*)+2*sizeof(int) ){
00152
00153 int *pi = (int*)(((char*)ppvfn)+sizeof(void*)+sizeof(int));
00154 return (*pi)-1;
00155 }
00156
00157 #elif defined(__MWERKS__)
00158 if( mfn_size==sizeof(void*)+2*sizeof(int) ){
00159
00160 int *pi = (int*)(((char*)ppvfn)+sizeof(int));
00161 return *pi;
00162 }
00163
00164 #elif defined (__sgi) || defined (__EDG__) || defined(__COMO__)
00165
00166 if( mfn_size==2*sizeof(short)+sizeof(void*) ){
00167
00168 int *ps = (short*)(((char*)ppvfn)+sizeof(short));
00169 return (int)*ps;
00170 }
00171
00172 #elif defined (_MSC_VER) || defined(__INTEL_COMPILER)
00173
00174
00175 #endif
00176
00177
00178
00179
00180 void *pvs[3];
00181 pvs[0] = NULL;
00182 pvs[1] = g_do_TFA;
00183 pvs[2] = g_do_RA1;
00184
00185
00186 if( mfn_size==sizeof(void*) ){
00187 if( vtbl && ppvfn )
00188 pvs[0] = pvfn;
00189 }
00190
00191
00192 for( int ix=0; ix<MAX_VTABLE_SEARCH; ix++ ){
00193 if( !vtbl[ix] ) continue;
00194 void *pv = vtbl[ix];
00195 if( pv==pvs[0] || pv==pvs[1] || pv==pvs[2] ||
00196
00197 ((char*)pvs[2]>(char*)pv && (char*)pvs[2]<((char*)pv)+0x20) )
00198 return ix;
00199 }
00200
00201
00202 return -1;
00203 }
00204
00205
00206 template<class C,class ARG>
00207 int GetVTableSizeOf( ){
00208 VTblSizer<C,ARG> vtbs;
00209 int (VTblSizer<C,ARG>::*mfn)() = &VTblSizer<C,ARG>::AVFunc;
00210
00211
00212 g_do_TFA = g_do_RA1 = NULL;
00213 static int st_last_result;
00214 int result = vtbs.AVFunc();
00215 if( result==st_last_result ) return -1;
00216 st_last_result = result;
00217
00218 int ix = GetVIndex( mfn, *(void***)&vtbs );
00219 return ix>=0 ? ix : -1;
00220 }
00221
00222
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 #define VT_MATCH 0x2468ACE0
00239 #define VT_NO_MATCH 0x13579BDF
00240
00241 #define VT_NOT_VIRTUAL -1
00242 #define VT_NOT_FOUND -2
00243 #define VT_NO_VTABLE_FOUND -3
00244 #define VT_ERROR -4
00245
00246 int GetNoMatch();
00247 int GetMatch();
00248
00249
00250 struct VTMemHolder {
00251 VTMemHolder() : m_pc(0) { }
00252 ~VTMemHolder() { delete [] m_pc; }
00253 bool Alloc( int size ) {
00254 delete [] m_pc;
00255 m_pc = new char[size];
00256 return m_pc!=0;
00257 }
00258 void *Get(){ return m_pc; }
00259 char *m_pc;
00260 };
00261
00262
00263 template <class C>
00264 int GetVIndexOf( int (C::*pmf)() ) {
00265 static int vtbl_size = -2;
00266 if( vtbl_size==-2 )
00267 vtbl_size = GetVTableSizeOf<C,void>();
00268 if( vtbl_size<0 ) return VT_NO_VTABLE_FOUND;
00269
00270
00271 static void **vtbl;
00272 if( !vtbl ){
00273 static VTMemHolder st_mh;
00274 int sz = VTableIndex(vtbl_size+1);
00275 if( !st_mh.Alloc(sz*sizeof(void*)) )
00276 return VT_ERROR;
00277 vtbl = (void**)st_mh.Get();
00278 for( int ix=sz-1; ix>=0; ix-- )
00279 vtbl[ix] = (void*)&GetNoMatch;
00280 }
00281
00282
00283 C* pc = (C*)&vtbl;
00284 int ix = 0;
00285 while( ix<vtbl_size ) {
00286 vtbl[VTableIndex(ix)] = (void*)GetMatch;
00287 int r = (pc->*pmf)();
00288 vtbl[VTableIndex(ix)] = (void*)GetNoMatch;
00289 if( r==VT_MATCH ) {
00290 return ix;
00291 }
00292 else if( r!=VT_NO_MATCH ) {
00293 return VT_NOT_VIRTUAL;
00294 }
00295 ix++;
00296 }
00297
00298 return VT_NOT_FOUND;
00299 }
00300
00302
00303
00304
00305
00306
00307 template<class C>
00308 void *GetMFuncAddr( int (C::*pmf)(), C *pc=NULL ){
00309
00310 int vix = GetVIndexOf(pmf);
00311 if( vix>=0 ){
00312 bool did_create = false;
00313 if( !pc ) {
00314 pc = new C;
00315 did_create = true;
00316 }
00317
00318 void *pv = (*(void***)pc)[VTableIndex(vix)];
00319 if( did_create ) delete pc;
00320 return pv;
00321 }
00322 else {
00323
00324
00325
00326
00327 int *pi = (int*)&pmf;
00328 void **ppv = (void**)&pmf;
00329 #if defined(__GNUC__) || defined(__VISAGECPP__) || defined(__xlc__) || defined(__xlC__)
00330
00331
00332 if( !(pi[0]&1) )
00333 return ppv[0];
00334 else
00335
00336 return NULL;
00337
00338 #elif defined(__BORLANDC__) || defined(__TURBOC__) || defined(__WATCOMC__)
00339
00340 return *ppv;
00341
00342 #elif defined(__MWERKS__)
00343
00344 ppv = (void**)(pi+2);
00345 return *ppv;
00346
00347 #elif defined (__sgi) || defined (__EDG__) || defined(__COMO__)
00348
00349 short *ps = (short*)pv;
00350 ppv = (void**)(ps+2);
00351 return *ppv;
00352
00353 #elif defined (__DMC__) || defined(__SC__)
00354
00355 return *ppv;
00356
00357 #elif defined(_MSC_VER)
00358
00359 return *ppv;
00360
00361 #else
00362 #error GetMFuncAddr - Compiler not recognized!
00363 #endif
00364
00365 return NULL;
00366 }
00367 }
00368
00369
00371
00372
00373 #define VTP_N_ENTRIES_BEFORE 4
00374 struct DynObjType;
00375
00376 class VTableInfo {
00377 public:
00378 VTableInfo( void** td, void **to, int sz) : vtbl_d(td), vtbl_o(to), vtbl_r(NULL), size(sz), pdt(NULL) { }
00379 ~VTableInfo(){ delete [] (vtbl_r-VTP_N_ENTRIES_BEFORE); }
00380 bool AllocSoftVTbl(){
00381 void **vtbl_a = new void*[size+VTP_N_ENTRIES_BEFORE];
00382 if( !vtbl_a ) return false;
00383 vtbl_r = vtbl_a+VTP_N_ENTRIES_BEFORE;
00384
00385 memcpy( vtbl_a, vtbl_d-VTP_N_ENTRIES_BEFORE, sizeof(void*)*(size+VTP_N_ENTRIES_BEFORE) );
00386 return true;
00387 }
00388
00389 void **vtbl_d;
00390 void **vtbl_o;
00391 void **vtbl_r;
00392 int size;
00393 DynObjType *pdt;
00394
00395 bool operator == (void** vtbl){ return vtbl_d==vtbl || vtbl_r==vtbl; }
00396 };
00397
00398 #endif // VTABLEINFO_HPP
00399