| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | //***************************************************************************** |
| 5 | // File: daccess.h |
| 6 | // |
| 7 | |
| 8 | // |
| 9 | // Support for external access of runtime data structures. These |
| 10 | // macros and templates hide the details of pointer and data handling |
| 11 | // so that data structures and code can be compiled to work both |
| 12 | // in-process and through a special memory access layer. |
| 13 | // |
| 14 | // This code assumes the existence of two different pieces of code, |
| 15 | // the target, the runtime code that is going to be examined, and |
| 16 | // the host, the code that's doing the examining. Access to the |
| 17 | // target is abstracted so the target may be a live process on the |
| 18 | // same machine, a live process on a different machine, a dump file |
| 19 | // or whatever. No assumptions should be made about accessibility |
| 20 | // of the target. |
| 21 | // |
| 22 | // This code assumes that the data in the target is static. Any |
| 23 | // time the target's data changes the interfaces must be reset so |
| 24 | // that potentially stale data is discarded. |
| 25 | // |
| 26 | // This code is intended for read access and there is no |
| 27 | // way to write data back currently. |
| 28 | // |
| 29 | // DAC-ized code: |
| 30 | // - is read-only (non-invasive). So DACized codepaths can not trigger a GC. |
| 31 | // - has no Thread* object. In reality, DAC-ized codepaths are |
| 32 | // ReadProcessMemory calls from out-of-process. Conceptually, they |
| 33 | // are like a pure-native (preemptive) thread. |
| 34 | //// |
| 35 | // This means that in particular, you cannot DACize a GCTRIGGERS function. |
| 36 | // Neither can you DACize a function that throws if this will involve |
| 37 | // allocating a new exception object. There may be |
| 38 | // exceptions to these rules if you can guarantee that the DACized |
| 39 | // part of the code path cannot cause a garbage collection (see |
| 40 | // EditAndContinueModule::ResolveField for an example). |
| 41 | // If you need to DACize a function that may trigger |
| 42 | // a GC, it is probably best to refactor the function so that the DACized |
| 43 | // part of the code path is in a separate function. For instance, |
| 44 | // functions with GetOrCreate() semantics are hard to DAC-ize because |
| 45 | // they the Create portion is inherently invasive. Instead, consider refactoring |
| 46 | // into a GetOrFail() function that DAC can call; and then make GetOrCreate() |
| 47 | // a wrapper around that. |
| 48 | |
| 49 | // |
| 50 | // This code works by hiding the details of access to target memory. |
| 51 | // Access is divided into two types: |
| 52 | // 1. DPTR - access to a piece of data. |
| 53 | // 2. VPTR - access to a class with a vtable. The class can only have |
| 54 | // a single vtable pointer at the beginning of the class instance. |
| 55 | // Things only need to be declared as VPTRs when it is necessary to |
| 56 | // call virtual functions in the host. In that case the access layer |
| 57 | // must do extra work to provide a host vtable for the object when |
| 58 | // it is retrieved so that virtual functions can be called. |
| 59 | // |
| 60 | // When compiling with DACCESS_COMPILE the macros turn into templates |
| 61 | // which replace pointers with smart pointers that know how to fetch |
| 62 | // data from the target process and provide a host process version of it. |
| 63 | // Normal data structure access will transparently receive a host copy |
| 64 | // of the data and proceed, so code such as |
| 65 | // typedef DPTR(Class) PTR_Class; |
| 66 | // PTR_Class cls; |
| 67 | // int val = cls->m_Int; |
| 68 | // will work without modification. The appropriate operators are overloaded |
| 69 | // to provide transparent access, such as the -> operator in this case. |
| 70 | // Note that the convention is to create an appropriate typedef for |
| 71 | // each type that will be accessed. This hides the particular details |
| 72 | // of the type declaration and makes the usage look more like regular code. |
| 73 | // |
| 74 | // The ?PTR classes also have an implicit base type cast operator to |
| 75 | // produce a host-pointer instance of the given type. For example |
| 76 | // Class* cls = PTR_Class(addr); |
| 77 | // works by implicit conversion from the PTR_Class created by wrapping |
| 78 | // to a host-side Class instance. Again, this means that existing code |
| 79 | // can work without modification. |
| 80 | // |
| 81 | // Code Example: |
| 82 | // |
| 83 | // typedef struct _rangesection |
| 84 | // { |
| 85 | // PTR_IJitManager pjit; |
| 86 | // PTR_RangeSection pright; |
| 87 | // PTR_RangeSection pleft; |
| 88 | // ... Other fields omitted ... |
| 89 | // } RangeSection; |
| 90 | // |
| 91 | // RangeSection* pRS = m_RangeTree; |
| 92 | // |
| 93 | // while (pRS != NULL) |
| 94 | // { |
| 95 | // if (currentPC < pRS->LowAddress) |
| 96 | // pRS=pRS->pleft; |
| 97 | // else if (currentPC > pRS->HighAddress) |
| 98 | // pRS=pRS->pright; |
| 99 | // else |
| 100 | // { |
| 101 | // return pRS->pjit; |
| 102 | // } |
| 103 | // } |
| 104 | // |
| 105 | // This code does not require any modifications. The global reference |
| 106 | // provided by m_RangeTree will be a host version of the RangeSection |
| 107 | // instantiated by conversion. The references to pRS->pleft and |
| 108 | // pRS->pright will refer to DPTRs due to the modified declaration. |
| 109 | // In the assignment statement the compiler will automatically use |
| 110 | // the implicit conversion from PTR_RangeSection to RangeSection*, |
| 111 | // causing a host instance to be created. Finally, if an appropriate |
| 112 | // section is found the use of pRS->pjit will cause an implicit |
| 113 | // conversion from PTR_IJitManager to IJitManager. The VPTR code |
| 114 | // will look at target memory to determine the actual derived class |
| 115 | // for the JitManager and instantiate the right class in the host so |
| 116 | // that host virtual functions can be used just as they would in |
| 117 | // the target. |
| 118 | // |
| 119 | // There are situations where code modifications are required, though. |
| 120 | // |
| 121 | // 1. Any time the actual value of an address matters, such as using |
| 122 | // it as a search key in a tree, the target address must be used. |
| 123 | // |
| 124 | // An example of this is the RangeSection tree used to locate JIT |
| 125 | // managers. A portion of this code is shown above. Each |
| 126 | // RangeSection node in the tree describes a range of addresses |
| 127 | // managed by the JitMan. These addresses are just being used as |
| 128 | // values, not to dereference through, so there are not DPTRs. When |
| 129 | // searching the range tree for an address the address used in the |
| 130 | // search must be a target address as that's what values are kept in |
| 131 | // the RangeSections. In the code shown above, currentPC must be a |
| 132 | // target address as the RangeSections in the tree are all target |
| 133 | // addresses. Use dac_cast<TADDR> to retrieve the target address |
| 134 | // of a ?PTR, as well as to convert a host address to the |
| 135 | // target address used to retrieve that particular instance. Do not |
| 136 | // use dac_cast with any raw target pointer types (such as BYTE*). |
| 137 | // |
| 138 | // 2. Any time an address is modified, such as by address arithmetic, |
| 139 | // the arithmetic must be performed on the target address. |
| 140 | // |
| 141 | // When a host instance is created it is created for the type in use. |
| 142 | // There is no particular relation to any other instance, so address |
| 143 | // arithmetic cannot be used to get from one instance to any other |
| 144 | // part of memory. For example |
| 145 | // char* Func(Class* cls) |
| 146 | // { |
| 147 | // // String follows the basic Class data. |
| 148 | // return (char*)(cls + 1); |
| 149 | // } |
| 150 | // does not work with external access because the Class* used would |
| 151 | // have retrieved only a Class worth of data. There is no string |
| 152 | // following the host instance. Instead, this code should use |
| 153 | // dac_cast<TADDR> to get the target address of the Class |
| 154 | // instance, add sizeof(*cls) and then create a new ?PTR to access |
| 155 | // the desired data. Note that the newly retrieved data will not |
| 156 | // be contiguous with the Class instance, so address arithmetic |
| 157 | // will still not work. |
| 158 | // |
| 159 | // Previous Code: |
| 160 | // |
| 161 | // BOOL IsTarget(LPVOID ip) |
| 162 | // { |
| 163 | // StubCallInstrs* pStubCallInstrs = GetStubCallInstrs(); |
| 164 | // |
| 165 | // if (ip == (LPVOID) &(pStubCallInstrs->m_op)) |
| 166 | // { |
| 167 | // return TRUE; |
| 168 | // } |
| 169 | // |
| 170 | // Modified Code: |
| 171 | // |
| 172 | // BOOL IsTarget(LPVOID ip) |
| 173 | // { |
| 174 | // StubCallInstrs* pStubCallInstrs = GetStubCallInstrs(); |
| 175 | // |
| 176 | // if ((TADDR)ip == dac_cast<TADDR>(pStubCallInstrs) + |
| 177 | // (TADDR)offsetof(StubCallInstrs, m_op)) |
| 178 | // { |
| 179 | // return TRUE; |
| 180 | // } |
| 181 | // |
| 182 | // The parameter ip is a target address, so the host pStubCallInstrs |
| 183 | // cannot be used to derive an address from. The member & reference |
| 184 | // has to be replaced with a conversion from host to target address |
| 185 | // followed by explicit offsetting for the field. |
| 186 | // |
| 187 | // PTR_HOST_MEMBER_TADDR is a convenience macro that encapsulates |
| 188 | // these two operations, so the above code could also be: |
| 189 | // |
| 190 | // if ((TADDR)ip == |
| 191 | // PTR_HOST_MEMBER_TADDR(StubCallInstrs, pStubCallInstrs, m_op)) |
| 192 | // |
| 193 | // 3. Any time the amount of memory referenced through an address |
| 194 | // changes, such as by casting to a different type, a new ?PTR |
| 195 | // must be created. |
| 196 | // |
| 197 | // Host instances are created and stored based on both the target |
| 198 | // address and size of access. The access code has no way of knowing |
| 199 | // all possible ways that data will be retrieved for a given address |
| 200 | // so if code changes the way it accesses through an address a new |
| 201 | // ?PTR must be used, which may lead to a difference instance and |
| 202 | // different host address. This means that pointer identity does not hold |
| 203 | // across casts, so code like |
| 204 | // Class* cls = PTR_Class(addr); |
| 205 | // Class2* cls2 = PTR_Class2(addr); |
| 206 | // return cls == cls2; |
| 207 | // will fail because the host-side instances have no relation to each |
| 208 | // other. That isn't a problem, since by rule #1 you shouldn't be |
| 209 | // relying on specific host address values. |
| 210 | // |
| 211 | // Previous Code: |
| 212 | // |
| 213 | // return (ArrayClass *) m_pMethTab->GetClass(); |
| 214 | // |
| 215 | // Modified Code: |
| 216 | // |
| 217 | // return PTR_ArrayClass(m_pMethTab->GetClass()); |
| 218 | // |
| 219 | // The ?PTR templates have an implicit conversion from a host pointer |
| 220 | // to a target address, so the cast above constructs a new |
| 221 | // PTR_ArrayClass by implicitly converting the host pointer result |
| 222 | // from GetClass() to its target address and using that as the address |
| 223 | // of the new PTR_ArrayClass. As mentioned, the actual host-side |
| 224 | // pointer values may not be the same. |
| 225 | // |
| 226 | // Host pointer identity can be assumed as long as the type of access |
| 227 | // is the same. In the example above, if both accesses were of type |
| 228 | // Class then the host pointer will be the same, so it is safe to |
| 229 | // retrieve the target address of an instance and then later get |
| 230 | // a new host pointer for the target address using the same type as |
| 231 | // the host pointer in that case will be the same. This is enabled |
| 232 | // by caching all of the retrieved host instances. This cache is searched |
| 233 | // by the addr:size pair and when there's a match the existing instance |
| 234 | // is reused. This increases performance and also allows simple |
| 235 | // pointer identity to hold. It does mean that host memory grows |
| 236 | // in proportion to the amount of target memory being referenced, |
| 237 | // so retrieving extraneous data should be avoided. |
| 238 | // The host-side data cache grows until the Flush() method is called, |
| 239 | // at which point all host-side data is discarded. No host |
| 240 | // instance pointers should be held across a Flush(). |
| 241 | // |
| 242 | // Accessing into an object can lead to some unusual behavior. For |
| 243 | // example, the SList class relies on objects to contain an SLink |
| 244 | // instance that it uses for list maintenance. This SLink can be |
| 245 | // embedded anywhere in the larger object. The SList access is always |
| 246 | // purely to an SLink, so when using the access layer it will only |
| 247 | // retrieve an SLink's worth of data. The SList template will then |
| 248 | // do some address arithmetic to determine the start of the real |
| 249 | // object and cast the resulting pointer to the final object type. |
| 250 | // When using the access layer this results in a new ?PTR being |
| 251 | // created and used, so a new instance will result. The internal |
| 252 | // SLink instance will have no relation to the new object instance |
| 253 | // even though in target address terms one is embedded in the other. |
| 254 | // The assumption of data stability means that this won't cause |
| 255 | // a problem, but care must be taken with the address arithmetic, |
| 256 | // as layed out in rules #2 and #3. |
| 257 | // |
| 258 | // 4. Global address references cannot be used. Any reference to a |
| 259 | // global piece of code or data, such as a function address, global |
| 260 | // variable or class static variable, must be changed. |
| 261 | // |
| 262 | // The external access code may load at a different base address than |
| 263 | // the target process code. Global addresses are therefore not |
| 264 | // meaningful and must be replaced with something else. There isn't |
| 265 | // a single solution, so replacements must be done on a case-by-case |
| 266 | // basis. |
| 267 | // |
| 268 | // The simplest case is a global or class static variable. All |
| 269 | // declarations must be replaced with a special declaration that |
| 270 | // compiles into a modified accessor template value when compiled for |
| 271 | // external data access. Uses of the variable automatically are fixed |
| 272 | // up by the template instance. Note that assignment to the global |
| 273 | // must be independently ifdef'ed as the external access layer should |
| 274 | // not make any modifications. |
| 275 | // |
| 276 | // Macros allow for simple declaration of a class static and global |
| 277 | // values that compile into an appropriate templated value. |
| 278 | // |
| 279 | // Previous Code: |
| 280 | // |
| 281 | // static RangeSection* m_RangeTree; |
| 282 | // RangeSection* ExecutionManager::m_RangeTree; |
| 283 | // |
| 284 | // extern ThreadStore* g_pThreadStore; |
| 285 | // ThreadStore* g_pThreadStore = &StaticStore; |
| 286 | // class SystemDomain : public BaseDomain { |
| 287 | // ... |
| 288 | // ArrayListStatic m_appDomainIndexList; |
| 289 | // ... |
| 290 | // } |
| 291 | // |
| 292 | // SystemDomain::m_appDomainIndexList; |
| 293 | // |
| 294 | // extern DWORD gThreadTLSIndex; |
| 295 | // |
| 296 | // DWORD gThreadTLSIndex = TLS_OUT_OF_INDEXES; |
| 297 | // |
| 298 | // Modified Code: |
| 299 | // |
| 300 | // typedef DPTR(RangeSection) PTR_RangeSection; |
| 301 | // SPTR_DECL(RangeSection, m_RangeTree); |
| 302 | // SPTR_IMPL(RangeSection, ExecutionManager, m_RangeTree); |
| 303 | // |
| 304 | // typedef DPTR(ThreadStore) PTR_ThreadStore |
| 305 | // GPTR_DECL(ThreadStore, g_pThreadStore); |
| 306 | // GPTR_IMPL_INIT(ThreadStore, g_pThreadStore, &StaticStore); |
| 307 | // |
| 308 | // class SystemDomain : public BaseDomain { |
| 309 | // ... |
| 310 | // SVAL_DECL(ArrayListStatic; m_appDomainIndexList); |
| 311 | // ... |
| 312 | // } |
| 313 | // |
| 314 | // SVAL_IMPL(ArrayListStatic, SystemDomain, m_appDomainIndexList); |
| 315 | // |
| 316 | // GVAL_DECL(DWORD, gThreadTLSIndex); |
| 317 | // |
| 318 | // GVAL_IMPL_INIT(DWORD, gThreadTLSIndex, TLS_OUT_OF_INDEXES); |
| 319 | // |
| 320 | // When declaring the variable, the first argument declares the |
| 321 | // variable's type and the second argument declares the variable's |
| 322 | // name. When defining the variable the arguments are similar, with |
| 323 | // an extra class name parameter for the static class variable case. |
| 324 | // If an initializer is needed the IMPL_INIT macro should be used. |
| 325 | // |
| 326 | // Things get slightly more complicated when declaring an embedded |
| 327 | // array. In this case the data element is not a single element and |
| 328 | // therefore cannot be represented by a ?PTR. In the case of a global |
| 329 | // array, you should use the GARY_DECL and GARY_IMPL macros. |
| 330 | // We durrently have no support for declaring static array data members |
| 331 | // or initialized arrays. Array data members that are dynamically allocated |
| 332 | // need to be treated as pointer members. To reference individual elements |
| 333 | // you must use pointer arithmetic (see rule 2 above). An array declared |
| 334 | // as a local variable within a function does not need to be DACized. |
| 335 | // |
| 336 | // |
| 337 | // All uses of ?VAL_DECL must have a corresponding entry given in the |
| 338 | // DacGlobals structure in src\inc\dacvars.h. For SVAL_DECL the entry |
| 339 | // is class__name. For GVAL_DECL the entry is dac__name. You must add |
| 340 | // these entries in dacvars.h using the DEFINE_DACVAR macro. Note that |
| 341 | // these entries also are used for dumping memory in mini dumps and |
| 342 | // heap dumps. If it's not appropriate to dump a variable, (e.g., |
| 343 | // it's an array or some other value that is not important to have |
| 344 | // in a minidump) a second macro, DEFINE_DACVAR_NO_DUMP, will allow |
| 345 | // you to make the required entry in the DacGlobals structure without |
| 346 | // dumping its value. |
| 347 | // |
| 348 | // For convenience, here is a list of the various variable declaration and |
| 349 | // initialization macros: |
| 350 | // SVAL_DECL(type, name) static non-pointer data class MyClass |
| 351 | // member declared within { |
| 352 | // the class declaration // static int i; |
| 353 | // SVAL_DECL(int, i); |
| 354 | // } |
| 355 | // |
| 356 | // SVAL_IMPL(type, cls, name) static non-pointer data // int MyClass::i; |
| 357 | // member defined outside SVAL_IMPL(int, MyClass, i); |
| 358 | // the class declaration |
| 359 | // |
| 360 | // SVAL_IMPL_INIT(type, cls, static non-pointer data // int MyClass::i = 0; |
| 361 | // name, val) member defined and SVAL_IMPL_INIT(int, MyClass, i, 0); |
| 362 | // initialized outside the |
| 363 | // class declaration |
| 364 | // ------------------------------------------------------------------------------------------------ |
| 365 | // SPTR_DECL(type, name) static pointer data class MyClass |
| 366 | // member declared within { |
| 367 | // the class declaration // static int * pInt; |
| 368 | // SPTR_DECL(int, pInt); |
| 369 | // } |
| 370 | // |
| 371 | // SPTR_IMPL(type, cls, name) static pointer data // int * MyClass::pInt; |
| 372 | // member defined outside SPTR_IMPL(int, MyClass, pInt); |
| 373 | // the class declaration |
| 374 | // |
| 375 | // SPTR_IMPL_INIT(type, cls, static pointer data // int * MyClass::pInt = NULL; |
| 376 | // name, val) member defined and SPTR_IMPL_INIT(int, MyClass, pInt, NULL); |
| 377 | // initialized outside the |
| 378 | // class declaration |
| 379 | // ------------------------------------------------------------------------------------------------ |
| 380 | // GVAL_DECL(type, name) extern declaration of // extern int g_i |
| 381 | // global non-pointer GVAL_DECL(int, g_i); |
| 382 | // variable |
| 383 | // |
| 384 | // GVAL_IMPL(type, name) declaration of a // int g_i |
| 385 | // global non-pointer GVAL_IMPL(int, g_i); |
| 386 | // variable |
| 387 | // |
| 388 | // GVAL_IMPL_INIT (type, declaration and // int g_i = 0; |
| 389 | // name, initialization of a GVAL_IMPL_INIT(int, g_i, 0); |
| 390 | // val) global non-pointer |
| 391 | // variable |
| 392 | // ****Note**** |
| 393 | // If you use GVAL_? to declare a global variable of a structured type and you need to |
| 394 | // access a member of the type, you cannot use the dot operator. Instead, you must take the |
| 395 | // address of the variable and use the arrow operator. For example: |
| 396 | // struct |
| 397 | // { |
| 398 | // int x; |
| 399 | // char ch; |
| 400 | // } MyStruct; |
| 401 | // GVAL_IMPL(MyStruct, g_myStruct); |
| 402 | // int i = (&g_myStruct)->x; |
| 403 | // ------------------------------------------------------------------------------------------------ |
| 404 | // GPTR_DECL(type, name) extern declaration of // extern int * g_pInt |
| 405 | // global pointer GPTR_DECL(int, g_pInt); |
| 406 | // variable |
| 407 | // |
| 408 | // GPTR_IMPL(type, name) declaration of a // int * g_pInt |
| 409 | // global pointer GPTR_IMPL(int, g_pInt); |
| 410 | // variable |
| 411 | // |
| 412 | // GPTR_IMPL_INIT (type, declaration and // int * g_pInt = 0; |
| 413 | // name, initialization of a GPTR_IMPL_INIT(int, g_pInt, NULL); |
| 414 | // val) global pointer |
| 415 | // variable |
| 416 | // ------------------------------------------------------------------------------------------------ |
| 417 | // GARY_DECL(type, name) extern declaration of // extern int g_rgIntList[MAX_ELEMENTS]; |
| 418 | // a global array GPTR_DECL(int, g_rgIntList, MAX_ELEMENTS); |
| 419 | // variable |
| 420 | // |
| 421 | // GARY_IMPL(type, name) declaration of a // int g_rgIntList[MAX_ELEMENTS]; |
| 422 | // global pointer GPTR_IMPL(int, g_rgIntList, MAX_ELEMENTS); |
| 423 | // variable |
| 424 | // |
| 425 | // |
| 426 | // Certain pieces of code, such as the stack walker, rely on identifying |
| 427 | // an object from its vtable address. As the target vtable addresses |
| 428 | // do not necessarily correspond to the vtables used in the host, these |
| 429 | // references must be translated. The access layer maintains translation |
| 430 | // tables for all classes used with VPTR and can return the target |
| 431 | // vtable pointer for any host vtable in the known list of VPTR classes. |
| 432 | // |
| 433 | // ----- Errors: |
| 434 | // |
| 435 | // All errors in the access layer are reported via exceptions. The |
| 436 | // formal access layer methods catch all such exceptions and turn |
| 437 | // them into the appropriate error, so this generally isn't visible |
| 438 | // to users of the access layer. |
| 439 | // |
| 440 | // ----- DPTR Declaration: |
| 441 | // |
| 442 | // Create a typedef for the type with typedef DPTR(type) PTR_type; |
| 443 | // Replace type* with PTR_type. |
| 444 | // |
| 445 | // ----- VPTR Declaration: |
| 446 | // |
| 447 | // VPTR can only be used on classes that have a single vtable |
| 448 | // pointer at the beginning of the object. This should be true |
| 449 | // for a normal single-inheritance object. |
| 450 | // |
| 451 | // All of the classes that may be instantiated need to be identified |
| 452 | // and marked. In the base class declaration add either |
| 453 | // VPTR_BASE_VTABLE_CLASS if the class is abstract or |
| 454 | // VPTR_BASE_CONCRETE_VTABLE_CLASS if the class is concrete. In each |
| 455 | // derived class add VPTR_VTABLE_CLASS. If you end up with compile or |
| 456 | // link errors for an unresolved method called VPtrSize you missed a |
| 457 | // derived class declaration. |
| 458 | // |
| 459 | // As described above, dac can only handle classes with a single |
| 460 | // vtable. However, there's a special case for multiple inheritance |
| 461 | // situations when only one of the classes is needed for dac. If |
| 462 | // the base class needed is the first class in the derived class's |
| 463 | // layout then it can be used with dac via using the VPTR_MULTI_CLASS |
| 464 | // macros. Use with extreme care. |
| 465 | // |
| 466 | // All classes to be instantiated must be listed in src\inc\vptr_list.h. |
| 467 | // |
| 468 | // Create a typedef for the type with typedef VPTR(type) PTR_type; |
| 469 | // When using a VPTR, replace Class* with PTR_Class. |
| 470 | // |
| 471 | // ----- Specific Macros: |
| 472 | // |
| 473 | // PTR_TO_TADDR(ptr) |
| 474 | // Retrieves the raw target address for a ?PTR. |
| 475 | // See code:dac_cast for the preferred alternative |
| 476 | // |
| 477 | // PTR_HOST_TO_TADDR(host) |
| 478 | // Given a host address of an instance produced by a ?PTR reference, |
| 479 | // return the original target address. The host address must |
| 480 | // be an exact match for an instance. |
| 481 | // See code:dac_cast for the preferred alternative |
| 482 | // |
| 483 | // PTR_HOST_INT_TO_TADDR(host) |
| 484 | // Given a host address which resides somewhere within an instance |
| 485 | // produced by a ?PTR reference (a host interior pointer) return the |
| 486 | // corresponding target address. This is useful for evaluating |
| 487 | // relative pointers (e.g. RelativePointer<T>) where calculating the |
| 488 | // target address requires knowledge of the target address of the |
| 489 | // relative pointer field itself. This lookup is slower than that for |
| 490 | // a non-interior host pointer so use it sparingly. |
| 491 | // |
| 492 | // VPTR_HOST_VTABLE_TO_TADDR(host) |
| 493 | // Given the host vtable pointer for a known VPTR class, return |
| 494 | // the target vtable pointer. |
| 495 | // |
| 496 | // PTR_HOST_MEMBER_TADDR(type, host, memb) |
| 497 | // Retrieves the target address of a host instance pointer and |
| 498 | // offsets it by the given member's offset within the type. |
| 499 | // |
| 500 | // PTR_HOST_INT_MEMBER_TADDR(type, host, memb) |
| 501 | // As above but will work for interior host pointers (see the |
| 502 | // description of PTR_HOST_INT_TO_TADDR for an explanation of host |
| 503 | // interior pointers). |
| 504 | // |
| 505 | // PTR_READ(addr, size) |
| 506 | // Reads a block of memory from the target and returns a host |
| 507 | // pointer for it. Useful for reading blocks of data from the target |
| 508 | // whose size is only known at runtime, such as raw code for a jitted |
| 509 | // method. If the data being read is actually an object, use SPTR |
| 510 | // instead to get better type semantics. |
| 511 | // |
| 512 | // DAC_EMPTY() |
| 513 | // DAC_EMPTY_ERR() |
| 514 | // DAC_EMPTY_RET(retVal) |
| 515 | // DAC_UNEXPECTED() |
| 516 | // Provides an empty method implementation when compiled |
| 517 | // for DACCESS_COMPILE. For example, use to stub out methods needed |
| 518 | // for vtable entries but otherwise unused. |
| 519 | // |
| 520 | // These macros are designed to turn into normal code when compiled |
| 521 | // without DACCESS_COMPILE. |
| 522 | // |
| 523 | //***************************************************************************** |
| 524 | |
| 525 | |
| 526 | #ifndef __daccess_h__ |
| 527 | #define __daccess_h__ |
| 528 | |
| 529 | #include <stdint.h> |
| 530 | |
| 531 | #include "switches.h" |
| 532 | #include "safemath.h" |
| 533 | #include "corerror.h" |
| 534 | |
| 535 | #ifndef __in |
| 536 | #include <specstrings.h> |
| 537 | #endif |
| 538 | |
| 539 | #define DACCESS_TABLE_RESOURCE "COREXTERNALDATAACCESSRESOURCE" |
| 540 | |
| 541 | #ifdef PAL_STDCPP_COMPAT |
| 542 | #include <type_traits> |
| 543 | #else |
| 544 | #include "clr_std/type_traits" |
| 545 | #include "crosscomp.h" |
| 546 | #endif |
| 547 | |
| 548 | // Information stored in the DAC table of interest to the DAC implementation |
| 549 | // Note that this information is shared between all instantiations of ClrDataAccess, so initialize |
| 550 | // it just once in code:ClrDataAccess.GetDacGlobals (rather than use fields in ClrDataAccess); |
| 551 | struct DacTableInfo |
| 552 | { |
| 553 | // On Windows, the first DWORD is the 32-bit timestamp read out of the runtime dll's debug directory. |
| 554 | // The remaining 3 DWORDS must all be 0. |
| 555 | // On Mac, this is the 16-byte UUID of the runtime dll. |
| 556 | // It is used to validate that mscorwks is the same version as mscordacwks |
| 557 | DWORD dwID0; |
| 558 | DWORD dwID1; |
| 559 | DWORD dwID2; |
| 560 | DWORD dwID3; |
| 561 | }; |
| 562 | |
| 563 | // The header of the DAC table. This includes the number of globals, the number of vptrs, and |
| 564 | // the DacTableInfo structure. We need the DacTableInfo and DacTableHeader structs outside |
| 565 | // of a DACCESS_COMPILE since soshost walks the Dac table headers to find the UUID of CoreCLR |
| 566 | // in the target process. |
| 567 | struct |
| 568 | { |
| 569 | ULONG ; |
| 570 | ULONG ; |
| 571 | DacTableInfo ; |
| 572 | }; |
| 573 | |
| 574 | // |
| 575 | // This version of things wraps pointer access in |
| 576 | // templates which understand how to retrieve data |
| 577 | // through an access layer. In this case no assumptions |
| 578 | // can be made that the current compilation processor or |
| 579 | // pointer types match the target's processor or pointer types. |
| 580 | // |
| 581 | |
| 582 | // Define TADDR as a non-pointer value so use of it as a pointer |
| 583 | // will not work properly. Define it as unsigned so |
| 584 | // pointer comparisons aren't affected by sign. |
| 585 | // This requires special casting to ULONG64 to sign-extend if necessary. |
| 586 | typedef ULONG_PTR TADDR; |
| 587 | |
| 588 | // TSIZE_T used for counts or ranges that need to span the size of a |
| 589 | // target pointer. For cross-plat, this may be different than SIZE_T |
| 590 | // which reflects the host pointer size. |
| 591 | typedef SIZE_T TSIZE_T; |
| 592 | |
| 593 | |
| 594 | // |
| 595 | // The following table contains all the global information that data access needs to begin |
| 596 | // operation. All of the values stored here are RVAs. DacGlobalBase() returns the current |
| 597 | // base address to combine with to get a full target address. |
| 598 | // |
| 599 | |
| 600 | typedef struct _DacGlobals |
| 601 | { |
| 602 | #ifdef FEATURE_PAL |
| 603 | static void Initialize(); |
| 604 | void InitializeEntries(TADDR baseAddress); |
| 605 | #endif // FEATURE_PAL |
| 606 | |
| 607 | // These will define all of the dac related mscorwks static and global variables |
| 608 | #define DEFINE_DACVAR(id_type, size, id, var) id_type id; |
| 609 | #define DEFINE_DACVAR_NO_DUMP(id_type, size, id, var) id_type id; |
| 610 | #include "dacvars.h" |
| 611 | |
| 612 | // Global functions. |
| 613 | ULONG fn__ThreadpoolMgr__AsyncTimerCallbackCompletion; |
| 614 | ULONG fn__DACNotifyCompilationFinished; |
| 615 | ULONG fn__ThePreStub; |
| 616 | |
| 617 | #ifdef _TARGET_ARM_ |
| 618 | ULONG fn__ThePreStubCompactARM; |
| 619 | #endif // _TARGET_ARM_ |
| 620 | |
| 621 | ULONG fn__ThePreStubPatchLabel; |
| 622 | ULONG fn__PrecodeFixupThunk; |
| 623 | ULONG fn__StubDispatchFixupStub; |
| 624 | ULONG fn__StubDispatchFixupPatchLabel;; |
| 625 | #ifdef FEATURE_COMINTEROP |
| 626 | ULONG fn__Unknown_AddRef; |
| 627 | ULONG fn__Unknown_AddRefSpecial; |
| 628 | ULONG fn__Unknown_AddRefInner; |
| 629 | #endif |
| 630 | |
| 631 | // Vtable pointer values for all classes that must |
| 632 | // be instanted using vtable pointers as the identity. |
| 633 | #define VPTR_CLASS(name) ULONG name##__vtAddr; |
| 634 | #define VPTR_MULTI_CLASS(name, keyBase) ULONG name##__##keyBase##__mvtAddr; |
| 635 | #include <vptr_list.h> |
| 636 | #undef VPTR_CLASS |
| 637 | #undef VPTR_MULTI_CLASS |
| 638 | } DacGlobals; |
| 639 | |
| 640 | #ifdef DACCESS_COMPILE |
| 641 | |
| 642 | extern DacTableInfo g_dacTableInfo; |
| 643 | extern DacGlobals g_dacGlobals; |
| 644 | |
| 645 | #ifdef __cplusplus |
| 646 | extern "C" { |
| 647 | #endif |
| 648 | |
| 649 | // These two functions are largely just for marking code |
| 650 | // that is not fully converted. DacWarning prints a debug |
| 651 | // message, while DacNotImpl throws a not-implemented exception. |
| 652 | void __cdecl DacWarning(__in __in_z char* format, ...); |
| 653 | void DacNotImpl(void); |
| 654 | |
| 655 | void DacError(HRESULT err); |
| 656 | void DECLSPEC_NORETURN DacError_NoRet(HRESULT err); |
| 657 | TADDR DacGlobalBase(void); |
| 658 | HRESULT DacReadAll(TADDR addr, PVOID buffer, ULONG32 size, bool throwEx); |
| 659 | HRESULT DacWriteAll(TADDR addr, PVOID buffer, ULONG32 size, bool throwEx); |
| 660 | HRESULT DacAllocVirtual(TADDR addr, ULONG32 size, |
| 661 | ULONG32 typeFlags, ULONG32 protectFlags, |
| 662 | bool throwEx, TADDR* mem); |
| 663 | HRESULT DacFreeVirtual(TADDR mem, ULONG32 size, ULONG32 typeFlags, |
| 664 | bool throwEx); |
| 665 | PVOID DacInstantiateTypeByAddress(TADDR addr, ULONG32 size, bool throwEx); |
| 666 | PVOID DacInstantiateTypeByAddressNoReport(TADDR addr, ULONG32 size, bool throwEx); |
| 667 | PVOID DacInstantiateClassByVTable(TADDR addr, ULONG32 minSize, bool throwEx); |
| 668 | |
| 669 | // Copy a null-terminated ascii or unicode string from the target to the host. |
| 670 | // Note that most of the work here is to find the null terminator. If you know the exact length, |
| 671 | // then you can also just call DacInstantiateTypebyAddress. |
| 672 | PSTR DacInstantiateStringA(TADDR addr, ULONG32 maxChars, bool throwEx); |
| 673 | PWSTR DacInstantiateStringW(TADDR addr, ULONG32 maxChars, bool throwEx); |
| 674 | |
| 675 | TADDR DacGetTargetAddrForHostAddr(LPCVOID ptr, bool throwEx); |
| 676 | TADDR DacGetTargetAddrForHostInteriorAddr(LPCVOID ptr, bool throwEx); |
| 677 | TADDR DacGetTargetVtForHostVt(LPCVOID vtHost, bool throwEx); |
| 678 | PWSTR DacGetVtNameW(TADDR targetVtable); |
| 679 | |
| 680 | // Report a region of memory to the debugger |
| 681 | bool DacEnumMemoryRegion(TADDR addr, TSIZE_T size, bool fExpectSuccess = true); |
| 682 | |
| 683 | // Report a region of memory to the debugger |
| 684 | bool DacUpdateMemoryRegion(TADDR addr, TSIZE_T bufferSize, BYTE* buffer); |
| 685 | |
| 686 | HRESULT DacWriteHostInstance(PVOID host, bool throwEx); |
| 687 | |
| 688 | // This is meant to mimic the RethrowTerminalExceptions/ |
| 689 | // SwallowAllExceptions/RethrowTransientExceptions macros to allow minidump |
| 690 | // gathering cancelation for details see |
| 691 | // code:ClrDataAccess.EnumMemoryRegionsWrapper |
| 692 | |
| 693 | // This is usable in EX_TRY exactly how RethrowTerminalExceptions et cetera |
| 694 | #define RethrowCancelExceptions \ |
| 695 | if (GET_EXCEPTION()->GetHR() == COR_E_OPERATIONCANCELED) \ |
| 696 | { \ |
| 697 | EX_RETHROW; \ |
| 698 | } |
| 699 | |
| 700 | // Occasionally it's necessary to allocate some host memory for |
| 701 | // instance data that's created on the fly and so doesn't directly |
| 702 | // correspond to target memory. These are held and freed on flush |
| 703 | // like other instances but can't be looked up by address. |
| 704 | PVOID DacAllocHostOnlyInstance(ULONG32 size, bool throwEx); |
| 705 | |
| 706 | // Determines whether ASSERTs should be raised when inconsistencies in the target are detected |
| 707 | bool DacTargetConsistencyAssertsEnabled(); |
| 708 | |
| 709 | // Host instances can be marked as they are enumerated in |
| 710 | // order to break cycles. This function returns true if |
| 711 | // the instance is already marked, otherwise it marks the |
| 712 | // instance and returns false. |
| 713 | bool DacHostPtrHasEnumMark(LPCVOID host); |
| 714 | |
| 715 | // Determines if EnumMemoryRegions has been called on a method descriptor. |
| 716 | // This helps perf for minidumps of apps with large managed stacks. |
| 717 | bool DacHasMethodDescBeenEnumerated(LPCVOID pMD); |
| 718 | |
| 719 | // Sets a flag indicating that EnumMemoryRegions on a method desciptor |
| 720 | // has been successfully called. The function returns true if |
| 721 | // this flag had been previously set. |
| 722 | bool DacSetMethodDescEnumerated(LPCVOID pMD); |
| 723 | |
| 724 | // Determines if a method descriptor is valid |
| 725 | BOOL DacValidateMD(LPCVOID pMD); |
| 726 | |
| 727 | // Enumerate the instructions around a call site to help debugger stack walking heuristics |
| 728 | void DacEnumCodeForStackwalk(TADDR taCallEnd); |
| 729 | |
| 730 | // Given the address and the size of a memory range which is stored in the buffer, replace all the patches |
| 731 | // in the buffer with the real opcodes. This is especially important on X64 where the unwinder needs to |
| 732 | // disassemble the native instructions. |
| 733 | class MemoryRange; |
| 734 | HRESULT DacReplacePatchesInHostMemory(MemoryRange range, PVOID pBuffer); |
| 735 | |
| 736 | // |
| 737 | // Convenience macros for EnumMemoryRegions implementations. |
| 738 | // |
| 739 | |
| 740 | // Enumerate the given host instance and return |
| 741 | // true if the instance hasn't already been enumerated. |
| 742 | #define DacEnumHostDPtrMem(host) \ |
| 743 | (!DacHostPtrHasEnumMark(host) ? \ |
| 744 | (DacEnumMemoryRegion(PTR_HOST_TO_TADDR(host), sizeof(*host)), \ |
| 745 | true) : false) |
| 746 | #define DacEnumHostSPtrMem(host, type) \ |
| 747 | (!DacHostPtrHasEnumMark(host) ? \ |
| 748 | (DacEnumMemoryRegion(PTR_HOST_TO_TADDR(host), \ |
| 749 | type::DacSize(PTR_HOST_TO_TADDR(host))), \ |
| 750 | true) : false) |
| 751 | #define DacEnumHostVPtrMem(host) \ |
| 752 | (!DacHostPtrHasEnumMark(host) ? \ |
| 753 | (DacEnumMemoryRegion(PTR_HOST_TO_TADDR(host), (host)->VPtrSize()), \ |
| 754 | true) : false) |
| 755 | |
| 756 | // Check enumeration of 'this' and return if this has already been |
| 757 | // enumerated. Making this the first line of an object's EnumMemoryRegions |
| 758 | // method will prevent cycles. |
| 759 | #define DAC_CHECK_ENUM_THIS() \ |
| 760 | if (DacHostPtrHasEnumMark(this)) return |
| 761 | #define DAC_ENUM_DTHIS() \ |
| 762 | if (!DacEnumHostDPtrMem(this)) return |
| 763 | #define DAC_ENUM_STHIS(type) \ |
| 764 | if (!DacEnumHostSPtrMem(this, type)) return |
| 765 | #define DAC_ENUM_VTHIS() \ |
| 766 | if (!DacEnumHostVPtrMem(this)) return |
| 767 | |
| 768 | #ifdef __cplusplus |
| 769 | } |
| 770 | class ReflectionModule; |
| 771 | interface IMDInternalImport* DacGetMDImport(const class PEFile* peFile, |
| 772 | bool throwEx); |
| 773 | interface IMDInternalImport* DacGetMDImport(const ReflectionModule* reflectionModule, |
| 774 | bool throwEx); |
| 775 | |
| 776 | int DacGetIlMethodSize(TADDR methAddr); |
| 777 | struct COR_ILMETHOD* DacGetIlMethod(TADDR methAddr); |
| 778 | #ifdef WIN64EXCEPTIONS |
| 779 | struct _UNWIND_INFO * DacGetUnwindInfo(TADDR taUnwindInfo); |
| 780 | |
| 781 | // virtually unwind a CONTEXT out-of-process |
| 782 | struct _KNONVOLATILE_CONTEXT_POINTERS; |
| 783 | BOOL DacUnwindStackFrame(T_CONTEXT * pContext, T_KNONVOLATILE_CONTEXT_POINTERS* pContextPointers); |
| 784 | #endif // WIN64EXCEPTIONS |
| 785 | |
| 786 | #if defined(FEATURE_PAL) |
| 787 | // call back through data target to unwind out-of-process |
| 788 | HRESULT DacVirtualUnwind(ULONG32 threadId, PT_CONTEXT context, PT_KNONVOLATILE_CONTEXT_POINTERS contextPointers); |
| 789 | #endif // FEATURE_PAL |
| 790 | |
| 791 | #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS |
| 792 | class SString; |
| 793 | void DacMdCacheAddEEName(TADDR taEE, const SString& ssEEName); |
| 794 | bool DacMdCacheGetEEName(TADDR taEE, SString & ssEEName); |
| 795 | #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS |
| 796 | |
| 797 | // |
| 798 | // Computes (taBase + (dwIndex * dwElementSize()), with overflow checks. |
| 799 | // |
| 800 | // Arguments: |
| 801 | // taBase the base TADDR value |
| 802 | // dwIndex the index of the offset |
| 803 | // dwElementSize the size of each element (to multiply the offset by) |
| 804 | // |
| 805 | // Return value: |
| 806 | // The resulting TADDR, or throws CORDB_E_TARGET_INCONSISTENT on overlow. |
| 807 | // |
| 808 | // Notes: |
| 809 | // The idea here is that overflows during address arithmetic suggest that we're operating on corrupt |
| 810 | // pointers. It helps to improve reliability to detect the cases we can (like overflow) and fail. Note |
| 811 | // that this is just a heuristic, not a security measure. We can't trust target data regardless - |
| 812 | // failing on overflow is just one easy case of corruption to detect. There is no need to use checked |
| 813 | // arithmetic everywhere in the DAC infrastructure, this is intended just for the places most likely to |
| 814 | // help catch bugs (eg. __DPtr::operator[]). |
| 815 | // |
| 816 | inline TADDR DacTAddrOffset( TADDR taBase, TSIZE_T dwIndex, TSIZE_T dwElementSize ) |
| 817 | { |
| 818 | ClrSafeInt<TADDR> t(taBase); |
| 819 | t += ClrSafeInt<TSIZE_T>(dwIndex) * ClrSafeInt<TSIZE_T>(dwElementSize); |
| 820 | if( t.IsOverflow() ) |
| 821 | { |
| 822 | // Pointer arithmetic overflow - probably due to corrupt target data |
| 823 | DacError(CORDBG_E_TARGET_INCONSISTENT); |
| 824 | } |
| 825 | return t.Value(); |
| 826 | } |
| 827 | |
| 828 | |
| 829 | // Base pointer wrapper which provides common behavior. |
| 830 | class __TPtrBase |
| 831 | { |
| 832 | public: |
| 833 | __TPtrBase(void) |
| 834 | { |
| 835 | // Make uninitialized pointers obvious. |
| 836 | m_addr = (TADDR)-1; |
| 837 | } |
| 838 | __TPtrBase(TADDR addr) |
| 839 | { |
| 840 | m_addr = addr; |
| 841 | } |
| 842 | |
| 843 | bool operator!() const |
| 844 | { |
| 845 | return m_addr == 0; |
| 846 | } |
| 847 | // We'd like to have an implicit conversion to bool here since the C++ |
| 848 | // standard says all pointer types are implicitly converted to bool. |
| 849 | // Unfortunately, that would cause ambiguous overload errors for uses |
| 850 | // of operator== and operator!=. Instead callers will have to compare |
| 851 | // directly against NULL. |
| 852 | |
| 853 | bool operator==(TADDR addr) const |
| 854 | { |
| 855 | return m_addr == addr; |
| 856 | } |
| 857 | bool operator!=(TADDR addr) const |
| 858 | { |
| 859 | return m_addr != addr; |
| 860 | } |
| 861 | bool operator<(TADDR addr) const |
| 862 | { |
| 863 | return m_addr < addr; |
| 864 | } |
| 865 | bool operator>(TADDR addr) const |
| 866 | { |
| 867 | return m_addr > addr; |
| 868 | } |
| 869 | bool operator<=(TADDR addr) const |
| 870 | { |
| 871 | return m_addr <= addr; |
| 872 | } |
| 873 | bool operator>=(TADDR addr) const |
| 874 | { |
| 875 | return m_addr >= addr; |
| 876 | } |
| 877 | |
| 878 | TADDR GetAddr(void) const |
| 879 | { |
| 880 | return m_addr; |
| 881 | } |
| 882 | TADDR SetAddr(TADDR addr) |
| 883 | { |
| 884 | m_addr = addr; |
| 885 | return addr; |
| 886 | } |
| 887 | |
| 888 | protected: |
| 889 | TADDR m_addr; |
| 890 | }; |
| 891 | |
| 892 | // Pointer wrapper base class for various forms of normal data. |
| 893 | // This has the common functionality between __DPtr and __ArrayDPtr. |
| 894 | // The DPtrType type parameter is the actual derived type in use. This is necessary so that |
| 895 | // inhereted functions preserve exact return types. |
| 896 | template<typename type, typename DPtrType> |
| 897 | class __DPtrBase : public __TPtrBase |
| 898 | { |
| 899 | public: |
| 900 | typedef type _Type; |
| 901 | typedef type* _Ptr; |
| 902 | |
| 903 | protected: |
| 904 | // Constructors |
| 905 | // All protected - this type should not be used directly - use one of the derived types instead. |
| 906 | __DPtrBase< type, DPtrType >(void) : __TPtrBase() {} |
| 907 | __DPtrBase< type, DPtrType >(TADDR addr) : __TPtrBase(addr) {} |
| 908 | |
| 909 | explicit __DPtrBase< type, DPtrType >(__TPtrBase addr) |
| 910 | { |
| 911 | m_addr = addr.GetAddr(); |
| 912 | } |
| 913 | explicit __DPtrBase< type, DPtrType >(type const * host) |
| 914 | { |
| 915 | m_addr = DacGetTargetAddrForHostAddr(host, true); |
| 916 | } |
| 917 | |
| 918 | public: |
| 919 | DPtrType& operator=(const __TPtrBase& ptr) |
| 920 | { |
| 921 | m_addr = ptr.GetAddr(); |
| 922 | return DPtrType(m_addr); |
| 923 | } |
| 924 | DPtrType& operator=(TADDR addr) |
| 925 | { |
| 926 | m_addr = addr; |
| 927 | return DPtrType(m_addr); |
| 928 | } |
| 929 | |
| 930 | type& operator*(void) const |
| 931 | { |
| 932 | return *(type*)DacInstantiateTypeByAddress(m_addr, sizeof(type), true); |
| 933 | } |
| 934 | |
| 935 | bool operator==(const DPtrType& ptr) const |
| 936 | { |
| 937 | return m_addr == ptr.GetAddr(); |
| 938 | } |
| 939 | bool operator==(TADDR addr) const |
| 940 | { |
| 941 | return m_addr == addr; |
| 942 | } |
| 943 | bool operator!=(const DPtrType& ptr) const |
| 944 | { |
| 945 | return !operator==(ptr); |
| 946 | } |
| 947 | bool operator!=(TADDR addr) const |
| 948 | { |
| 949 | return m_addr != addr; |
| 950 | } |
| 951 | bool operator<(const DPtrType& ptr) const |
| 952 | { |
| 953 | return m_addr < ptr.GetAddr(); |
| 954 | } |
| 955 | bool operator>(const DPtrType& ptr) const |
| 956 | { |
| 957 | return m_addr > ptr.GetAddr(); |
| 958 | } |
| 959 | bool operator<=(const DPtrType& ptr) const |
| 960 | { |
| 961 | return m_addr <= ptr.GetAddr(); |
| 962 | } |
| 963 | bool operator>=(const DPtrType& ptr) const |
| 964 | { |
| 965 | return m_addr >= ptr.GetAddr(); |
| 966 | } |
| 967 | |
| 968 | // Array index operator |
| 969 | // we want an operator[] for all possible numeric types (rather than rely on |
| 970 | // implicit numeric conversions on the argument) to prevent ambiguity with |
| 971 | // DPtr's implicit conversion to type* and the built-in operator[]. |
| 972 | // @dbgtodo : we could also use this technique to simplify other operators below. |
| 973 | template<typename indexType> |
| 974 | type& operator[](indexType index) |
| 975 | { |
| 976 | // Compute the address of the element. |
| 977 | TADDR elementAddr; |
| 978 | if( index >= 0 ) |
| 979 | { |
| 980 | elementAddr = DacTAddrOffset(m_addr, index, sizeof(type)); |
| 981 | } |
| 982 | else |
| 983 | { |
| 984 | // Don't bother trying to do overflow checking for negative indexes - they are rare compared to |
| 985 | // positive ones. ClrSafeInt doesn't support signed datatypes yet (although we should be able to add it |
| 986 | // pretty easily). |
| 987 | elementAddr = m_addr + index * sizeof(type); |
| 988 | } |
| 989 | |
| 990 | // Marshal over a single instance and return a reference to it. |
| 991 | return *(type*) DacInstantiateTypeByAddress(elementAddr, sizeof(type), true); |
| 992 | } |
| 993 | |
| 994 | template<typename indexType> |
| 995 | type const & operator[](indexType index) const |
| 996 | { |
| 997 | return (*const_cast<__DPtrBase*>(this))[index]; |
| 998 | } |
| 999 | |
| 1000 | //------------------------------------------------------------------------- |
| 1001 | // operator+ |
| 1002 | |
| 1003 | DPtrType operator+(unsigned short val) |
| 1004 | { |
| 1005 | return DPtrType(DacTAddrOffset(m_addr, val, sizeof(type))); |
| 1006 | } |
| 1007 | DPtrType operator+(short val) |
| 1008 | { |
| 1009 | return DPtrType(m_addr + val * sizeof(type)); |
| 1010 | } |
| 1011 | // size_t is unsigned int on Win32, so we need |
| 1012 | // to ifdef here to make sure the unsigned int |
| 1013 | // and size_t overloads don't collide. size_t |
| 1014 | // is marked __w64 so a simple unsigned int |
| 1015 | // will not work on Win32, it has to be size_t. |
| 1016 | DPtrType operator+(size_t val) |
| 1017 | { |
| 1018 | return DPtrType(DacTAddrOffset(m_addr, val, sizeof(type))); |
| 1019 | } |
| 1020 | #if defined (_WIN64) |
| 1021 | DPtrType operator+(unsigned int val) |
| 1022 | { |
| 1023 | return DPtrType(DacTAddrOffset(m_addr, val, sizeof(type))); |
| 1024 | } |
| 1025 | #endif |
| 1026 | DPtrType operator+(int val) |
| 1027 | { |
| 1028 | return DPtrType(m_addr + val * sizeof(type)); |
| 1029 | } |
| 1030 | // Because of the size difference between long and int on non MS compilers, |
| 1031 | // we only need to define these operators on Windows. These provide compatible |
| 1032 | // overloads for DWORD addition operations. |
| 1033 | #ifdef _MSC_VER |
| 1034 | DPtrType operator+(unsigned long val) |
| 1035 | { |
| 1036 | return DPtrType(DacTAddrOffset(m_addr, val, sizeof(type))); |
| 1037 | } |
| 1038 | DPtrType operator+(long val) |
| 1039 | { |
| 1040 | return DPtrType(m_addr + val * sizeof(type)); |
| 1041 | } |
| 1042 | #endif |
| 1043 | |
| 1044 | //------------------------------------------------------------------------- |
| 1045 | // operator- |
| 1046 | |
| 1047 | DPtrType operator-(unsigned short val) |
| 1048 | { |
| 1049 | return DPtrType(m_addr - val * sizeof(type)); |
| 1050 | } |
| 1051 | DPtrType operator-(short val) |
| 1052 | { |
| 1053 | return DPtrType(m_addr - val * sizeof(type)); |
| 1054 | } |
| 1055 | // size_t is unsigned int on Win32, so we need |
| 1056 | // to ifdef here to make sure the unsigned int |
| 1057 | // and size_t overloads don't collide. size_t |
| 1058 | // is marked __w64 so a simple unsigned int |
| 1059 | // will not work on Win32, it has to be size_t. |
| 1060 | DPtrType operator-(size_t val) |
| 1061 | { |
| 1062 | return DPtrType(m_addr - val * sizeof(type)); |
| 1063 | } |
| 1064 | #ifdef _WIN64 |
| 1065 | DPtrType operator-(unsigned int val) |
| 1066 | { |
| 1067 | return DPtrType(m_addr - val * sizeof(type)); |
| 1068 | } |
| 1069 | #endif |
| 1070 | DPtrType operator-(int val) |
| 1071 | { |
| 1072 | return DPtrType(m_addr - val * sizeof(type)); |
| 1073 | } |
| 1074 | // Because of the size difference between long and int on non MS compilers, |
| 1075 | // we only need to define these operators on Windows. These provide compatible |
| 1076 | // overloads for DWORD addition operations. |
| 1077 | #ifdef _MSC_VER // for now, everything else is 32 bit |
| 1078 | DPtrType operator-(unsigned long val) |
| 1079 | { |
| 1080 | return DPtrType(m_addr - val * sizeof(type)); |
| 1081 | } |
| 1082 | DPtrType operator-(long val) |
| 1083 | { |
| 1084 | return DPtrType(m_addr - val * sizeof(type)); |
| 1085 | } |
| 1086 | #endif |
| 1087 | size_t operator-(const DPtrType& val) |
| 1088 | { |
| 1089 | return (m_addr - val.m_addr) / sizeof(type); |
| 1090 | } |
| 1091 | |
| 1092 | //------------------------------------------------------------------------- |
| 1093 | |
| 1094 | DPtrType& operator+=(size_t val) |
| 1095 | { |
| 1096 | m_addr += val * sizeof(type); |
| 1097 | return static_cast<DPtrType&>(*this); |
| 1098 | } |
| 1099 | DPtrType& operator-=(size_t val) |
| 1100 | { |
| 1101 | m_addr -= val * sizeof(type); |
| 1102 | return static_cast<DPtrType&>(*this); |
| 1103 | } |
| 1104 | |
| 1105 | DPtrType& operator++() |
| 1106 | { |
| 1107 | m_addr += sizeof(type); |
| 1108 | return static_cast<DPtrType&>(*this); |
| 1109 | } |
| 1110 | DPtrType& operator--() |
| 1111 | { |
| 1112 | m_addr -= sizeof(type); |
| 1113 | return static_cast<DPtrType&>(*this); |
| 1114 | } |
| 1115 | DPtrType operator++(int postfix) |
| 1116 | { |
| 1117 | DPtrType orig = DPtrType(*this); |
| 1118 | m_addr += sizeof(type); |
| 1119 | return orig; |
| 1120 | } |
| 1121 | DPtrType operator--(int postfix) |
| 1122 | { |
| 1123 | DPtrType orig = DPtrType(*this); |
| 1124 | m_addr -= sizeof(type); |
| 1125 | return orig; |
| 1126 | } |
| 1127 | |
| 1128 | bool IsValid(void) const |
| 1129 | { |
| 1130 | return m_addr && |
| 1131 | DacInstantiateTypeByAddress(m_addr, sizeof(type), |
| 1132 | false) != NULL; |
| 1133 | } |
| 1134 | void EnumMem(void) const |
| 1135 | { |
| 1136 | DacEnumMemoryRegion(m_addr, sizeof(type)); |
| 1137 | } |
| 1138 | }; |
| 1139 | |
| 1140 | // forward declaration |
| 1141 | template<typename acc_type, typename store_type> |
| 1142 | class __GlobalPtr; |
| 1143 | |
| 1144 | // Pointer wrapper for objects which are just plain data |
| 1145 | // and need no special handling. |
| 1146 | template<typename type> |
| 1147 | class __DPtr : public __DPtrBase<type,__DPtr<type> > |
| 1148 | { |
| 1149 | public: |
| 1150 | // constructors - all chain to __DPtrBase constructors |
| 1151 | __DPtr< type >(void) : __DPtrBase<type,__DPtr<type> >() {} |
| 1152 | __DPtr< type >(TADDR addr) : __DPtrBase<type,__DPtr<type> >(addr) {} |
| 1153 | |
| 1154 | // construct const from non-const |
| 1155 | typedef typename std::remove_const<type>::type mutable_type; |
| 1156 | __DPtr< type >(__DPtr<mutable_type> const & rhs) : __DPtrBase<type,__DPtr<type> >(rhs.GetAddr()) {} |
| 1157 | |
| 1158 | // construct from GlobalPtr |
| 1159 | explicit __DPtr< type >(__GlobalPtr< type*, __DPtr< type > > globalPtr) : |
| 1160 | __DPtrBase<type,__DPtr<type> >(globalPtr.GetAddr()) {} |
| 1161 | |
| 1162 | explicit __DPtr< type >(__TPtrBase addr) : __DPtrBase<type,__DPtr<type> >(addr) {} |
| 1163 | explicit __DPtr< type >(type const * host) : __DPtrBase<type,__DPtr<type> >(host) {} |
| 1164 | |
| 1165 | operator type*() const |
| 1166 | { |
| 1167 | return (type*)DacInstantiateTypeByAddress(this->m_addr, sizeof(type), true); |
| 1168 | } |
| 1169 | type* operator->() const |
| 1170 | { |
| 1171 | return (type*)DacInstantiateTypeByAddress(this->m_addr, sizeof(type), true); |
| 1172 | } |
| 1173 | }; |
| 1174 | |
| 1175 | #define DPTR(type) __DPtr< type > |
| 1176 | |
| 1177 | // A restricted form of DPtr that doesn't have any conversions to pointer types. |
| 1178 | // This is useful for pointer types that almost always represent arrays, as opposed |
| 1179 | // to pointers to single instances (eg. PTR_BYTE). In these cases, allowing implicit |
| 1180 | // conversions to (for eg.) BYTE* would usually result in incorrect usage (eg. pointer |
| 1181 | // arithmetic and array indexing), since only a single instance has been marshalled to the host. |
| 1182 | // If you really must marshal a single instance (eg. converting T* to PTR_T is too painful for now), |
| 1183 | // then use code:DacUnsafeMarshalSingleElement so we can identify such unsafe code. |
| 1184 | template<typename type> |
| 1185 | class __ArrayDPtr : public __DPtrBase<type,__ArrayDPtr<type> > |
| 1186 | { |
| 1187 | public: |
| 1188 | // constructors - all chain to __DPtrBase constructors |
| 1189 | __ArrayDPtr< type >(void) : __DPtrBase<type,__ArrayDPtr<type> >() {} |
| 1190 | __ArrayDPtr< type >(TADDR addr) : __DPtrBase<type,__ArrayDPtr<type> >(addr) {} |
| 1191 | |
| 1192 | // construct const from non-const |
| 1193 | typedef typename std::remove_const<type>::type mutable_type; |
| 1194 | __ArrayDPtr< type >(__ArrayDPtr<mutable_type> const & rhs) : __DPtrBase<type,__ArrayDPtr<type> >(rhs.GetAddr()) {} |
| 1195 | |
| 1196 | explicit __ArrayDPtr< type >(__TPtrBase addr) : __DPtrBase<type,__ArrayDPtr<type> >(addr) {} |
| 1197 | |
| 1198 | // Note that there is also no explicit constructor from host instances (type*). |
| 1199 | // Going this direction is less problematic, but often still represents risky coding. |
| 1200 | }; |
| 1201 | |
| 1202 | #define ArrayDPTR(type) __ArrayDPtr< type > |
| 1203 | |
| 1204 | |
| 1205 | // Pointer wrapper for objects which are just plain data |
| 1206 | // but whose size is not the same as the base type size. |
| 1207 | // This can be used for prefetching data for arrays or |
| 1208 | // for cases where an object has a variable size. |
| 1209 | template<typename type> |
| 1210 | class __SPtr : public __TPtrBase |
| 1211 | { |
| 1212 | public: |
| 1213 | typedef type _Type; |
| 1214 | typedef type* _Ptr; |
| 1215 | |
| 1216 | __SPtr< type >(void) : __TPtrBase() {} |
| 1217 | __SPtr< type >(TADDR addr) : __TPtrBase(addr) {} |
| 1218 | explicit __SPtr< type >(__TPtrBase addr) |
| 1219 | { |
| 1220 | m_addr = addr.GetAddr(); |
| 1221 | } |
| 1222 | explicit __SPtr< type >(type* host) |
| 1223 | { |
| 1224 | m_addr = DacGetTargetAddrForHostAddr(host, true); |
| 1225 | } |
| 1226 | |
| 1227 | __SPtr< type >& operator=(const __TPtrBase& ptr) |
| 1228 | { |
| 1229 | m_addr = ptr.GetAddr(); |
| 1230 | return *this; |
| 1231 | } |
| 1232 | __SPtr< type >& operator=(TADDR addr) |
| 1233 | { |
| 1234 | m_addr = addr; |
| 1235 | return *this; |
| 1236 | } |
| 1237 | |
| 1238 | operator type*() const |
| 1239 | { |
| 1240 | if (m_addr) |
| 1241 | { |
| 1242 | return (type*)DacInstantiateTypeByAddress(m_addr, |
| 1243 | type::DacSize(m_addr), |
| 1244 | true); |
| 1245 | } |
| 1246 | else |
| 1247 | { |
| 1248 | return (type*)NULL; |
| 1249 | } |
| 1250 | } |
| 1251 | type* operator->() const |
| 1252 | { |
| 1253 | if (m_addr) |
| 1254 | { |
| 1255 | return (type*)DacInstantiateTypeByAddress(m_addr, |
| 1256 | type::DacSize(m_addr), |
| 1257 | true); |
| 1258 | } |
| 1259 | else |
| 1260 | { |
| 1261 | return (type*)NULL; |
| 1262 | } |
| 1263 | } |
| 1264 | type& operator*(void) const |
| 1265 | { |
| 1266 | if (!m_addr) |
| 1267 | { |
| 1268 | DacError(E_INVALIDARG); |
| 1269 | } |
| 1270 | |
| 1271 | return *(type*)DacInstantiateTypeByAddress(m_addr, |
| 1272 | type::DacSize(m_addr), |
| 1273 | true); |
| 1274 | } |
| 1275 | |
| 1276 | bool IsValid(void) const |
| 1277 | { |
| 1278 | return m_addr && |
| 1279 | DacInstantiateTypeByAddress(m_addr, type::DacSize(m_addr), |
| 1280 | false) != NULL; |
| 1281 | } |
| 1282 | void EnumMem(void) const |
| 1283 | { |
| 1284 | if (m_addr) |
| 1285 | { |
| 1286 | DacEnumMemoryRegion(m_addr, type::DacSize(m_addr)); |
| 1287 | } |
| 1288 | } |
| 1289 | }; |
| 1290 | |
| 1291 | #define SPTR(type) __SPtr< type > |
| 1292 | |
| 1293 | // Pointer wrapper for objects which have a single leading |
| 1294 | // vtable, such as objects in a single-inheritance tree. |
| 1295 | // The base class of all such trees must have use |
| 1296 | // VPTR_BASE_VTABLE_CLASS in their declaration and all |
| 1297 | // instantiable members of the tree must be listed in vptr_list.h. |
| 1298 | template<class type> |
| 1299 | class __VPtr : public __TPtrBase |
| 1300 | { |
| 1301 | public: |
| 1302 | // VPtr::_Type has to be a pointer as |
| 1303 | // often the type is an abstract class. |
| 1304 | // This type is not expected to be used anyway. |
| 1305 | typedef type* _Type; |
| 1306 | typedef type* _Ptr; |
| 1307 | |
| 1308 | __VPtr< type >(void) : __TPtrBase() {} |
| 1309 | __VPtr< type >(TADDR addr) : __TPtrBase(addr) {} |
| 1310 | explicit __VPtr< type >(__TPtrBase addr) |
| 1311 | { |
| 1312 | m_addr = addr.GetAddr(); |
| 1313 | } |
| 1314 | explicit __VPtr< type >(type* host) |
| 1315 | { |
| 1316 | m_addr = DacGetTargetAddrForHostAddr(host, true); |
| 1317 | } |
| 1318 | |
| 1319 | __VPtr< type >& operator=(const __TPtrBase& ptr) |
| 1320 | { |
| 1321 | m_addr = ptr.GetAddr(); |
| 1322 | return *this; |
| 1323 | } |
| 1324 | __VPtr< type >& operator=(TADDR addr) |
| 1325 | { |
| 1326 | m_addr = addr; |
| 1327 | return *this; |
| 1328 | } |
| 1329 | |
| 1330 | operator type*() const |
| 1331 | { |
| 1332 | return (type*)DacInstantiateClassByVTable(m_addr, sizeof(type), true); |
| 1333 | } |
| 1334 | type* operator->() const |
| 1335 | { |
| 1336 | return (type*)DacInstantiateClassByVTable(m_addr, sizeof(type), true); |
| 1337 | } |
| 1338 | |
| 1339 | bool operator==(const __VPtr< type >& ptr) const |
| 1340 | { |
| 1341 | return m_addr == ptr.m_addr; |
| 1342 | } |
| 1343 | bool operator==(TADDR addr) const |
| 1344 | { |
| 1345 | return m_addr == addr; |
| 1346 | } |
| 1347 | bool operator!=(const __VPtr< type >& ptr) const |
| 1348 | { |
| 1349 | return !operator==(ptr); |
| 1350 | } |
| 1351 | bool operator!=(TADDR addr) const |
| 1352 | { |
| 1353 | return m_addr != addr; |
| 1354 | } |
| 1355 | |
| 1356 | bool IsValid(void) const |
| 1357 | { |
| 1358 | return m_addr && |
| 1359 | DacInstantiateClassByVTable(m_addr, sizeof(type), false) != NULL; |
| 1360 | } |
| 1361 | void EnumMem(void) const |
| 1362 | { |
| 1363 | if (IsValid()) |
| 1364 | { |
| 1365 | DacEnumMemoryRegion(m_addr, (operator->())->VPtrSize()); |
| 1366 | } |
| 1367 | } |
| 1368 | }; |
| 1369 | |
| 1370 | #define VPTR(type) __VPtr< type > |
| 1371 | |
| 1372 | // Pointer wrapper for 8-bit strings. |
| 1373 | template<typename type, ULONG32 maxChars = 32760> |
| 1374 | class __Str8Ptr : public __DPtr<char> |
| 1375 | { |
| 1376 | public: |
| 1377 | typedef type _Type; |
| 1378 | typedef type* _Ptr; |
| 1379 | |
| 1380 | __Str8Ptr< type, maxChars >(void) : __DPtr<char>() {} |
| 1381 | __Str8Ptr< type, maxChars >(TADDR addr) : __DPtr<char>(addr) {} |
| 1382 | explicit __Str8Ptr< type, maxChars >(__TPtrBase addr) |
| 1383 | { |
| 1384 | m_addr = addr.GetAddr(); |
| 1385 | } |
| 1386 | explicit __Str8Ptr< type, maxChars >(type* host) |
| 1387 | { |
| 1388 | m_addr = DacGetTargetAddrForHostAddr(host, true); |
| 1389 | } |
| 1390 | |
| 1391 | __Str8Ptr< type, maxChars >& operator=(const __TPtrBase& ptr) |
| 1392 | { |
| 1393 | m_addr = ptr.GetAddr(); |
| 1394 | return *this; |
| 1395 | } |
| 1396 | __Str8Ptr< type, maxChars >& operator=(TADDR addr) |
| 1397 | { |
| 1398 | m_addr = addr; |
| 1399 | return *this; |
| 1400 | } |
| 1401 | |
| 1402 | operator type*() const |
| 1403 | { |
| 1404 | return (type*)DacInstantiateStringA(m_addr, maxChars, true); |
| 1405 | } |
| 1406 | |
| 1407 | bool IsValid(void) const |
| 1408 | { |
| 1409 | return m_addr && |
| 1410 | DacInstantiateStringA(m_addr, maxChars, false) != NULL; |
| 1411 | } |
| 1412 | void EnumMem(void) const |
| 1413 | { |
| 1414 | char* str = DacInstantiateStringA(m_addr, maxChars, false); |
| 1415 | if (str) |
| 1416 | { |
| 1417 | DacEnumMemoryRegion(m_addr, strlen(str) + 1); |
| 1418 | } |
| 1419 | } |
| 1420 | }; |
| 1421 | |
| 1422 | #define S8PTR(type) __Str8Ptr< type > |
| 1423 | #define S8PTRMAX(type, maxChars) __Str8Ptr< type, maxChars > |
| 1424 | |
| 1425 | // Pointer wrapper for 16-bit strings. |
| 1426 | template<typename type, ULONG32 maxChars = 32760> |
| 1427 | class __Str16Ptr : public __DPtr<WCHAR> |
| 1428 | { |
| 1429 | public: |
| 1430 | typedef type _Type; |
| 1431 | typedef type* _Ptr; |
| 1432 | |
| 1433 | __Str16Ptr< type, maxChars >(void) : __DPtr<WCHAR>() {} |
| 1434 | __Str16Ptr< type, maxChars >(TADDR addr) : __DPtr<WCHAR>(addr) {} |
| 1435 | explicit __Str16Ptr< type, maxChars >(__TPtrBase addr) |
| 1436 | { |
| 1437 | m_addr = addr.GetAddr(); |
| 1438 | } |
| 1439 | explicit __Str16Ptr< type, maxChars >(type* host) |
| 1440 | { |
| 1441 | m_addr = DacGetTargetAddrForHostAddr(host, true); |
| 1442 | } |
| 1443 | |
| 1444 | __Str16Ptr< type, maxChars >& operator=(const __TPtrBase& ptr) |
| 1445 | { |
| 1446 | m_addr = ptr.GetAddr(); |
| 1447 | return *this; |
| 1448 | } |
| 1449 | __Str16Ptr< type, maxChars >& operator=(TADDR addr) |
| 1450 | { |
| 1451 | m_addr = addr; |
| 1452 | return *this; |
| 1453 | } |
| 1454 | |
| 1455 | operator type*() const |
| 1456 | { |
| 1457 | return (type*)DacInstantiateStringW(m_addr, maxChars, true); |
| 1458 | } |
| 1459 | |
| 1460 | bool IsValid(void) const |
| 1461 | { |
| 1462 | return m_addr && |
| 1463 | DacInstantiateStringW(m_addr, maxChars, false) != NULL; |
| 1464 | } |
| 1465 | void EnumMem(void) const |
| 1466 | { |
| 1467 | char* str = DacInstantiateStringW(m_addr, maxChars, false); |
| 1468 | if (str) |
| 1469 | { |
| 1470 | DacEnumMemoryRegion(m_addr, strlen(str) + 1); |
| 1471 | } |
| 1472 | } |
| 1473 | }; |
| 1474 | |
| 1475 | #define S16PTR(type) __Str16Ptr< type > |
| 1476 | #define S16PTRMAX(type, maxChars) __Str16Ptr< type, maxChars > |
| 1477 | |
| 1478 | template<typename type> |
| 1479 | class __GlobalVal |
| 1480 | { |
| 1481 | public: |
| 1482 | __GlobalVal< type >(PULONG rvaPtr) |
| 1483 | { |
| 1484 | m_rvaPtr = rvaPtr; |
| 1485 | } |
| 1486 | |
| 1487 | operator type() const |
| 1488 | { |
| 1489 | return (type)*__DPtr< type >(DacGlobalBase() + *m_rvaPtr); |
| 1490 | } |
| 1491 | |
| 1492 | __DPtr< type > operator&() const |
| 1493 | { |
| 1494 | return __DPtr< type >(DacGlobalBase() + *m_rvaPtr); |
| 1495 | } |
| 1496 | |
| 1497 | // @dbgtodo dac support: This updates values in the host. This seems extremely dangerous |
| 1498 | // to do silently. I'd prefer that a specific (searchable) write function |
| 1499 | // was used. Try disabling this and see what fails... |
| 1500 | __GlobalVal<type> & operator=(const type & val) |
| 1501 | { |
| 1502 | type* ptr = __DPtr< type >(DacGlobalBase() + *m_rvaPtr); |
| 1503 | // Update the host copy; |
| 1504 | *ptr = val; |
| 1505 | // Write back to the target. |
| 1506 | DacWriteHostInstance(ptr, true); |
| 1507 | return *this; |
| 1508 | } |
| 1509 | |
| 1510 | bool IsValid(void) const |
| 1511 | { |
| 1512 | return __DPtr< type >(DacGlobalBase() + *m_rvaPtr).IsValid(); |
| 1513 | } |
| 1514 | void EnumMem(void) const |
| 1515 | { |
| 1516 | TADDR p = DacGlobalBase() + *m_rvaPtr; |
| 1517 | __DPtr< type >(p).EnumMem(); |
| 1518 | } |
| 1519 | |
| 1520 | private: |
| 1521 | PULONG m_rvaPtr; |
| 1522 | }; |
| 1523 | |
| 1524 | template<typename type, size_t size> |
| 1525 | class __GlobalArray |
| 1526 | { |
| 1527 | public: |
| 1528 | __GlobalArray< type, size >(PULONG rvaPtr) |
| 1529 | { |
| 1530 | m_rvaPtr = rvaPtr; |
| 1531 | } |
| 1532 | |
| 1533 | __DPtr< type > operator&() const |
| 1534 | { |
| 1535 | return __DPtr< type >(DacGlobalBase() + *m_rvaPtr); |
| 1536 | } |
| 1537 | |
| 1538 | type& operator[](unsigned int index) const |
| 1539 | { |
| 1540 | return __DPtr< type >(DacGlobalBase() + *m_rvaPtr)[index]; |
| 1541 | } |
| 1542 | |
| 1543 | bool IsValid(void) const |
| 1544 | { |
| 1545 | // Only validates the base pointer, not the full array range. |
| 1546 | return __DPtr< type >(DacGlobalBase() + *m_rvaPtr).IsValid(); |
| 1547 | } |
| 1548 | void EnumMem(void) const |
| 1549 | { |
| 1550 | DacEnumMemoryRegion(DacGlobalBase() + *m_rvaPtr, sizeof(type) * size); |
| 1551 | } |
| 1552 | |
| 1553 | private: |
| 1554 | PULONG m_rvaPtr; |
| 1555 | }; |
| 1556 | |
| 1557 | template<typename acc_type, typename store_type> |
| 1558 | class __GlobalPtr |
| 1559 | { |
| 1560 | public: |
| 1561 | __GlobalPtr< acc_type, store_type >(PULONG rvaPtr) |
| 1562 | { |
| 1563 | m_rvaPtr = rvaPtr; |
| 1564 | } |
| 1565 | |
| 1566 | __DPtr< store_type > operator&() const |
| 1567 | { |
| 1568 | return __DPtr< store_type >(DacGlobalBase() + *m_rvaPtr); |
| 1569 | } |
| 1570 | |
| 1571 | store_type & operator=(store_type & val) |
| 1572 | { |
| 1573 | store_type* ptr = __DPtr< store_type >(DacGlobalBase() + *m_rvaPtr); |
| 1574 | // Update the host copy; |
| 1575 | *ptr = val; |
| 1576 | // Write back to the target. |
| 1577 | DacWriteHostInstance(ptr, true); |
| 1578 | return val; |
| 1579 | } |
| 1580 | |
| 1581 | acc_type operator->() const |
| 1582 | { |
| 1583 | return (acc_type)*__DPtr< store_type >(DacGlobalBase() + *m_rvaPtr); |
| 1584 | } |
| 1585 | operator acc_type() const |
| 1586 | { |
| 1587 | return (acc_type)*__DPtr< store_type >(DacGlobalBase() + *m_rvaPtr); |
| 1588 | } |
| 1589 | operator store_type() const |
| 1590 | { |
| 1591 | return *__DPtr< store_type >(DacGlobalBase() + *m_rvaPtr); |
| 1592 | } |
| 1593 | bool operator!() const |
| 1594 | { |
| 1595 | return !*__DPtr< store_type >(DacGlobalBase() + *m_rvaPtr); |
| 1596 | } |
| 1597 | |
| 1598 | typename store_type::_Type& operator[](int index) |
| 1599 | { |
| 1600 | return (*__DPtr< store_type >(DacGlobalBase() + *m_rvaPtr))[index]; |
| 1601 | } |
| 1602 | |
| 1603 | typename store_type::_Type& operator[](unsigned int index) |
| 1604 | { |
| 1605 | return (*__DPtr< store_type >(DacGlobalBase() + *m_rvaPtr))[index]; |
| 1606 | } |
| 1607 | |
| 1608 | TADDR GetAddr() const |
| 1609 | { |
| 1610 | return (*__DPtr< store_type >(DacGlobalBase() + *m_rvaPtr)).GetAddr(); |
| 1611 | } |
| 1612 | |
| 1613 | TADDR GetAddrRaw () const |
| 1614 | { |
| 1615 | return DacGlobalBase() + *m_rvaPtr; |
| 1616 | } |
| 1617 | |
| 1618 | // This is only testing the the pointer memory is available but does not verify |
| 1619 | // the memory that it points to. |
| 1620 | // |
| 1621 | bool IsValidPtr(void) const |
| 1622 | { |
| 1623 | return __DPtr< store_type >(DacGlobalBase() + *m_rvaPtr).IsValid(); |
| 1624 | } |
| 1625 | |
| 1626 | bool IsValid(void) const |
| 1627 | { |
| 1628 | return __DPtr< store_type >(DacGlobalBase() + *m_rvaPtr).IsValid() && |
| 1629 | (*__DPtr< store_type >(DacGlobalBase() + *m_rvaPtr)).IsValid(); |
| 1630 | } |
| 1631 | void EnumMem(void) const |
| 1632 | { |
| 1633 | __DPtr< store_type > ptr(DacGlobalBase() + *m_rvaPtr); |
| 1634 | ptr.EnumMem(); |
| 1635 | if (ptr.IsValid()) |
| 1636 | { |
| 1637 | (*ptr).EnumMem(); |
| 1638 | } |
| 1639 | } |
| 1640 | |
| 1641 | PULONG m_rvaPtr; |
| 1642 | }; |
| 1643 | |
| 1644 | template<typename acc_type, typename store_type> |
| 1645 | inline bool operator==(const __GlobalPtr<acc_type, store_type>& gptr, |
| 1646 | acc_type host) |
| 1647 | { |
| 1648 | return DacGetTargetAddrForHostAddr(host, true) == |
| 1649 | *__DPtr< TADDR >(DacGlobalBase() + *gptr.m_rvaPtr); |
| 1650 | } |
| 1651 | template<typename acc_type, typename store_type> |
| 1652 | inline bool operator!=(const __GlobalPtr<acc_type, store_type>& gptr, |
| 1653 | acc_type host) |
| 1654 | { |
| 1655 | return !operator==(gptr, host); |
| 1656 | } |
| 1657 | |
| 1658 | template<typename acc_type, typename store_type> |
| 1659 | inline bool operator==(acc_type host, |
| 1660 | const __GlobalPtr<acc_type, store_type>& gptr) |
| 1661 | { |
| 1662 | return DacGetTargetAddrForHostAddr(host, true) == |
| 1663 | *__DPtr< TADDR >(DacGlobalBase() + *gptr.m_rvaPtr); |
| 1664 | } |
| 1665 | template<typename acc_type, typename store_type> |
| 1666 | inline bool operator!=(acc_type host, |
| 1667 | const __GlobalPtr<acc_type, store_type>& gptr) |
| 1668 | { |
| 1669 | return !operator==(host, gptr); |
| 1670 | } |
| 1671 | |
| 1672 | |
| 1673 | // |
| 1674 | // __VoidPtr is a type that behaves like void* but for target pointers. |
| 1675 | // Behavior of PTR_VOID: |
| 1676 | // * has void* semantics. Will compile to void* in non-DAC builds (just like |
| 1677 | // other PTR types. Unlike TADDR, we want pointer semantics. |
| 1678 | // * NOT assignable from host pointer types or convertible to host pointer |
| 1679 | // types - ensures we can't confuse host and target pointers (we'll get |
| 1680 | // compiler errors if we try and cast between them). |
| 1681 | // * like void*, no pointer arithmetic or dereferencing is allowed |
| 1682 | // * like TADDR, can be used to construct any __DPtr / __VPtr instance |
| 1683 | // * representation is the same as a void* (for marshalling / casting) |
| 1684 | // |
| 1685 | // One way in which __VoidPtr is unlike void* is that it can't be cast to |
| 1686 | // pointer or integer types. On the one hand, this is a good thing as it forces |
| 1687 | // us to keep target pointers separate from other data types. On the other hand |
| 1688 | // in practice this means we have to use dac_cast<TADDR> in places where we used |
| 1689 | // to use a (TADDR) cast. Unfortunately C++ provides us no way to allow the |
| 1690 | // explicit cast to primitive types without also allowing implicit conversions. |
| 1691 | // |
| 1692 | // This is very similar in spirit to TADDR. The primary difference is that |
| 1693 | // PTR_VOID has pointer semantics, where TADDR has integer semantics. When |
| 1694 | // dacizing uses of void* to TADDR, casts must be inserted everywhere back to |
| 1695 | // pointer types. If we switch a use of TADDR to PTR_VOID, those casts in |
| 1696 | // DACCESS_COMPILE regions no longer compile (see above). Also, TADDR supports |
| 1697 | // pointer arithmetic, but that might not be necessary (could use PTR_BYTE |
| 1698 | // instead etc.). Ideally we'd probably have just one type for this purpose |
| 1699 | // (named TADDR but with the semantics of PTR_VOID), but outright conversion |
| 1700 | // would require too much work. |
| 1701 | // |
| 1702 | class __VoidPtr : public __TPtrBase |
| 1703 | { |
| 1704 | public: |
| 1705 | __VoidPtr(void) : __TPtrBase() {} |
| 1706 | __VoidPtr(TADDR addr) : __TPtrBase(addr) {} |
| 1707 | |
| 1708 | // Note, unlike __DPtr, this ctor form is not explicit. We allow implicit |
| 1709 | // conversions from any pointer type (just like for void*). |
| 1710 | __VoidPtr(__TPtrBase addr) |
| 1711 | { |
| 1712 | m_addr = addr.GetAddr(); |
| 1713 | } |
| 1714 | |
| 1715 | // Like TPtrBase, VoidPtrs can also be created impicitly from all GlobalPtrs |
| 1716 | template<typename acc_type, typename store_type> |
| 1717 | __VoidPtr(__GlobalPtr<acc_type, store_type> globalPtr) |
| 1718 | { |
| 1719 | m_addr = globalPtr.GetAddr(); |
| 1720 | } |
| 1721 | |
| 1722 | // Note, unlike __DPtr, there is no explicit conversion from host pointer |
| 1723 | // types. Since void* cannot be marshalled, there is no such thing as |
| 1724 | // a void* DAC instance in the host. |
| 1725 | |
| 1726 | // Also, we don't want an implicit conversion to TADDR because then the |
| 1727 | // compiler will allow pointer arithmetic (which it wouldn't allow for |
| 1728 | // void*). Instead, callers can use dac_cast<TADDR> if they want. |
| 1729 | |
| 1730 | // Note, unlike __DPtr, any pointer type can be assigned to a __VoidPtr |
| 1731 | // This is to mirror the assignability of any pointer type to a void* |
| 1732 | __VoidPtr& operator=(const __TPtrBase& ptr) |
| 1733 | { |
| 1734 | m_addr = ptr.GetAddr(); |
| 1735 | return *this; |
| 1736 | } |
| 1737 | __VoidPtr& operator=(TADDR addr) |
| 1738 | { |
| 1739 | m_addr = addr; |
| 1740 | return *this; |
| 1741 | } |
| 1742 | |
| 1743 | // note, no marshalling operators (type* conversion, operator ->, operator*) |
| 1744 | // A void* can't be marshalled because we don't know how much to copy |
| 1745 | |
| 1746 | // PTR_Void can be compared to any other pointer type (because conceptually, |
| 1747 | // any other pointer type should be implicitly convertible to void*) |
| 1748 | bool operator==(const __TPtrBase& ptr) const |
| 1749 | { |
| 1750 | return m_addr == ptr.GetAddr(); |
| 1751 | } |
| 1752 | bool operator==(TADDR addr) const |
| 1753 | { |
| 1754 | return m_addr == addr; |
| 1755 | } |
| 1756 | bool operator!=(const __TPtrBase& ptr) const |
| 1757 | { |
| 1758 | return !operator==(ptr); |
| 1759 | } |
| 1760 | bool operator!=(TADDR addr) const |
| 1761 | { |
| 1762 | return m_addr != addr; |
| 1763 | } |
| 1764 | bool operator<(const __TPtrBase& ptr) const |
| 1765 | { |
| 1766 | return m_addr < ptr.GetAddr(); |
| 1767 | } |
| 1768 | bool operator>(const __TPtrBase& ptr) const |
| 1769 | { |
| 1770 | return m_addr > ptr.GetAddr(); |
| 1771 | } |
| 1772 | bool operator<=(const __TPtrBase& ptr) const |
| 1773 | { |
| 1774 | return m_addr <= ptr.GetAddr(); |
| 1775 | } |
| 1776 | bool operator>=(const __TPtrBase& ptr) const |
| 1777 | { |
| 1778 | return m_addr >= ptr.GetAddr(); |
| 1779 | } |
| 1780 | }; |
| 1781 | |
| 1782 | typedef __VoidPtr PTR_VOID; |
| 1783 | typedef DPTR(PTR_VOID) PTR_PTR_VOID; |
| 1784 | |
| 1785 | // For now we treat pointers to const and non-const void the same in DAC |
| 1786 | // builds. In general, DAC is read-only anyway and so there isn't a danger of |
| 1787 | // writing to these pointers. Also, the non-dac builds will ensure |
| 1788 | // const-correctness. However, if we wanted to support true void* / const void* |
| 1789 | // behavior, we could probably build the follow functionality by templating |
| 1790 | // __VoidPtr: |
| 1791 | // * A PTR_VOID would be implicitly convertable to PTR_CVOID |
| 1792 | // * An explicit coercion (ideally const_cast) would be required to convert a |
| 1793 | // PTR_CVOID to a PTR_VOID |
| 1794 | // * Similarily, an explicit coercion would be required to convert a cost PTR |
| 1795 | // type (eg. PTR_CBYTE) to a PTR_VOID. |
| 1796 | typedef __VoidPtr PTR_CVOID; |
| 1797 | |
| 1798 | |
| 1799 | // The special empty ctor declared here allows the whole |
| 1800 | // class hierarchy to be instantiated easily by the |
| 1801 | // external access code. The actual class body will be |
| 1802 | // read externally so no members should be initialized. |
| 1803 | |
| 1804 | // |
| 1805 | // VPTR_ANY_CLASS_METHODS - Defines the following methods for all VPTR classes |
| 1806 | // |
| 1807 | // VPtrSize |
| 1808 | // Returns the size of the dynamic type of the object (as opposed to sizeof |
| 1809 | // which is based only on the static type). |
| 1810 | // |
| 1811 | // VPtrHostVTable |
| 1812 | // Returns the address of the vtable for this type. |
| 1813 | // We create a temporary instance of this type in order to read it's vtable pointer |
| 1814 | // (at offset 0). For this temporary instance, we do not want to initialize any fields, |
| 1815 | // so we use the marshalling ctor. Since we didn't initialize any fields, we also don't |
| 1816 | // wan't to run the dtor (marshaled data structures don't normally expect their destructor |
| 1817 | // or non-DAC constructors to be called in DAC builds anyway). So, rather than create a |
| 1818 | // normal stack object, or put the object on the heap, we create the temporary object |
| 1819 | // on the stack using placement-new and alloca, and don't destruct it. |
| 1820 | // |
| 1821 | #define VPTR_ANY_CLASS_METHODS(name) \ |
| 1822 | virtual ULONG32 VPtrSize(void) { SUPPORTS_DAC; return sizeof(name); } \ |
| 1823 | static PVOID VPtrHostVTable() { \ |
| 1824 | void * pBuf = _alloca(sizeof(name)); \ |
| 1825 | name * dummy = new (pBuf) name((TADDR)0, (TADDR)0); \ |
| 1826 | return *((PVOID*)dummy); } |
| 1827 | |
| 1828 | #define VPTR_CLASS_METHODS(name) \ |
| 1829 | VPTR_ANY_CLASS_METHODS(name) \ |
| 1830 | static TADDR VPtrTargetVTable() { \ |
| 1831 | SUPPORTS_DAC; \ |
| 1832 | return DacGlobalBase() + g_dacGlobals.name##__vtAddr; } |
| 1833 | |
| 1834 | #define VPTR_MULTI_CLASS_METHODS(name, keyBase) \ |
| 1835 | VPTR_ANY_CLASS_METHODS(name) \ |
| 1836 | static TADDR VPtrTargetVTable() { \ |
| 1837 | SUPPORTS_DAC; \ |
| 1838 | return DacGlobalBase() + g_dacGlobals.name##__##keyBase##__mvtAddr; } |
| 1839 | |
| 1840 | #define VPTR_VTABLE_CLASS(name, base) \ |
| 1841 | public: name(TADDR addr, TADDR vtAddr) : base(addr, vtAddr) {} \ |
| 1842 | VPTR_CLASS_METHODS(name) |
| 1843 | |
| 1844 | #define VPTR_VTABLE_CLASS_AND_CTOR(name, base) \ |
| 1845 | VPTR_VTABLE_CLASS(name, base) |
| 1846 | |
| 1847 | #define VPTR_MULTI_VTABLE_CLASS(name, base) \ |
| 1848 | public: name(TADDR addr, TADDR vtAddr) : base(addr, vtAddr) {} \ |
| 1849 | VPTR_MULTI_CLASS_METHODS(name, base) |
| 1850 | |
| 1851 | // Used for base classes that can be instantiated directly. |
| 1852 | // The fake vfn is still used to force a vtable even when |
| 1853 | // all the normal vfns are ifdef'ed out. |
| 1854 | #define VPTR_BASE_CONCRETE_VTABLE_CLASS(name) \ |
| 1855 | public: name(TADDR addr, TADDR vtAddr) {} \ |
| 1856 | VPTR_CLASS_METHODS(name) |
| 1857 | |
| 1858 | #define VPTR_BASE_CONCRETE_VTABLE_CLASS_NO_CTOR_BODY(name) \ |
| 1859 | public: name(TADDR addr, TADDR vtAddr); \ |
| 1860 | VPTR_CLASS_METHODS(name) |
| 1861 | |
| 1862 | // The pure virtual method forces all derivations to use |
| 1863 | // VPTR_VTABLE_CLASS to compile. |
| 1864 | #define VPTR_BASE_VTABLE_CLASS(name) \ |
| 1865 | public: name(TADDR addr, TADDR vtAddr) {} \ |
| 1866 | virtual ULONG32 VPtrSize(void) = 0; |
| 1867 | |
| 1868 | #define VPTR_BASE_VTABLE_CLASS_AND_CTOR(name) \ |
| 1869 | VPTR_BASE_VTABLE_CLASS(name) |
| 1870 | |
| 1871 | #define VPTR_BASE_VTABLE_CLASS_NO_CTOR_BODY(name) \ |
| 1872 | public: name(TADDR addr, TADDR vtAddr); \ |
| 1873 | virtual ULONG32 VPtrSize(void) = 0; |
| 1874 | |
| 1875 | #define VPTR_ABSTRACT_VTABLE_CLASS(name, base) \ |
| 1876 | public: name(TADDR addr, TADDR vtAddr) : base(addr, vtAddr) {} |
| 1877 | |
| 1878 | #define VPTR_ABSTRACT_VTABLE_CLASS_AND_CTOR(name, base) \ |
| 1879 | VPTR_ABSTRACT_VTABLE_CLASS(name, base) |
| 1880 | |
| 1881 | #define VPTR_ABSTRACT_VTABLE_CLASS_NO_CTOR_BODY(name, base) \ |
| 1882 | public: name(TADDR addr, TADDR vtAddr); |
| 1883 | |
| 1884 | // helper macro to make the vtables unique for DAC |
| 1885 | #define VPTR_UNIQUE(unique) |
| 1886 | |
| 1887 | // Safe access for retrieving the target address of a PTR. |
| 1888 | #define PTR_TO_TADDR(ptr) ((ptr).GetAddr()) |
| 1889 | |
| 1890 | #define GFN_TADDR(name) (DacGlobalBase() + g_dacGlobals.fn__ ## name) |
| 1891 | |
| 1892 | #define GVAL_ADDR(g) \ |
| 1893 | ((g).operator&()) |
| 1894 | |
| 1895 | // |
| 1896 | // References to class static and global data. |
| 1897 | // These all need to be redirected through the global |
| 1898 | // data table. |
| 1899 | // |
| 1900 | |
| 1901 | #define _SPTR_DECL(acc_type, store_type, var) \ |
| 1902 | static __GlobalPtr< acc_type, store_type > var |
| 1903 | #define _SPTR_IMPL(acc_type, store_type, cls, var) \ |
| 1904 | __GlobalPtr< acc_type, store_type > cls::var(&g_dacGlobals.cls##__##var) |
| 1905 | #define _SPTR_IMPL_INIT(acc_type, store_type, cls, var, init) \ |
| 1906 | __GlobalPtr< acc_type, store_type > cls::var(&g_dacGlobals.cls##__##var) |
| 1907 | #define _SPTR_IMPL_NS(acc_type, store_type, ns, cls, var) \ |
| 1908 | __GlobalPtr< acc_type, store_type > cls::var(&g_dacGlobals.ns##__##cls##__##var) |
| 1909 | #define _SPTR_IMPL_NS_INIT(acc_type, store_type, ns, cls, var, init) \ |
| 1910 | __GlobalPtr< acc_type, store_type > cls::var(&g_dacGlobals.ns##__##cls##__##var) |
| 1911 | |
| 1912 | #define _GPTR_DECL(acc_type, store_type, var) \ |
| 1913 | extern __GlobalPtr< acc_type, store_type > var |
| 1914 | #define _GPTR_IMPL(acc_type, store_type, var) \ |
| 1915 | __GlobalPtr< acc_type, store_type > var(&g_dacGlobals.dac__##var) |
| 1916 | #define _GPTR_IMPL_INIT(acc_type, store_type, var, init) \ |
| 1917 | __GlobalPtr< acc_type, store_type > var(&g_dacGlobals.dac__##var) |
| 1918 | |
| 1919 | #define SVAL_DECL(type, var) \ |
| 1920 | static __GlobalVal< type > var |
| 1921 | #define SVAL_IMPL(type, cls, var) \ |
| 1922 | __GlobalVal< type > cls::var(&g_dacGlobals.cls##__##var) |
| 1923 | #define SVAL_IMPL_INIT(type, cls, var, init) \ |
| 1924 | __GlobalVal< type > cls::var(&g_dacGlobals.cls##__##var) |
| 1925 | #define SVAL_IMPL_NS(type, ns, cls, var) \ |
| 1926 | __GlobalVal< type > cls::var(&g_dacGlobals.ns##__##cls##__##var) |
| 1927 | #define SVAL_IMPL_NS_INIT(type, ns, cls, var, init) \ |
| 1928 | __GlobalVal< type > cls::var(&g_dacGlobals.ns##__##cls##__##var) |
| 1929 | |
| 1930 | #define GVAL_DECL(type, var) \ |
| 1931 | extern __GlobalVal< type > var |
| 1932 | #define GVAL_IMPL(type, var) \ |
| 1933 | __GlobalVal< type > var(&g_dacGlobals.dac__##var) |
| 1934 | #define GVAL_IMPL_INIT(type, var, init) \ |
| 1935 | __GlobalVal< type > var(&g_dacGlobals.dac__##var) |
| 1936 | |
| 1937 | #define GARY_DECL(type, var, size) \ |
| 1938 | extern __GlobalArray< type, size > var |
| 1939 | #define GARY_IMPL(type, var, size) \ |
| 1940 | __GlobalArray< type, size > var(&g_dacGlobals.dac__##var) |
| 1941 | |
| 1942 | // Translation from a host pointer back to the target address |
| 1943 | // that was used to retrieve the data for the host pointer. |
| 1944 | #define PTR_HOST_TO_TADDR(host) DacGetTargetAddrForHostAddr(host, true) |
| 1945 | // Translation from a host interior pointer back to the corresponding |
| 1946 | // target address. The host address must reside within a previously |
| 1947 | // retrieved instance. |
| 1948 | #define PTR_HOST_INT_TO_TADDR(host) DacGetTargetAddrForHostInteriorAddr(host, true) |
| 1949 | // Translation from a host vtable pointer to a target vtable pointer. |
| 1950 | #define VPTR_HOST_VTABLE_TO_TADDR(host) DacGetTargetVtForHostVt(host, true) |
| 1951 | |
| 1952 | // Construct a pointer to a member of the given type. |
| 1953 | #define PTR_HOST_MEMBER_TADDR(type, host, memb) \ |
| 1954 | (PTR_HOST_TO_TADDR(host) + (TADDR)offsetof(type, memb)) |
| 1955 | |
| 1956 | // Construct a pointer to a member of the given type given an interior |
| 1957 | // host address. |
| 1958 | #define PTR_HOST_INT_MEMBER_TADDR(type, host, memb) \ |
| 1959 | (PTR_HOST_INT_TO_TADDR(host) + (TADDR)offsetof(type, memb)) |
| 1960 | |
| 1961 | #define PTR_TO_MEMBER_TADDR(type, ptr, memb) \ |
| 1962 | (PTR_TO_TADDR(ptr) + (TADDR)offsetof(type, memb)) |
| 1963 | |
| 1964 | // Constructs an arbitrary data instance for a piece of |
| 1965 | // memory in the target. |
| 1966 | #define PTR_READ(addr, size) \ |
| 1967 | DacInstantiateTypeByAddress(addr, size, true) |
| 1968 | |
| 1969 | // This value is used to intiailize target pointers to NULL. We want this to be TADDR type |
| 1970 | // (as opposed to, say, __TPtrBase) so that it can be used in the non-explicit ctor overloads, |
| 1971 | // eg. as an argument default value. |
| 1972 | // We can't always just use NULL because that's 0 which (in C++) can be any integer or pointer |
| 1973 | // type (causing an ambiguous overload compiler error when used in explicit ctor forms). |
| 1974 | #define PTR_NULL ((TADDR)0) |
| 1975 | |
| 1976 | // Provides an empty method implementation when compiled |
| 1977 | // for DACCESS_COMPILE. For example, use to stub out methods needed |
| 1978 | // for vtable entries but otherwise unused. |
| 1979 | // Note that these functions are explicitly NOT marked SUPPORTS_DAC so that we'll get a |
| 1980 | // DacCop warning if any calls to them are detected. |
| 1981 | // @dbgtodo : It's probably almost always wrong to call any such function, so |
| 1982 | // we should probably throw a better error (DacNotImpl), and ideally mark the function |
| 1983 | // DECLSPEC_NORETURN so we don't have to deal with fabricating return values and we can |
| 1984 | // get compiler warnings (unreachable code) anytime functions marked this way are called. |
| 1985 | #define DAC_EMPTY() { LIMITED_METHOD_CONTRACT; } |
| 1986 | #define DAC_EMPTY_ERR() { LIMITED_METHOD_CONTRACT; DacError(E_UNEXPECTED); } |
| 1987 | #define DAC_EMPTY_RET(retVal) { LIMITED_METHOD_CONTRACT; DacError(E_UNEXPECTED); return retVal; } |
| 1988 | #define DAC_UNEXPECTED() { LIMITED_METHOD_CONTRACT; DacError_NoRet(E_UNEXPECTED); } |
| 1989 | |
| 1990 | #endif // #ifdef __cplusplus |
| 1991 | |
| 1992 | // Implementation details for dac_cast, should never be accessed directly. |
| 1993 | // See code:dac_cast for details and discussion. |
| 1994 | namespace dac_imp |
| 1995 | { |
| 1996 | // Helper functions to get the target address of specific types |
| 1997 | inline TADDR getTaddr(TADDR addr) { return addr; } |
| 1998 | inline TADDR getTaddr(__TPtrBase const &tptr) { return PTR_TO_TADDR(tptr); } |
| 1999 | inline TADDR getTaddr(void const * host) { return PTR_HOST_TO_TADDR((void *)host); } |
| 2000 | template<typename acc_type, typename store_type> |
| 2001 | inline TADDR getTaddr(__GlobalPtr<acc_type, store_type> const &gptr) { return PTR_TO_TADDR(gptr); } |
| 2002 | |
| 2003 | // It is an error to try dac_cast on a __GlobalVal or a __GlobalArray. Declare |
| 2004 | // but do not define the methods so that a compile-time error results. |
| 2005 | template<typename type> |
| 2006 | TADDR getTaddr(__GlobalVal<type> const &gval); |
| 2007 | template<typename type, size_t size> |
| 2008 | TADDR getTaddr(__GlobalArray<type, size> const &garr); |
| 2009 | |
| 2010 | // Helper class to instantiate DAC instances from a TADDR |
| 2011 | // The default implementation assumes we want to create an instance of a PTR type |
| 2012 | template<typename T> struct makeDacInst |
| 2013 | { |
| 2014 | static inline T fromTaddr(TADDR addr) |
| 2015 | { |
| 2016 | static_assert((std::is_base_of<__TPtrBase, T>::value), "is_base_of constraint violation" ); |
| 2017 | return T(addr); |
| 2018 | } |
| 2019 | }; |
| 2020 | |
| 2021 | // Partial specialization for creating TADDRs |
| 2022 | // This is the only other way to create a DAC type instance other than PTR types (above) |
| 2023 | template<> struct makeDacInst<TADDR> |
| 2024 | { |
| 2025 | static inline TADDR fromTaddr(TADDR addr) { return addr; } |
| 2026 | }; |
| 2027 | } // namespace dac_imp |
| 2028 | |
| 2029 | |
| 2030 | // DacCop in-line exclusion mechanism |
| 2031 | |
| 2032 | // Warnings - official home is DacCop\Shared\Warnings.cs, but we want a way for users to indicate |
| 2033 | // warning codes in a way that is descriptive to readers (not just code numbers). The names here |
| 2034 | // don't matter - DacCop just looks at the value |
| 2035 | enum DacCopWarningCode |
| 2036 | { |
| 2037 | // General Rules |
| 2038 | FieldAccess = 1, |
| 2039 | PointerArith = 2, |
| 2040 | PointerComparison = 3, |
| 2041 | InconsistentMarshalling = 4, |
| 2042 | CastBetweenAddressSpaces = 5, |
| 2043 | CastOfMarshalledType = 6, |
| 2044 | VirtualCallToNonVPtr = 7, |
| 2045 | UndacizedGlobalVariable = 8, |
| 2046 | |
| 2047 | // Function graph related |
| 2048 | CallUnknown = 701, |
| 2049 | CallNonDac = 702, |
| 2050 | CallVirtualUnknown = 704, |
| 2051 | CallVirtualNonDac = 705, |
| 2052 | }; |
| 2053 | |
| 2054 | // DACCOP_IGNORE is a mechanism to suppress DacCop violations from within the source-code. |
| 2055 | // See the DacCop wiki for guidance on how best to use this: http://mswikis/clr/dev/Pages/DacCop.aspx |
| 2056 | // |
| 2057 | // DACCOP_IGNORE will suppress a DacCop violation for the following (non-compound) statement. |
| 2058 | // For example: |
| 2059 | // // The "dual-mode DAC problem" occurs in a few places where a class is used both |
| 2060 | // // in the host, and marshalled from the target ... <further details> |
| 2061 | // DACCOP_IGNORE(CastBetweenAddressSpaces,"SBuffer has the dual-mode DAC problem"); |
| 2062 | // TADDR bufAddr = (TADDR)m_buffer; |
| 2063 | // |
| 2064 | // A call to DACCOP_IGNORE must occur as it's own statement, and can apply only to following |
| 2065 | // single-statements (not to compound statement blocks). Occasionally it is necessary to hoist |
| 2066 | // violation-inducing code out to its own statement (e.g., if it occurs in the conditional of an |
| 2067 | // if). |
| 2068 | // |
| 2069 | // Arguments: |
| 2070 | // code: a literal value from DacCopWarningCode indicating which violation should be suppressed. |
| 2071 | // szReasonString: a short description of why this exclusion is necessary. This is intended just |
| 2072 | // to help readers of the code understand the source of the problem, and what would be required |
| 2073 | // to fix it. More details can be provided in comments if desired. |
| 2074 | // |
| 2075 | inline void DACCOP_IGNORE(DacCopWarningCode code, const char * szReasonString) |
| 2076 | { |
| 2077 | // DacCop detects calls to this function. No implementation is necessary. |
| 2078 | } |
| 2079 | |
| 2080 | #else // #ifdef DACCESS_COMPILE |
| 2081 | |
| 2082 | // |
| 2083 | // This version of the macros turns into normal pointers |
| 2084 | // for unmodified in-proc compilation. |
| 2085 | |
| 2086 | // ******************************************************* |
| 2087 | // !!!!!!!!!!!!!!!!!!!!!!!!!NOTE!!!!!!!!!!!!!!!!!!!!!!!!!! |
| 2088 | // |
| 2089 | // Please search this file for the type name to find the |
| 2090 | // DAC versions of these definitions |
| 2091 | // |
| 2092 | // !!!!!!!!!!!!!!!!!!!!!!!!!NOTE!!!!!!!!!!!!!!!!!!!!!!!!!! |
| 2093 | // ******************************************************* |
| 2094 | |
| 2095 | |
| 2096 | // Declare TADDR as a non-pointer type so that arithmetic |
| 2097 | // can be done on it directly, as with the DACCESS_COMPILE definition. |
| 2098 | // This also helps expose pointer usage that may need to be changed. |
| 2099 | typedef ULONG_PTR TADDR; |
| 2100 | |
| 2101 | typedef void* PTR_VOID; |
| 2102 | typedef LPVOID* PTR_PTR_VOID; |
| 2103 | typedef const void* PTR_CVOID; |
| 2104 | |
| 2105 | #define DPTR(type) type* |
| 2106 | #define ArrayDPTR(type) type* |
| 2107 | #define SPTR(type) type* |
| 2108 | #define VPTR(type) type* |
| 2109 | #define S8PTR(type) type* |
| 2110 | #define S8PTRMAX(type, maxChars) type* |
| 2111 | #define S16PTR(type) type* |
| 2112 | #define S16PTRMAX(type, maxChars) type* |
| 2113 | |
| 2114 | #if defined(FEATURE_PAL) |
| 2115 | |
| 2116 | #define VPTR_VTABLE_CLASS(name, base) \ |
| 2117 | friend struct _DacGlobals; \ |
| 2118 | public: name(int dummy) : base(dummy) {} |
| 2119 | |
| 2120 | #define VPTR_VTABLE_CLASS_AND_CTOR(name, base) \ |
| 2121 | VPTR_VTABLE_CLASS(name, base) \ |
| 2122 | name() : base() {} |
| 2123 | |
| 2124 | #define VPTR_MULTI_VTABLE_CLASS(name, base) \ |
| 2125 | friend struct _DacGlobals; \ |
| 2126 | public: name(int dummy) : base(dummy) {} |
| 2127 | |
| 2128 | #define VPTR_BASE_CONCRETE_VTABLE_CLASS(name) \ |
| 2129 | friend struct _DacGlobals; \ |
| 2130 | public: name(int dummy) {} |
| 2131 | |
| 2132 | #define VPTR_BASE_VTABLE_CLASS(name) \ |
| 2133 | friend struct _DacGlobals; \ |
| 2134 | public: name(int dummy) {} |
| 2135 | |
| 2136 | #define VPTR_BASE_VTABLE_CLASS_AND_CTOR(name) \ |
| 2137 | VPTR_BASE_VTABLE_CLASS(name) \ |
| 2138 | name() {} |
| 2139 | |
| 2140 | #define VPTR_ABSTRACT_VTABLE_CLASS(name, base) \ |
| 2141 | friend struct _DacGlobals; \ |
| 2142 | public: name(int dummy) : base(dummy) {} |
| 2143 | |
| 2144 | #define VPTR_ABSTRACT_VTABLE_CLASS_AND_CTOR(name, base) \ |
| 2145 | VPTR_ABSTRACT_VTABLE_CLASS(name, base) \ |
| 2146 | name() : base() {} |
| 2147 | |
| 2148 | #else // FEATURE_PAL |
| 2149 | |
| 2150 | #define VPTR_VTABLE_CLASS(name, base) |
| 2151 | #define VPTR_VTABLE_CLASS_AND_CTOR(name, base) |
| 2152 | #define VPTR_MULTI_VTABLE_CLASS(name, base) |
| 2153 | #define VPTR_BASE_CONCRETE_VTABLE_CLASS(name) |
| 2154 | #define VPTR_BASE_VTABLE_CLASS(name) |
| 2155 | #define VPTR_BASE_VTABLE_CLASS_AND_CTOR(name) |
| 2156 | #define VPTR_ABSTRACT_VTABLE_CLASS(name, base) |
| 2157 | #define VPTR_ABSTRACT_VTABLE_CLASS_AND_CTOR(name, base) |
| 2158 | |
| 2159 | #endif // FEATURE_PAL |
| 2160 | |
| 2161 | // helper macro to make the vtables unique for DAC |
| 2162 | #define VPTR_UNIQUE(unique) virtual int MakeVTableUniqueForDAC() { STATIC_CONTRACT_SO_TOLERANT; return unique; } |
| 2163 | #define VPTR_UNIQUE_BaseDomain (100000) |
| 2164 | #define VPTR_UNIQUE_SystemDomain (VPTR_UNIQUE_BaseDomain + 1) |
| 2165 | #define VPTR_UNIQUE_ComMethodFrame (VPTR_UNIQUE_SystemDomain + 1) |
| 2166 | #define VPTR_UNIQUE_StubHelperFrame (VPTR_UNIQUE_ComMethodFrame + 1) |
| 2167 | #define VPTR_UNIQUE_RedirectedThreadFrame (VPTR_UNIQUE_StubHelperFrame + 1) |
| 2168 | #define VPTR_UNIQUE_HijackFrame (VPTR_UNIQUE_RedirectedThreadFrame + 1) |
| 2169 | |
| 2170 | #define PTR_TO_TADDR(ptr) ((TADDR)(ptr)) |
| 2171 | #define GFN_TADDR(name) ((TADDR)(name)) |
| 2172 | |
| 2173 | #define GVAL_ADDR(g) (&(g)) |
| 2174 | #define _SPTR_DECL(acc_type, store_type, var) \ |
| 2175 | static store_type var |
| 2176 | #define _SPTR_IMPL(acc_type, store_type, cls, var) \ |
| 2177 | store_type cls::var |
| 2178 | #define _SPTR_IMPL_INIT(acc_type, store_type, cls, var, init) \ |
| 2179 | store_type cls::var = init |
| 2180 | #define _SPTR_IMPL_NS(acc_type, store_type, ns, cls, var) \ |
| 2181 | store_type cls::var |
| 2182 | #define _SPTR_IMPL_NS_INIT(acc_type, store_type, ns, cls, var, init) \ |
| 2183 | store_type cls::var = init |
| 2184 | #define _GPTR_DECL(acc_type, store_type, var) \ |
| 2185 | extern store_type var |
| 2186 | #define _GPTR_IMPL(acc_type, store_type, var) \ |
| 2187 | store_type var |
| 2188 | #define _GPTR_IMPL_INIT(acc_type, store_type, var, init) \ |
| 2189 | store_type var = init |
| 2190 | #define SVAL_DECL(type, var) \ |
| 2191 | static type var |
| 2192 | #define SVAL_IMPL(type, cls, var) \ |
| 2193 | type cls::var |
| 2194 | #define SVAL_IMPL_INIT(type, cls, var, init) \ |
| 2195 | type cls::var = init |
| 2196 | #define SVAL_IMPL_NS(type, ns, cls, var) \ |
| 2197 | type cls::var |
| 2198 | #define SVAL_IMPL_NS_INIT(type, ns, cls, var, init) \ |
| 2199 | type cls::var = init |
| 2200 | #define GVAL_DECL(type, var) \ |
| 2201 | extern type var |
| 2202 | #define GVAL_IMPL(type, var) \ |
| 2203 | type var |
| 2204 | #define GVAL_IMPL_INIT(type, var, init) \ |
| 2205 | type var = init |
| 2206 | #define GARY_DECL(type, var, size) \ |
| 2207 | extern type var[size] |
| 2208 | #define GARY_IMPL(type, var, size) \ |
| 2209 | type var[size] |
| 2210 | #define PTR_HOST_TO_TADDR(host) ((TADDR)(host)) |
| 2211 | #define PTR_HOST_INT_TO_TADDR(host) ((TADDR)(host)) |
| 2212 | #define VPTR_HOST_VTABLE_TO_TADDR(host) ((TADDR)(host)) |
| 2213 | #define PTR_HOST_MEMBER_TADDR(type, host, memb) ((TADDR)&(host)->memb) |
| 2214 | #define PTR_HOST_INT_MEMBER_TADDR(type, host, memb) ((TADDR)&(host)->memb) |
| 2215 | #define PTR_TO_MEMBER_TADDR(type, ptr, memb) ((TADDR)&((ptr)->memb)) |
| 2216 | #define PTR_READ(addr, size) ((PVOID)(addr)) |
| 2217 | |
| 2218 | #define PTR_NULL NULL |
| 2219 | |
| 2220 | #define DAC_EMPTY() |
| 2221 | #define DAC_EMPTY_ERR() |
| 2222 | #define DAC_EMPTY_RET(retVal) |
| 2223 | #define DAC_UNEXPECTED() |
| 2224 | |
| 2225 | #define DACCOP_IGNORE(warningCode, reasonString) |
| 2226 | |
| 2227 | #endif // #ifdef DACCESS_COMPILE |
| 2228 | |
| 2229 | //---------------------------------------------------------------------------- |
| 2230 | // dac_cast |
| 2231 | // Casting utility, to be used for casting one class pointer type to another. |
| 2232 | // Use as you would use static_cast |
| 2233 | // |
| 2234 | // dac_cast is designed to act just as static_cast does when |
| 2235 | // dealing with pointers and their DAC abstractions. Specifically, |
| 2236 | // it handles these coversions: |
| 2237 | // |
| 2238 | // dac_cast<TargetType>(SourceTypeVal) |
| 2239 | // |
| 2240 | // where TargetType <- SourceTypeVal are |
| 2241 | // |
| 2242 | // ?PTR(Tgt) <- TADDR - Create PTR type (DPtr etc.) from TADDR |
| 2243 | // ?PTR(Tgt) <- ?PTR(Src) - Convert one PTR type to another |
| 2244 | // ?PTR(Tgt) <- Src * - Create PTR type from dac host object instance |
| 2245 | // TADDR <- ?PTR(Src) - Get TADDR of PTR object (DPtr etc.) |
| 2246 | // TADDR <- Src * - Get TADDR of dac host object instance |
| 2247 | // |
| 2248 | // Note that there is no direct convertion to other host-pointer types (because we don't |
| 2249 | // know if you want a DPTR or VPTR etc.). However, due to the implicit DAC conversions, |
| 2250 | // you can just use dac_cast<PTR_Foo> and assign that to a Foo*. |
| 2251 | // |
| 2252 | // The beauty of this syntax is that it is consistent regardless |
| 2253 | // of source and target casting types. You just use dac_cast |
| 2254 | // and the partial template specialization will do the right thing. |
| 2255 | // |
| 2256 | // One important thing to realise is that all "Foo *" types are |
| 2257 | // assumed to be pointers to host instances that were marshalled by DAC. This should |
| 2258 | // fail at runtime if it's not the case. |
| 2259 | // |
| 2260 | // Some examples would be: |
| 2261 | // |
| 2262 | // - Host pointer of one type to a related host pointer of another |
| 2263 | // type, i.e., MethodDesc * <-> InstantiatedMethodDesc * |
| 2264 | // Syntax: with MethodDesc *pMD, InstantiatedMethodDesc *pInstMD |
| 2265 | // pInstMd = dac_cast<PTR_InstantiatedMethodDesc>(pMD) |
| 2266 | // pMD = dac_cast<PTR_MethodDesc>(pInstMD) |
| 2267 | // |
| 2268 | // - (D|V)PTR of one encapsulated pointer type to a (D|V)PTR of |
| 2269 | // another type, i.e., PTR_AppDomain <-> PTR_BaseDomain |
| 2270 | // Syntax: with PTR_AppDomain pAD, PTR_BaseDomain pBD |
| 2271 | // dac_cast<PTR_AppDomain>(pBD) |
| 2272 | // dac_cast<PTR_BaseDomain>(pAD) |
| 2273 | // |
| 2274 | // Example comparsions of some old and new syntax, where |
| 2275 | // h is a host pointer, such as "Foo *h;" |
| 2276 | // p is a DPTR, such as "PTR_Foo p;" |
| 2277 | // |
| 2278 | // PTR_HOST_TO_TADDR(h) ==> dac_cast<TADDR>(h) |
| 2279 | // PTR_TO_TADDR(p) ==> dac_cast<TADDR>(p) |
| 2280 | // PTR_Foo(PTR_HOST_TO_TADDR(h)) ==> dac_cast<PTR_Foo>(h) |
| 2281 | // |
| 2282 | //---------------------------------------------------------------------------- |
| 2283 | template <typename Tgt, typename Src> |
| 2284 | inline Tgt dac_cast(Src src) |
| 2285 | { |
| 2286 | #ifdef DACCESS_COMPILE |
| 2287 | // In DAC builds, first get a TADDR for the source, then create the |
| 2288 | // appropriate destination instance. |
| 2289 | TADDR addr = dac_imp::getTaddr(src); |
| 2290 | return dac_imp::makeDacInst<Tgt>::fromTaddr(addr); |
| 2291 | #else |
| 2292 | // In non-DAC builds, dac_cast is the same as a C-style cast because we need to support: |
| 2293 | // - casting away const |
| 2294 | // - conversions between pointers and TADDR |
| 2295 | // Perhaps we should more precisely restrict it's usage, but we get the precise |
| 2296 | // restrictions in DAC builds, so it wouldn't buy us much. |
| 2297 | return (Tgt)(src); |
| 2298 | #endif |
| 2299 | } |
| 2300 | |
| 2301 | //---------------------------------------------------------------------------- |
| 2302 | // |
| 2303 | // Convenience macros which work for either mode. |
| 2304 | // |
| 2305 | //---------------------------------------------------------------------------- |
| 2306 | |
| 2307 | #define SPTR_DECL(type, var) _SPTR_DECL(type*, PTR_##type, var) |
| 2308 | #define SPTR_IMPL(type, cls, var) _SPTR_IMPL(type*, PTR_##type, cls, var) |
| 2309 | #define SPTR_IMPL_INIT(type, cls, var, init) _SPTR_IMPL_INIT(type*, PTR_##type, cls, var, init) |
| 2310 | #define SPTR_IMPL_NS(type, ns, cls, var) _SPTR_IMPL_NS(type*, PTR_##type, ns, cls, var) |
| 2311 | #define SPTR_IMPL_NS_INIT(type, ns, cls, var, init) _SPTR_IMPL_NS_INIT(type*, PTR_##type, ns, cls, var, init) |
| 2312 | #define GPTR_DECL(type, var) _GPTR_DECL(type*, PTR_##type, var) |
| 2313 | #define GPTR_IMPL(type, var) _GPTR_IMPL(type*, PTR_##type, var) |
| 2314 | #define GPTR_IMPL_INIT(type, var, init) _GPTR_IMPL_INIT(type*, PTR_##type, var, init) |
| 2315 | |
| 2316 | |
| 2317 | // If you want to marshal a single instance of an ArrayDPtr over to the host and |
| 2318 | // return a pointer to it, you can use this function. However, this is unsafe because |
| 2319 | // users of value may assume they can do pointer arithmetic on it. This is exactly |
| 2320 | // the bugs ArrayDPtr is designed to prevent. See code:__ArrayDPtr for details. |
| 2321 | template<typename type> |
| 2322 | inline type* DacUnsafeMarshalSingleElement( ArrayDPTR(type) arrayPtr ) |
| 2323 | { |
| 2324 | return (DPTR(type))(arrayPtr); |
| 2325 | } |
| 2326 | |
| 2327 | //---------------------------------------------------------------------------- |
| 2328 | // |
| 2329 | // Forward typedefs for system types. This is a convenient place |
| 2330 | // to declare things for system types, plus it gives us a central |
| 2331 | // place to look at when deciding what types may cause issues for |
| 2332 | // cross-platform compilation. |
| 2333 | // |
| 2334 | //---------------------------------------------------------------------------- |
| 2335 | |
| 2336 | typedef ArrayDPTR(BYTE) PTR_BYTE; |
| 2337 | typedef ArrayDPTR(uint8_t) PTR_uint8_t; |
| 2338 | typedef DPTR(PTR_BYTE) PTR_PTR_BYTE; |
| 2339 | typedef DPTR(PTR_uint8_t) PTR_PTR_uint8_t; |
| 2340 | typedef DPTR(PTR_PTR_BYTE) PTR_PTR_PTR_BYTE; |
| 2341 | typedef ArrayDPTR(signed char) PTR_SBYTE; |
| 2342 | typedef ArrayDPTR(const BYTE) PTR_CBYTE; |
| 2343 | typedef DPTR(INT8) PTR_INT8; |
| 2344 | typedef DPTR(INT16) PTR_INT16; |
| 2345 | typedef DPTR(UINT16) PTR_UINT16; |
| 2346 | typedef DPTR(WORD) PTR_WORD; |
| 2347 | typedef DPTR(USHORT) PTR_USHORT; |
| 2348 | typedef DPTR(DWORD) PTR_DWORD; |
| 2349 | typedef DPTR(uint32_t) PTR_uint32_t; |
| 2350 | typedef DPTR(LONG) PTR_LONG; |
| 2351 | typedef DPTR(ULONG) PTR_ULONG; |
| 2352 | typedef DPTR(INT32) PTR_INT32; |
| 2353 | typedef DPTR(UINT32) PTR_UINT32; |
| 2354 | typedef DPTR(ULONG64) PTR_ULONG64; |
| 2355 | typedef DPTR(INT64) PTR_INT64; |
| 2356 | typedef DPTR(UINT64) PTR_UINT64; |
| 2357 | typedef DPTR(SIZE_T) PTR_SIZE_T; |
| 2358 | typedef DPTR(size_t) PTR_size_t; |
| 2359 | typedef DPTR(TADDR) PTR_TADDR; |
| 2360 | typedef DPTR(int) PTR_int; |
| 2361 | typedef DPTR(BOOL) PTR_BOOL; |
| 2362 | typedef DPTR(unsigned) PTR_unsigned; |
| 2363 | |
| 2364 | typedef S8PTR(char) PTR_STR; |
| 2365 | typedef S8PTR(const char) PTR_CSTR; |
| 2366 | typedef S8PTR(char) PTR_UTF8; |
| 2367 | typedef S8PTR(const char) PTR_CUTF8; |
| 2368 | typedef S16PTR(WCHAR) PTR_WSTR; |
| 2369 | typedef S16PTR(const WCHAR) PTR_CWSTR; |
| 2370 | |
| 2371 | typedef DPTR(T_CONTEXT) PTR_CONTEXT; |
| 2372 | typedef DPTR(PTR_CONTEXT) PTR_PTR_CONTEXT; |
| 2373 | typedef DPTR(struct _EXCEPTION_POINTERS) PTR_EXCEPTION_POINTERS; |
| 2374 | typedef DPTR(struct _EXCEPTION_RECORD) PTR_EXCEPTION_RECORD; |
| 2375 | |
| 2376 | typedef DPTR(struct _EXCEPTION_REGISTRATION_RECORD) PTR_EXCEPTION_REGISTRATION_RECORD; |
| 2377 | |
| 2378 | typedef DPTR(struct IMAGE_COR_VTABLEFIXUP) PTR_IMAGE_COR_VTABLEFIXUP; |
| 2379 | typedef DPTR(IMAGE_DATA_DIRECTORY) PTR_IMAGE_DATA_DIRECTORY; |
| 2380 | typedef DPTR(IMAGE_DEBUG_DIRECTORY) PTR_IMAGE_DEBUG_DIRECTORY; |
| 2381 | typedef DPTR(IMAGE_DOS_HEADER) ; |
| 2382 | typedef DPTR(IMAGE_NT_HEADERS) ; |
| 2383 | typedef DPTR(IMAGE_NT_HEADERS32) ; |
| 2384 | typedef DPTR(IMAGE_NT_HEADERS64) ; |
| 2385 | typedef DPTR(IMAGE_SECTION_HEADER) ; |
| 2386 | typedef DPTR(IMAGE_TLS_DIRECTORY) PTR_IMAGE_TLS_DIRECTORY; |
| 2387 | |
| 2388 | #if defined(DACCESS_COMPILE) |
| 2389 | #include <corhdr.h> |
| 2390 | #include <clrdata.h> |
| 2391 | #include <xclrdata.h> |
| 2392 | #endif |
| 2393 | |
| 2394 | #if defined(_TARGET_X86_) && defined(FEATURE_PAL) |
| 2395 | typedef DPTR(struct _UNWIND_INFO) PTR_UNWIND_INFO; |
| 2396 | #endif |
| 2397 | |
| 2398 | #ifdef _TARGET_64BIT_ |
| 2399 | typedef DPTR(T_RUNTIME_FUNCTION) PTR_RUNTIME_FUNCTION; |
| 2400 | typedef DPTR(struct _UNWIND_INFO) PTR_UNWIND_INFO; |
| 2401 | #if defined(_TARGET_AMD64_) |
| 2402 | typedef DPTR(union _UNWIND_CODE) PTR_UNWIND_CODE; |
| 2403 | #endif // _TARGET_AMD64_ |
| 2404 | #endif // _TARGET_64BIT_ |
| 2405 | |
| 2406 | #ifdef _TARGET_ARM_ |
| 2407 | typedef DPTR(T_RUNTIME_FUNCTION) PTR_RUNTIME_FUNCTION; |
| 2408 | #endif |
| 2409 | |
| 2410 | //---------------------------------------------------------------------------- |
| 2411 | // |
| 2412 | // A PCODE is a valid PC/IP value -- a pointer to an instruction, possibly including some processor mode bits. |
| 2413 | // (On ARM, for example, a PCODE value should have the low-order THUMB_CODE bit set if the code should |
| 2414 | // be executed in that mode.) |
| 2415 | // |
| 2416 | typedef TADDR PCODE; |
| 2417 | typedef DPTR(PCODE) PTR_PCODE; |
| 2418 | typedef DPTR(PTR_PCODE) PTR_PTR_PCODE; |
| 2419 | |
| 2420 | // There is another concept we should have, "pointer to the start of an instruction" -- a PCODE with any mode bits masked off. |
| 2421 | // Attempts to introduce this concept, and classify uses of PCODE as one or the other, |
| 2422 | // turned out to be too hard: either name choice required *many* code changes, and decisions in unfamiliar code. So despite the |
| 2423 | // the comment above, the PCODE is currently sometimes used for the PINSTR concept. |
| 2424 | |
| 2425 | // See PCODEToPINSTR in utilcode.h for conversion from PCODE to PINSTR. |
| 2426 | |
| 2427 | //---------------------------------------------------------------------------- |
| 2428 | // |
| 2429 | // The access code compile must compile data structures that exactly |
| 2430 | // match the real structures for access to work. The access code |
| 2431 | // doesn't want all of the debugging validation code, though, so |
| 2432 | // distinguish between _DEBUG, for declaring general debugging data |
| 2433 | // and always-on debug code, and _DEBUG_IMPL, for debugging code |
| 2434 | // which will be disabled when compiling for external access. |
| 2435 | // |
| 2436 | //---------------------------------------------------------------------------- |
| 2437 | |
| 2438 | #if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE) |
| 2439 | #define _DEBUG_IMPL 1 |
| 2440 | #endif |
| 2441 | |
| 2442 | // Helper macro for tracking EnumMemoryRegions progress. |
| 2443 | #if 0 |
| 2444 | #define EMEM_OUT(args) DacWarning args |
| 2445 | #else |
| 2446 | #define EMEM_OUT(args) |
| 2447 | #endif |
| 2448 | |
| 2449 | // Macros like MAIN_CLR_MODULE_NAME* for the DAC module |
| 2450 | #define MAIN_DAC_MODULE_NAME_W W("mscordaccore") |
| 2451 | #define MAIN_DAC_MODULE_DLL_NAME_W W("mscordaccore.dll") |
| 2452 | |
| 2453 | // TARGET_CONSISTENCY_CHECK represents a condition that should not fail unless the DAC target is corrupt. |
| 2454 | // This is in contrast to ASSERTs in DAC infrastructure code which shouldn't fail regardless of the memory |
| 2455 | // read from the target. At the moment we treat these the same, but in the future we will want a mechanism |
| 2456 | // for disabling just the target consistency checks (eg. for tests that intentionally use corrupted targets). |
| 2457 | // @dbgtodo : Separating asserts and target consistency checks is tracked by DevDiv Bugs 31674 |
| 2458 | #define TARGET_CONSISTENCY_CHECK(expr,msg) _ASSERTE_MSG(expr,msg) |
| 2459 | |
| 2460 | #endif // #ifndef __daccess_h__ |
| 2461 | |