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 | |