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: ValueHome.cpp |
6 | // |
7 | |
8 | // |
9 | //***************************************************************************** |
10 | #include "stdafx.h" |
11 | #include "primitives.h" |
12 | |
13 | // constructor to initialize an instance of EnregisteredValueHome |
14 | // Arguments: |
15 | // input: pFrame - frame to which the value belongs |
16 | // output: no out parameters, but the instance has been initialized |
17 | EnregisteredValueHome::EnregisteredValueHome(const CordbNativeFrame * pFrame): |
18 | m_pFrame(pFrame) |
19 | { |
20 | _ASSERTE(pFrame != NULL); |
21 | } |
22 | |
23 | // ---------------------------------------------------------------------------- |
24 | // RegValueHome member function implementations |
25 | // ---------------------------------------------------------------------------- |
26 | |
27 | // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this |
28 | // instance of a derived class of EnregisteredValueHome (see EnregisteredValueHome::CopyToIPCEType for full |
29 | // header comment) |
30 | void RegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) |
31 | { |
32 | pRegAddr->kind = RAK_REG; |
33 | pRegAddr->reg1 = m_reg1Info.m_kRegNumber; |
34 | pRegAddr->reg1Addr = CORDB_ADDRESS_TO_PTR(m_reg1Info.m_regAddr); |
35 | pRegAddr->reg1Value = m_reg1Info.m_regValue; |
36 | } // RegValueHome::CopyToIPCEType |
37 | |
38 | // RegValueHome::SetContextRegister |
39 | // This will update a register in a given context, and in the regdisplay of a given frame. |
40 | // Arguments: |
41 | // input: pContext - context from which the register comes |
42 | // regnum - enumeration constant indicating which register is to be updated |
43 | // newVal - the new value for the register contents |
44 | // output: no out parameters, but the new value will be written to the context and the frame |
45 | // Notes: We don't take a data target here because we are directly writing process memory and passing |
46 | // in a context, which has the location to update. |
47 | // Throws |
48 | void RegValueHome::SetContextRegister(DT_CONTEXT * pContext, |
49 | CorDebugRegister regNum, |
50 | SIZE_T newVal) |
51 | { |
52 | LPVOID rdRegAddr; |
53 | |
54 | #define _UpdateFrame() \ |
55 | if (m_pFrame != NULL) \ |
56 | { \ |
57 | rdRegAddr = m_pFrame->GetAddressOfRegister(regNum); \ |
58 | *(SIZE_T *)rdRegAddr = newVal; \ |
59 | } |
60 | |
61 | switch(regNum) |
62 | { |
63 | case REGISTER_INSTRUCTION_POINTER: CORDbgSetIP(pContext, (LPVOID)newVal); break; |
64 | case REGISTER_STACK_POINTER: CORDbgSetSP(pContext, (LPVOID)newVal); break; |
65 | |
66 | #if defined(DBG_TARGET_X86) |
67 | case REGISTER_FRAME_POINTER: CORDbgSetFP(pContext, (LPVOID)newVal); |
68 | _UpdateFrame(); break; |
69 | |
70 | case REGISTER_X86_EAX: pContext->Eax = newVal; |
71 | _UpdateFrame(); break; |
72 | case REGISTER_X86_ECX: pContext->Ecx = newVal; |
73 | _UpdateFrame(); break; |
74 | case REGISTER_X86_EDX: pContext->Edx = newVal; |
75 | _UpdateFrame(); break; |
76 | case REGISTER_X86_EBX: pContext->Ebx = newVal; |
77 | _UpdateFrame(); break; |
78 | case REGISTER_X86_ESI: pContext->Esi = newVal; |
79 | _UpdateFrame(); break; |
80 | case REGISTER_X86_EDI: pContext->Edi = newVal; |
81 | _UpdateFrame(); break; |
82 | |
83 | #elif defined(DBG_TARGET_AMD64) |
84 | case REGISTER_AMD64_RBP: pContext->Rbp = newVal; |
85 | _UpdateFrame(); break; |
86 | case REGISTER_AMD64_RAX: pContext->Rax = newVal; |
87 | _UpdateFrame(); break; |
88 | case REGISTER_AMD64_RCX: pContext->Rcx = newVal; |
89 | _UpdateFrame(); break; |
90 | case REGISTER_AMD64_RDX: pContext->Rdx = newVal; |
91 | _UpdateFrame(); break; |
92 | case REGISTER_AMD64_RBX: pContext->Rbx = newVal; |
93 | _UpdateFrame(); break; |
94 | case REGISTER_AMD64_RSI: pContext->Rsi = newVal; |
95 | _UpdateFrame(); break; |
96 | case REGISTER_AMD64_RDI: pContext->Rdi = newVal; |
97 | _UpdateFrame(); break; |
98 | case REGISTER_AMD64_R8: pContext->R8 = newVal; |
99 | _UpdateFrame(); break; |
100 | case REGISTER_AMD64_R9: pContext->R9 = newVal; |
101 | _UpdateFrame(); break; |
102 | case REGISTER_AMD64_R10: pContext->R10 = newVal; |
103 | _UpdateFrame(); break; |
104 | case REGISTER_AMD64_R11: pContext->R11 = newVal; |
105 | _UpdateFrame(); break; |
106 | case REGISTER_AMD64_R12: pContext->R12 = newVal; |
107 | _UpdateFrame(); break; |
108 | case REGISTER_AMD64_R13: pContext->R13 = newVal; |
109 | _UpdateFrame(); break; |
110 | case REGISTER_AMD64_R14: pContext->R14 = newVal; |
111 | _UpdateFrame(); break; |
112 | case REGISTER_AMD64_R15: pContext->R15 = newVal; |
113 | _UpdateFrame(); break; |
114 | #elif defined(DBG_TARGET_ARM) |
115 | case REGISTER_ARM_R0: pContext->R0 = newVal; |
116 | _UpdateFrame(); break; |
117 | case REGISTER_ARM_R1: pContext->R1 = newVal; |
118 | _UpdateFrame(); break; |
119 | case REGISTER_ARM_R2: pContext->R2 = newVal; |
120 | _UpdateFrame(); break; |
121 | case REGISTER_ARM_R3: pContext->R3 = newVal; |
122 | _UpdateFrame(); break; |
123 | case REGISTER_ARM_R4: pContext->R4 = newVal; |
124 | _UpdateFrame(); break; |
125 | case REGISTER_ARM_R5: pContext->R5 = newVal; |
126 | _UpdateFrame(); break; |
127 | case REGISTER_ARM_R6: pContext->R6 = newVal; |
128 | _UpdateFrame(); break; |
129 | case REGISTER_ARM_R7: pContext->R7 = newVal; |
130 | _UpdateFrame(); break; |
131 | case REGISTER_ARM_R8: pContext->R8 = newVal; |
132 | _UpdateFrame(); break; |
133 | case REGISTER_ARM_R9: pContext->R9 = newVal; |
134 | _UpdateFrame(); break; |
135 | case REGISTER_ARM_R10: pContext->R10 = newVal; |
136 | _UpdateFrame(); break; |
137 | case REGISTER_ARM_R11: pContext->R11 = newVal; |
138 | _UpdateFrame(); break; |
139 | case REGISTER_ARM_R12: pContext->R12 = newVal; |
140 | _UpdateFrame(); break; |
141 | case REGISTER_ARM_LR: pContext->Lr = newVal; |
142 | _UpdateFrame(); break; |
143 | #elif defined(DBG_TARGET_ARM64) |
144 | case REGISTER_ARM64_X0: |
145 | case REGISTER_ARM64_X1: |
146 | case REGISTER_ARM64_X2: |
147 | case REGISTER_ARM64_X3: |
148 | case REGISTER_ARM64_X4: |
149 | case REGISTER_ARM64_X5: |
150 | case REGISTER_ARM64_X6: |
151 | case REGISTER_ARM64_X7: |
152 | case REGISTER_ARM64_X8: |
153 | case REGISTER_ARM64_X9: |
154 | case REGISTER_ARM64_X10: |
155 | case REGISTER_ARM64_X11: |
156 | case REGISTER_ARM64_X12: |
157 | case REGISTER_ARM64_X13: |
158 | case REGISTER_ARM64_X14: |
159 | case REGISTER_ARM64_X15: |
160 | case REGISTER_ARM64_X16: |
161 | case REGISTER_ARM64_X17: |
162 | case REGISTER_ARM64_X18: |
163 | case REGISTER_ARM64_X19: |
164 | case REGISTER_ARM64_X20: |
165 | case REGISTER_ARM64_X21: |
166 | case REGISTER_ARM64_X22: |
167 | case REGISTER_ARM64_X23: |
168 | case REGISTER_ARM64_X24: |
169 | case REGISTER_ARM64_X25: |
170 | case REGISTER_ARM64_X26: |
171 | case REGISTER_ARM64_X27: |
172 | case REGISTER_ARM64_X28: pContext->X[regNum - REGISTER_ARM64_X0] = newVal; |
173 | _UpdateFrame(); break; |
174 | |
175 | case REGISTER_ARM64_LR: pContext->Lr = newVal; |
176 | _UpdateFrame(); break; |
177 | #endif |
178 | default: |
179 | _ASSERTE(!"Invalid register number!" ); |
180 | ThrowHR(E_FAIL); |
181 | } |
182 | } // RegValueHome::SetContextRegister |
183 | |
184 | // RegValueHome::SetEnregisteredValue |
185 | // set a remote enregistered location to a new value (see code:EnregisteredValueHome::SetEnregisteredValue |
186 | // for full header comment) |
187 | void RegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) |
188 | { |
189 | SIZE_T extendedVal = 0; |
190 | |
191 | // If the value is in a reg, then it's going to be a register's width (regardless of |
192 | // the actual width of the data). |
193 | // For signed types, like i2, i1, make sure we sign extend. |
194 | |
195 | if (fIsSigned) |
196 | { |
197 | // Sign extend. SSIZE_T is a register size signed value. |
198 | // Casting |
199 | switch(newValue.Size()) |
200 | { |
201 | case 1: _ASSERTE(sizeof( BYTE) == 1); |
202 | extendedVal = (SSIZE_T) *(char*)newValue.StartAddress(); break; |
203 | case 2: _ASSERTE(sizeof( WORD) == 2); |
204 | extendedVal = (SSIZE_T) *(short*)newValue.StartAddress(); break; |
205 | case 4: _ASSERTE(sizeof(DWORD) == 4); |
206 | extendedVal = (SSIZE_T) *(int*)newValue.StartAddress(); break; |
207 | #if defined(DBG_TARGET_WIN64) |
208 | case 8: _ASSERTE(sizeof(ULONGLONG) == 8); |
209 | extendedVal = (SSIZE_T) *(ULONGLONG*)newValue.StartAddress(); break; |
210 | #endif // DBG_TARGET_WIN64 |
211 | default: _ASSERTE(!"bad size" ); |
212 | } |
213 | } |
214 | else |
215 | { |
216 | // Zero extend. |
217 | switch(newValue.Size()) |
218 | { |
219 | case 1: _ASSERTE(sizeof( BYTE) == 1); |
220 | extendedVal = *( BYTE*)newValue.StartAddress(); break; |
221 | case 2: _ASSERTE(sizeof( WORD) == 2); |
222 | extendedVal = *( WORD*)newValue.StartAddress(); break; |
223 | case 4: _ASSERTE(sizeof(DWORD) == 4); |
224 | extendedVal = *(DWORD*)newValue.StartAddress(); break; |
225 | #if defined(DBG_TARGET_WIN64) |
226 | case 8: _ASSERTE(sizeof(ULONGLONG) == 8); |
227 | extendedVal = *(ULONGLONG*)newValue.StartAddress(); break; |
228 | #endif // DBG_TARGET_WIN64 |
229 | default: _ASSERTE(!"bad size" ); |
230 | } |
231 | } |
232 | |
233 | SetContextRegister(pContext, m_reg1Info.m_kRegNumber, extendedVal); // throws |
234 | } // RegValueHome::SetEnregisteredValue |
235 | |
236 | // RegValueHome::GetEnregisteredValue |
237 | // Gets an enregistered value and returns it to the caller (see EnregisteredValueHome::GetEnregisteredValue |
238 | // for full header comment) |
239 | void RegValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) |
240 | { |
241 | UINT_PTR* reg = m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber); |
242 | PREFIX_ASSUME(reg != NULL); |
243 | _ASSERTE(sizeof(*reg) == valueOutBuffer.Size()); |
244 | |
245 | memcpy(valueOutBuffer.StartAddress(), reg, sizeof(*reg)); |
246 | } // RegValueHome::GetEnregisteredValue |
247 | |
248 | |
249 | // ---------------------------------------------------------------------------- |
250 | // RegRegValueHome member function implementations |
251 | // ---------------------------------------------------------------------------- |
252 | |
253 | // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this |
254 | // instance of a derived class of EnregisteredValueHome (see EnregisteredValueHome::CopyToIPCEType for full |
255 | // header comment) |
256 | void RegRegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) |
257 | { |
258 | pRegAddr->kind = RAK_REGREG; |
259 | pRegAddr->reg1 = m_reg1Info.m_kRegNumber; |
260 | pRegAddr->reg1Addr = CORDB_ADDRESS_TO_PTR(m_reg1Info.m_regAddr); |
261 | pRegAddr->reg1Value = m_reg1Info.m_regValue; |
262 | pRegAddr->u.reg2 = m_reg2Info.m_kRegNumber; |
263 | pRegAddr->u.reg2Addr = CORDB_ADDRESS_TO_PTR(m_reg2Info.m_regAddr); |
264 | pRegAddr->u.reg2Value = m_reg2Info.m_regValue; |
265 | } // RegRegValueHome::CopyToIPCEType |
266 | |
267 | // RegRegValueHome::SetEnregisteredValue |
268 | // set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue |
269 | // for full header comment) |
270 | void RegRegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) |
271 | { |
272 | _ASSERTE(newValue.Size() == 8); |
273 | _ASSERTE(REG_SIZE == sizeof(void*)); |
274 | |
275 | // Split the new value into high and low parts. |
276 | SIZE_T highPart; |
277 | SIZE_T lowPart; |
278 | |
279 | memcpy(&lowPart, newValue.StartAddress(), REG_SIZE); |
280 | memcpy(&highPart, (BYTE *)newValue.StartAddress() + REG_SIZE, REG_SIZE); |
281 | |
282 | // Update the proper registers. |
283 | SetContextRegister(pContext, m_reg1Info.m_kRegNumber, highPart); // throws |
284 | SetContextRegister(pContext, m_reg2Info.m_kRegNumber, lowPart); // throws |
285 | |
286 | // update the frame's register display |
287 | void * valueAddress = (void *)(m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber)); |
288 | memcpy(valueAddress, newValue.StartAddress(), newValue.Size()); |
289 | } // RegRegValueHome::SetEnregisteredValue |
290 | |
291 | // RegRegValueHome::GetEnregisteredValue |
292 | // Gets an enregistered value and returns it to the caller (see EnregisteredValueHome::GetEnregisteredValue |
293 | // for full header comment) |
294 | void RegRegValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) |
295 | { |
296 | UINT_PTR* highWordAddr = m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber); |
297 | PREFIX_ASSUME(highWordAddr != NULL); |
298 | |
299 | UINT_PTR* lowWordAddr = m_pFrame->GetAddressOfRegister(m_reg2Info.m_kRegNumber); |
300 | PREFIX_ASSUME(lowWordAddr != NULL); |
301 | |
302 | _ASSERTE(sizeof(*highWordAddr) + sizeof(*lowWordAddr) == valueOutBuffer.Size()); |
303 | |
304 | memcpy(valueOutBuffer.StartAddress(), lowWordAddr, sizeof(*lowWordAddr)); |
305 | memcpy((BYTE *)valueOutBuffer.StartAddress() + sizeof(*lowWordAddr), highWordAddr, sizeof(*highWordAddr)); |
306 | |
307 | } // RegRegValueHome::GetEnregisteredValue |
308 | |
309 | |
310 | // ---------------------------------------------------------------------------- |
311 | // RegMemValueHome member function implementations |
312 | // ---------------------------------------------------------------------------- |
313 | |
314 | // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this |
315 | // instance of a derived class of EnregisteredValueHome (see EnregisteredValueHome::CopyToIPCEType for full |
316 | // header comment) |
317 | void RegMemValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) |
318 | { |
319 | pRegAddr->kind = RAK_REGMEM; |
320 | pRegAddr->reg1 = m_reg1Info.m_kRegNumber; |
321 | pRegAddr->reg1Addr = CORDB_ADDRESS_TO_PTR(m_reg1Info.m_regAddr); |
322 | pRegAddr->reg1Value = m_reg1Info.m_regValue; |
323 | pRegAddr->addr = m_memAddr; |
324 | } // RegMemValueHome::CopyToIPCEType |
325 | |
326 | // RegMemValueHome::SetEnregisteredValue |
327 | // set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue |
328 | // for full header comment) |
329 | void RegMemValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) |
330 | { |
331 | _ASSERTE(newValue.Size() == REG_SIZE >> 1); // make sure we have bytes for two registers |
332 | _ASSERTE(REG_SIZE == sizeof(void*)); |
333 | |
334 | // Split the new value into high and low parts. |
335 | SIZE_T highPart; |
336 | SIZE_T lowPart; |
337 | |
338 | memcpy(&lowPart, newValue.StartAddress(), REG_SIZE); |
339 | memcpy(&highPart, (BYTE *)newValue.StartAddress() + REG_SIZE, REG_SIZE); |
340 | |
341 | // Update the proper registers. |
342 | SetContextRegister(pContext, m_reg1Info.m_kRegNumber, highPart); // throws |
343 | |
344 | _ASSERTE(REG_SIZE == sizeof(lowPart)); |
345 | HRESULT hr = m_pFrame->GetProcess()->SafeReadStruct(m_memAddr, &lowPart); |
346 | IfFailThrow(hr); |
347 | |
348 | } // RegMemValueHome::SetEnregisteredValue |
349 | |
350 | // RegMemValueHome::GetEnregisteredValue |
351 | // Gets an enregistered value and returns it to the caller (see EnregisteredValueHome::GetEnregisteredValue |
352 | // for full header comment) |
353 | void RegMemValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) |
354 | { |
355 | // Read the high bits from the register... |
356 | UINT_PTR* highBitsAddr = m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber); |
357 | PREFIX_ASSUME(highBitsAddr != NULL); |
358 | |
359 | // ... and the low bits from the remote process |
360 | DWORD lowBits; |
361 | HRESULT hr = m_pFrame->GetProcess()->SafeReadStruct(m_memAddr, &lowBits); |
362 | IfFailThrow(hr); |
363 | |
364 | _ASSERTE(sizeof(lowBits)+sizeof(*highBitsAddr) == valueOutBuffer.Size()); |
365 | |
366 | memcpy(valueOutBuffer.StartAddress(), &lowBits, sizeof(lowBits)); |
367 | memcpy((BYTE *)valueOutBuffer.StartAddress() + sizeof(lowBits), highBitsAddr, sizeof(*highBitsAddr)); |
368 | |
369 | } // RegMemValueHome::GetEnregisteredValue |
370 | |
371 | |
372 | // ---------------------------------------------------------------------------- |
373 | // MemRegValueHome member function implementations |
374 | // ---------------------------------------------------------------------------- |
375 | |
376 | // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this |
377 | // instance of a derived class of EnregisteredValueHome (see EnregisteredValueHome::CopyToIPCEType for full |
378 | // header comment) |
379 | void MemRegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) |
380 | { |
381 | pRegAddr->kind = RAK_MEMREG; |
382 | pRegAddr->reg1 = m_reg1Info.m_kRegNumber; |
383 | pRegAddr->reg1Addr = CORDB_ADDRESS_TO_PTR(m_reg1Info.m_regAddr); |
384 | pRegAddr->reg1Value = m_reg1Info.m_regValue; |
385 | pRegAddr->addr = m_memAddr; |
386 | } // MemRegValueHome::CopyToIPCEType |
387 | |
388 | // MemRegValueHome::SetEnregisteredValue |
389 | // set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue |
390 | // for full header comment) |
391 | void MemRegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) |
392 | { |
393 | _ASSERTE(newValue.Size() == REG_SIZE << 1); // make sure we have bytes for two registers |
394 | _ASSERTE(REG_SIZE == sizeof(void *)); |
395 | |
396 | // Split the new value into high and low parts. |
397 | SIZE_T highPart; |
398 | SIZE_T lowPart; |
399 | |
400 | memcpy(&lowPart, newValue.StartAddress(), REG_SIZE); |
401 | memcpy(&highPart, (BYTE *)newValue.StartAddress() + REG_SIZE, REG_SIZE); |
402 | |
403 | // Update the proper registers. |
404 | SetContextRegister(pContext, m_reg1Info.m_kRegNumber, lowPart); // throws |
405 | |
406 | _ASSERTE(REG_SIZE == sizeof(highPart)); |
407 | HRESULT hr = m_pFrame->GetProcess()->SafeWriteStruct(m_memAddr, &highPart); |
408 | IfFailThrow(hr); |
409 | } // MemRegValueHome::SetEnregisteredValue |
410 | |
411 | // MemRegValueHome::GetEnregisteredValue |
412 | // Gets an enregistered value and returns it to the caller (see EnregisteredValueHome::GetEnregisteredValue |
413 | // for full header comment) |
414 | void MemRegValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) |
415 | { |
416 | // Read the high bits from the remote process' memory |
417 | DWORD highBits; |
418 | HRESULT hr = m_pFrame->GetProcess()->SafeReadStruct(m_memAddr, &highBits); |
419 | IfFailThrow(hr); |
420 | |
421 | |
422 | // and the low bits from a register |
423 | UINT_PTR* lowBitsAddr = m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber); |
424 | PREFIX_ASSUME(lowBitsAddr != NULL); |
425 | |
426 | _ASSERTE(sizeof(*lowBitsAddr)+sizeof(highBits) == valueOutBuffer.Size()); |
427 | |
428 | memcpy(valueOutBuffer.StartAddress(), lowBitsAddr, sizeof(*lowBitsAddr)); |
429 | memcpy((BYTE *)valueOutBuffer.StartAddress() + sizeof(*lowBitsAddr), &highBits, sizeof(highBits)); |
430 | |
431 | } // MemRegValueHome::GetEnregisteredValue |
432 | |
433 | |
434 | // ---------------------------------------------------------------------------- |
435 | // FloatRegValueHome member function implementations |
436 | // ---------------------------------------------------------------------------- |
437 | |
438 | // initialize an instance of RemoteAddress for use in an IPC event buffer with values from this |
439 | // instance of a derived class of EnregisteredValueHome (see EnregisteredValueHome::CopyToIPCEType for full |
440 | // header comment) |
441 | void FloatRegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) |
442 | { |
443 | pRegAddr->kind = RAK_FLOAT; |
444 | pRegAddr->reg1Addr = NULL; |
445 | pRegAddr->floatIndex = m_floatIndex; |
446 | } // FloatRegValueHome::CopyToIPCEType |
447 | |
448 | // FloatValueHome::SetEnregisteredValue |
449 | // set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue |
450 | // for full header comment) |
451 | void FloatRegValueHome::SetEnregisteredValue(MemoryRange newValue, |
452 | DT_CONTEXT * pContext, |
453 | bool fIsSigned) |
454 | { |
455 | // TODO: : implement CordbValue::SetEnregisteredValue for RAK_FLOAT |
456 | #if defined(DBG_TARGET_AMD64) |
457 | PORTABILITY_ASSERT("NYI: SetEnregisteredValue (divalue.cpp): RAK_FLOAT for AMD64" ); |
458 | #endif // DBG_TARGET_AMD64 |
459 | |
460 | _ASSERTE((newValue.Size() == 4) || (newValue.Size() == 8)); |
461 | |
462 | // Convert the input to a double. |
463 | double newVal = 0.0; |
464 | |
465 | memcpy(&newVal, newValue.StartAddress(), newValue.Size()); |
466 | |
467 | #if defined(DBG_TARGET_X86) |
468 | |
469 | // This is unfortunately non-portable. Luckily we can live with this for now since we only support |
470 | // Win/X86 debugging a Mac/X86 platform. |
471 | |
472 | #if !defined(_TARGET_X86_) |
473 | #error Unsupported target platform |
474 | #endif // !_TARGET_X86_ |
475 | |
476 | // What a pain, on X86 take the floating |
477 | // point state in the context and make it our current FP |
478 | // state, set the value into the current FP state, then |
479 | // save out the FP state into the context again and |
480 | // restore our original state. |
481 | DT_FLOATING_SAVE_AREA currentFPUState; |
482 | |
483 | #ifdef _MSC_VER |
484 | __asm fnsave currentFPUState // save the current FPU state. |
485 | #else |
486 | __asm__ __volatile__ |
487 | ( |
488 | " fnsave %0\n" \ |
489 | : "=m" (currentFPUState) |
490 | ); |
491 | #endif |
492 | |
493 | // Copy the state out of the context. |
494 | DT_FLOATING_SAVE_AREA floatarea = pContext->FloatSave; |
495 | floatarea.StatusWord &= 0xFF00; // remove any error codes. |
496 | floatarea.ControlWord |= 0x3F; // mask all exceptions. |
497 | |
498 | #ifdef _MSC_VER |
499 | __asm |
500 | { |
501 | fninit |
502 | frstor floatarea ;; reload the threads FPU state. |
503 | } |
504 | #else |
505 | __asm__ |
506 | ( |
507 | " fninit\n" \ |
508 | " frstor %0\n" \ |
509 | : /* no outputs */ |
510 | : "m" (floatarea) |
511 | ); |
512 | #endif |
513 | |
514 | double td; // temp double |
515 | double popArea[DebuggerIPCE_FloatCount]; |
516 | |
517 | // Pop off until we reach the value we want to change. |
518 | DWORD i = 0; |
519 | |
520 | while (i <= m_floatIndex) |
521 | { |
522 | __asm fstp td |
523 | popArea[i++] = td; |
524 | } |
525 | |
526 | __asm fld newVal; // push on the new value. |
527 | |
528 | // Push any values that we popled off back onto the stack, |
529 | // _except_ the last one, which was the one we changed. |
530 | i--; |
531 | |
532 | while (i > 0) |
533 | { |
534 | td = popArea[--i]; |
535 | __asm fld td |
536 | } |
537 | |
538 | // Save out the modified float area. |
539 | #ifdef _MSC_VER |
540 | __asm fnsave floatarea |
541 | #else |
542 | __asm__ __volatile__ |
543 | ( |
544 | " fnsave %0\n" \ |
545 | : "=m" (floatarea) |
546 | ); |
547 | #endif |
548 | |
549 | // Put it into the context. |
550 | pContext->FloatSave= floatarea; |
551 | |
552 | // Restore our FPU state |
553 | #ifdef _MSC_VER |
554 | __asm |
555 | { |
556 | fninit |
557 | frstor currentFPUState ;; restore our saved FPU state. |
558 | } |
559 | #else |
560 | __asm__ |
561 | ( |
562 | " fninit\n" \ |
563 | " frstor %0\n" \ |
564 | : /* no outputs */ |
565 | : "m" (currentFPUState) |
566 | ); |
567 | #endif |
568 | #endif // DBG_TARGET_X86 |
569 | |
570 | // update the thread's floating point stack |
571 | void * valueAddress = (void *) &(m_pFrame->m_pThread->m_floatValues[m_floatIndex]); |
572 | memcpy(valueAddress, newValue.StartAddress(), newValue.Size()); |
573 | } // FloatValueHome::SetEnregisteredValue |
574 | |
575 | // FloatRegValueHome::GetEnregisteredValue |
576 | // Throws E_NOTIMPL for attempts to get an enregistered value for a float register |
577 | void FloatRegValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) |
578 | { |
579 | _ASSERTE(!"invalid variable home" ); |
580 | ThrowHR(E_NOTIMPL); |
581 | } // FloatRegValueHome::GetEnregisteredValue |
582 | |
583 | |
584 | // ============================================================================ |
585 | // RemoteValueHome implementation |
586 | // ============================================================================ |
587 | |
588 | // constructor |
589 | // Arguments: |
590 | // input: pProcess - the process to which the value belongs |
591 | // remoteValue - a buffer with the target address of the value and its size |
592 | // Note: It's possible a particular instance of CordbGenericValue may have neither a remote address nor a |
593 | // register address--FuncEval makes empty GenericValues for literals but for those, we will make a |
594 | // RegisterValueHome,so we can assert that we have a non-null remote address here |
595 | RemoteValueHome::RemoteValueHome(CordbProcess * pProcess, TargetBuffer remoteValue): |
596 | ValueHome(pProcess), |
597 | m_remoteValue(remoteValue) |
598 | { |
599 | _ASSERTE(remoteValue.pAddress != NULL); |
600 | } // RemoteValueHome::RemoteValueHome |
601 | |
602 | // Gets a value and returns it in dest |
603 | // virtual |
604 | void RemoteValueHome::GetValue(MemoryRange dest) |
605 | { |
606 | _ASSERTE(dest.Size() == m_remoteValue.cbSize); |
607 | _ASSERTE((!m_remoteValue.IsEmpty()) && (dest.StartAddress() != NULL)); |
608 | m_pProcess->SafeReadBuffer(m_remoteValue, (BYTE *)dest.StartAddress()); |
609 | } // RemoteValueHome::GetValue |
610 | |
611 | // Sets a location to the value provided in src |
612 | // virtual |
613 | void RemoteValueHome::SetValue(MemoryRange src, CordbType * pType) |
614 | { |
615 | _ASSERTE(!m_remoteValue.IsEmpty()); |
616 | _ASSERTE(src.Size() == m_remoteValue.cbSize); |
617 | _ASSERTE(src.StartAddress() != NULL); |
618 | m_pProcess->SafeWriteBuffer(m_remoteValue, (BYTE *)src.StartAddress()); |
619 | } // RemoteValueHome::SetValue |
620 | |
621 | // creates an ICDValue for a field or array element or for the value type of a boxed object |
622 | // virtual |
623 | void RemoteValueHome::CreateInternalValue(CordbType * pType, |
624 | SIZE_T offset, |
625 | void * localAddress, |
626 | ULONG32 size, |
627 | ICorDebugValue ** ppValue) |
628 | { |
629 | // If we're creating an ICDValue for a field added with EnC, the local address will be null, since the field |
630 | // will not be included with the local cached copy of the ICDObjectValue to which the field belongs. |
631 | // This means we need to compute the size for the type of the field, and then determine whether this |
632 | // should also be the size for the localValue we pass to CreateValueByType. The only way we can tell if this |
633 | // is an EnC added field is if the local address is NULL. |
634 | ULONG32 localSize = localAddress != NULL ? size : 0; |
635 | |
636 | CordbAppDomain * pAppdomain = pType->GetAppDomain(); |
637 | |
638 | CordbValue::CreateValueByType(pAppdomain, |
639 | pType, |
640 | kUnboxed, |
641 | TargetBuffer(m_remoteValue.pAddress + offset, size), |
642 | MemoryRange(localAddress, localSize), |
643 | NULL, // remote reg |
644 | ppValue); // throws |
645 | } // RemoteValueHome::CreateInternalValue |
646 | |
647 | // Gets the value of a field or element of an existing ICDValue instance and returns it in dest |
648 | void RemoteValueHome::GetInternalValue(MemoryRange dest, SIZE_T offset) |
649 | { |
650 | _ASSERTE((!m_remoteValue.IsEmpty()) && (dest.StartAddress() != NULL)); |
651 | |
652 | m_pProcess->SafeReadBuffer(TargetBuffer(m_remoteValue.pAddress + offset, (ULONG)dest.Size()), |
653 | (BYTE *)dest.StartAddress()); |
654 | } // RemoteValueHome::GetInternalValue |
655 | |
656 | // copies the register information from this to a RemoteAddress instance |
657 | // virtual |
658 | void RemoteValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) |
659 | { |
660 | pRegAddr->kind = RAK_NONE; |
661 | } // RegisterValueHome::CopyToIPCEType |
662 | |
663 | |
664 | // ============================================================================ |
665 | // RegisterValueHome implementation |
666 | // ============================================================================ |
667 | |
668 | // constructor |
669 | // Arguments: |
670 | // input: pProcess - process for this value |
671 | // ppRemoteRegAddr - enregistered value information |
672 | // |
673 | RegisterValueHome::RegisterValueHome(CordbProcess * pProcess, |
674 | EnregisteredValueHomeHolder * ppRemoteRegAddr): |
675 | ValueHome(pProcess) |
676 | { |
677 | EnregisteredValueHome * pRemoteRegAddr = ppRemoteRegAddr == NULL ? NULL : ppRemoteRegAddr->GetValue(); |
678 | // in the general case, we should have either a remote address or a register address, but FuncEval makes |
679 | // empty GenericValues for literals, so it's possible that we have neither address |
680 | |
681 | if (pRemoteRegAddr != NULL) |
682 | { |
683 | m_pRemoteRegAddr = pRemoteRegAddr; |
684 | // be sure not to delete the remote register information on exit |
685 | ppRemoteRegAddr->SuppressRelease(); |
686 | } |
687 | else |
688 | { |
689 | m_pRemoteRegAddr = NULL; |
690 | } |
691 | } // RegisterValueHome::RegisterValueHome |
692 | |
693 | // clean up resources as necessary |
694 | void RegisterValueHome::Clear() |
695 | { |
696 | if (m_pRemoteRegAddr != NULL) |
697 | { |
698 | delete m_pRemoteRegAddr; |
699 | m_pRemoteRegAddr = NULL; |
700 | } |
701 | } // RegisterValueHome::Clear |
702 | |
703 | // Gets a value and returns it in dest |
704 | // virtual |
705 | void RegisterValueHome::GetValue(MemoryRange dest) |
706 | { |
707 | // FuncEval makes empty CordbGenericValue instances for literals, which will have a RegisterValueHome, |
708 | // but we should not be calling this in that case; we should be able to assert that the register |
709 | // address isn't NULL |
710 | _ASSERTE(m_pRemoteRegAddr != NULL); |
711 | m_pRemoteRegAddr->GetEnregisteredValue(dest); // throws |
712 | } // RegisterValueHome::GetValue |
713 | |
714 | // Sets a location to the value provided in src |
715 | void RegisterValueHome::SetValue(MemoryRange src, CordbType * pType) |
716 | { |
717 | SetEnregisteredValue(src, IsSigned(pType->m_elementType)); // throws |
718 | } // RegisterValueHome::SetValue |
719 | |
720 | // creates an ICDValue for a field or array element or for the value type of a boxed object |
721 | // virtual |
722 | void RegisterValueHome::CreateInternalValue(CordbType * pType, |
723 | SIZE_T offset, |
724 | void * localAddress, |
725 | ULONG32 size, |
726 | ICorDebugValue ** ppValue) |
727 | { |
728 | TargetBuffer remoteValue(PTR_TO_CORDB_ADDRESS((void *)NULL),0); |
729 | EnregisteredValueHomeHolder pRemoteReg(NULL); |
730 | |
731 | _ASSERTE(m_pRemoteRegAddr != NULL); |
732 | // Remote register address is the same as the parent.... |
733 | /* |
734 | * <TODO> |
735 | * nickbe 10/17/2002 07:31:53 |
736 | * If this object consists of two register-sized fields, e.g. |
737 | * struct Point |
738 | * { |
739 | * int x; |
740 | * int y; |
741 | * }; |
742 | * then the variable home of this object is not necessarily the variable |
743 | * home for member data within this object. For example, if we have |
744 | * Point p; |
745 | * and p.x is in a register, while p.y is in memory, then clearly the |
746 | * home of p (RAK_REGMEM) is not the same as the home of p.x (RAK_MEM). |
747 | * |
748 | * Currently the JIT does not split compound objects in this way. It |
749 | * will only split an object that has exactly one field that is twice |
750 | * the size of the register |
751 | * </TODO> |
752 | */ |
753 | _ASSERTE(offset == 0); |
754 | pRemoteReg.Assign(m_pRemoteRegAddr->Clone()); |
755 | |
756 | EnregisteredValueHomeHolder * pRegHolder = pRemoteReg.GetAddr(); |
757 | |
758 | // create a value for the member field. |
759 | CordbValue::CreateValueByType(pType->GetAppDomain(), |
760 | pType, |
761 | kUnboxed, |
762 | EMPTY_BUFFER, // remote address |
763 | MemoryRange(localAddress, size), |
764 | pRegHolder, |
765 | ppValue); // throws |
766 | } // RegisterValueHome::CreateInternalValue |
767 | |
768 | // Gets the value of a field or element of an existing ICDValue instance and returns it in dest |
769 | // virtual |
770 | void RegisterValueHome::GetInternalValue(MemoryRange dest, SIZE_T offset) |
771 | { |
772 | // currently, we can't have an enregistered value that has more than one field or element, so |
773 | // there's nothing to do here but ASSERT. If the JIT changes what can be enregistered, we'll have |
774 | // work to do here |
775 | _ASSERTE(!"Compound types are not enregistered--we shouldn't be here" ); |
776 | ThrowHR(E_INVALIDARG); |
777 | } // RegisterValueHome::GetInternalValue |
778 | |
779 | |
780 | // copies the register information from this to a RemoteAddress instance |
781 | // virtual |
782 | void RegisterValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) |
783 | { |
784 | if(m_pRemoteRegAddr != NULL) |
785 | { |
786 | m_pRemoteRegAddr->CopyToIPCEType(pRegAddr); |
787 | } |
788 | else |
789 | { |
790 | pRegAddr->kind = RAK_NONE; |
791 | } |
792 | } // RegisterValueHome::CopyToIPCEType |
793 | |
794 | // sets a remote enregistered location to a new value |
795 | // Arguments: |
796 | // input: src - contains the new value |
797 | // fIsSigned - indicates whether the new value is signed (needed for proper extension |
798 | // Return value: S_OK on success or CORDBG_E_SET_VALUE_NOT_ALLOWED_ON_NONLEAF_FRAME, CORDBG_E_CONTEXT_UNVAILABLE, |
799 | // or HRESULT values from writing process memory |
800 | void RegisterValueHome::SetEnregisteredValue(MemoryRange src, bool fIsSigned) |
801 | { |
802 | _ASSERTE(m_pRemoteRegAddr != NULL); |
803 | // Get the thread's context so we can update it. |
804 | DT_CONTEXT * cTemp; |
805 | const CordbNativeFrame * frame = m_pRemoteRegAddr->GetFrame(); |
806 | |
807 | // Can't set an enregistered value unless the frame the value was |
808 | // from is also the current leaf frame. This is because we don't |
809 | // track where we get the registers from every frame from. |
810 | |
811 | if (!frame->IsLeafFrame()) |
812 | { |
813 | ThrowHR(CORDBG_E_SET_VALUE_NOT_ALLOWED_ON_NONLEAF_FRAME); |
814 | } |
815 | |
816 | HRESULT hr = S_OK; |
817 | EX_TRY |
818 | { |
819 | // This may throw, in which case we want to return our own HRESULT. |
820 | hr = frame->m_pThread->GetManagedContext(&cTemp); |
821 | } |
822 | EX_CATCH_HRESULT(hr); |
823 | if (FAILED(hr)) |
824 | { |
825 | // If we failed to get the context, then we must not be in a leaf frame. |
826 | ThrowHR(CORDBG_E_SET_VALUE_NOT_ALLOWED_ON_NONLEAF_FRAME); |
827 | } |
828 | |
829 | // Its important to copy this context that we're given a ptr to. |
830 | DT_CONTEXT c; |
831 | c = *cTemp; |
832 | |
833 | m_pRemoteRegAddr->SetEnregisteredValue(src, &c, fIsSigned); |
834 | |
835 | // Set the thread's modified context. |
836 | IfFailThrow(frame->m_pThread->SetManagedContext(&c)); |
837 | } // RegisterValueHome::SetEnregisteredValue |
838 | |
839 | |
840 | // Get an enregistered value from the register display of the native frame |
841 | // Arguments: |
842 | // output: dest - buffer will hold the register value |
843 | // Note: Throws E_NOTIMPL for attempts to get an enregistered value for a float register |
844 | // or for 64-bit platforms |
845 | void RegisterValueHome::GetEnregisteredValue(MemoryRange dest) |
846 | { |
847 | #if !defined(DBG_TARGET_X86) |
848 | _ASSERTE(!"@TODO IA64/AMD64 -- Not Yet Implemented" ); |
849 | ThrowHR(E_NOTIMPL); |
850 | #else // DBG_TARGET_X86 |
851 | _ASSERTE(m_pRemoteRegAddr != NULL); |
852 | |
853 | m_pRemoteRegAddr->GetEnregisteredValue(dest); // throws |
854 | #endif // !DBG_TARGET_X86 |
855 | } // RegisterValueHome::GetEnregisteredValue |
856 | |
857 | // Is this a signed type or unsigned type? |
858 | // Useful to known when we need to sign-extend. |
859 | bool RegisterValueHome::IsSigned(CorElementType elementType) |
860 | { |
861 | switch (elementType) |
862 | { |
863 | case ELEMENT_TYPE_I1: |
864 | case ELEMENT_TYPE_I2: |
865 | case ELEMENT_TYPE_I4: |
866 | case ELEMENT_TYPE_I8: |
867 | case ELEMENT_TYPE_I: |
868 | return true; |
869 | |
870 | default: |
871 | return false; |
872 | } |
873 | } // RegisterValueHome::IsSigned |
874 | |
875 | // ============================================================================ |
876 | // HandleValueHome implementation |
877 | // ============================================================================ |
878 | |
879 | // |
880 | CORDB_ADDRESS HandleValueHome::GetAddress() |
881 | { |
882 | _ASSERTE((m_pProcess != NULL) && !m_vmObjectHandle.IsNull()); |
883 | CORDB_ADDRESS handle = PTR_TO_CORDB_ADDRESS((void *)NULL); |
884 | EX_TRY |
885 | { |
886 | handle = m_pProcess->GetDAC()->GetHandleAddressFromVmHandle(m_vmObjectHandle); |
887 | } |
888 | EX_CATCH |
889 | { |
890 | } |
891 | EX_END_CATCH(SwallowAllExceptions); |
892 | return handle; |
893 | } |
894 | |
895 | // Gets a value and returns it in dest |
896 | // virtual |
897 | void HandleValueHome::GetValue(MemoryRange dest) |
898 | { |
899 | _ASSERTE((m_pProcess != NULL) && !m_vmObjectHandle.IsNull()); |
900 | CORDB_ADDRESS objPtr = PTR_TO_CORDB_ADDRESS((void *)NULL); |
901 | objPtr = m_pProcess->GetDAC()->GetHandleAddressFromVmHandle(m_vmObjectHandle); |
902 | |
903 | _ASSERTE(dest.Size() <= sizeof(void *)); |
904 | _ASSERTE(dest.StartAddress() != NULL); |
905 | _ASSERTE(objPtr != NULL); |
906 | m_pProcess->SafeReadBuffer(TargetBuffer(objPtr, sizeof(void *)), (BYTE *)dest.StartAddress()); |
907 | } // HandleValueHome::GetValue |
908 | |
909 | // Sets a location to the value provided in src |
910 | // virtual |
911 | void HandleValueHome::SetValue(MemoryRange src, CordbType * pType) |
912 | { |
913 | _ASSERTE(!m_vmObjectHandle.IsNull()); |
914 | |
915 | DebuggerIPCEvent event; |
916 | |
917 | m_pProcess->InitIPCEvent(&event, DB_IPCE_SET_REFERENCE, true, VMPTR_AppDomain::NullPtr()); |
918 | |
919 | event.SetReference.objectRefAddress = NULL; |
920 | event.SetReference.vmObjectHandle = m_vmObjectHandle; |
921 | event.SetReference.newReference = *((void **)src.StartAddress()); |
922 | |
923 | // Note: two-way event here... |
924 | IfFailThrow(m_pProcess->SendIPCEvent(&event, sizeof(DebuggerIPCEvent))); |
925 | |
926 | _ASSERTE(event.type == DB_IPCE_SET_REFERENCE_RESULT); |
927 | |
928 | IfFailThrow(event.hr); |
929 | } // HandleValueHome::SetValue |
930 | |
931 | // creates an ICDValue for a field or array element or for the value type of a boxed object |
932 | // virtual |
933 | void HandleValueHome::CreateInternalValue(CordbType * pType, |
934 | SIZE_T offset, |
935 | void * localAddress, |
936 | ULONG32 size, |
937 | ICorDebugValue ** ppValue) |
938 | { |
939 | _ASSERTE(!"References don't have sub-objects--we shouldn't be here" ); |
940 | ThrowHR(E_INVALIDARG); |
941 | |
942 | } // HandleValueHome::CreateInternalValue |
943 | |
944 | // Gets the value of a field or element of an existing ICDValue instance and returns it in dest |
945 | // virtual |
946 | void HandleValueHome::GetInternalValue(MemoryRange dest, SIZE_T offset) |
947 | { |
948 | _ASSERTE(!"References don't have sub-objects--we shouldn't be here" ); |
949 | ThrowHR(E_INVALIDARG); |
950 | } // HandleValueHome::GetInternalValue |
951 | |
952 | // copies the register information from this to a RemoteAddress instance |
953 | // virtual |
954 | void HandleValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) |
955 | { |
956 | pRegAddr->kind = RAK_NONE; |
957 | } // HandleValueHome::CopyToIPCEType |
958 | |
959 | // ============================================================================ |
960 | // VCRemoteValueHome implementation |
961 | // ============================================================================ |
962 | |
963 | // Sets a location to the value provided in src |
964 | // Arguments: |
965 | // input: src - buffer containing the new value to be set--memory for this buffer is owned by the caller |
966 | // pType - type information for the value |
967 | // output: none, but sets the value on success |
968 | // Note: Throws CORDBG_E_CLASS_NOT_LOADED or errors from WriteProcessMemory or |
969 | // GetRemoteBuffer on failure |
970 | void VCRemoteValueHome::SetValue(MemoryRange src, CordbType * pType) |
971 | { |
972 | _ASSERTE(!m_remoteValue.IsEmpty()); |
973 | |
974 | // send a Set Value Class message to the right side with the address of this value class, the address of |
975 | // the new data, and the class of the value class that we're setting. |
976 | DebuggerIPCEvent event; |
977 | |
978 | // First, we have to make room on the Left Side for the new data for the value class. We allocate |
979 | // memory on the Left Side for this, then write the new data across. The Set Value Class message will |
980 | // free the buffer when its done. |
981 | void *buffer = NULL; |
982 | IfFailThrow(m_pProcess->GetAndWriteRemoteBuffer(NULL, |
983 | m_remoteValue.cbSize, |
984 | CORDB_ADDRESS_TO_PTR(src.StartAddress()), |
985 | &buffer)); |
986 | |
987 | // Finally, send over the Set Value Class message. |
988 | m_pProcess->InitIPCEvent(&event, DB_IPCE_SET_VALUE_CLASS, true, VMPTR_AppDomain::NullPtr()); |
989 | event.SetValueClass.oldData = CORDB_ADDRESS_TO_PTR(m_remoteValue.pAddress); |
990 | event.SetValueClass.newData = buffer; |
991 | IfFailThrow(pType->TypeToBasicTypeData(&event.SetValueClass.type)); |
992 | |
993 | // Note: two-way event here... |
994 | IfFailThrow(m_pProcess->SendIPCEvent(&event, sizeof(DebuggerIPCEvent))); |
995 | |
996 | _ASSERTE(event.type == DB_IPCE_SET_VALUE_CLASS_RESULT); |
997 | |
998 | IfFailThrow(event.hr); |
999 | } // VCRemoteValueHome::SetValue |
1000 | |
1001 | |
1002 | // ============================================================================ |
1003 | // RefRemoteValueHome implementation |
1004 | // ============================================================================ |
1005 | |
1006 | // constructor |
1007 | // Arguments: |
1008 | // input: pProcess - process for this value |
1009 | // remoteValue - remote location information |
1010 | // vmObjHandle - object handle |
1011 | RefRemoteValueHome ::RefRemoteValueHome (CordbProcess * pProcess, |
1012 | TargetBuffer remoteValue): |
1013 | RemoteValueHome(pProcess, remoteValue) |
1014 | { |
1015 | // caller supplies remoteValue, to work w/ Func-eval. |
1016 | _ASSERTE((!remoteValue.IsEmpty()) && (remoteValue.cbSize == sizeof (void *))); |
1017 | |
1018 | } // RefRemoteValueHome::RefRemoteValueHome |
1019 | |
1020 | // Sets a location to the value provided in src |
1021 | // Arguments: |
1022 | // input: src - buffer containing the new value to be set--memory for this buffer is owned by the caller |
1023 | // pType - type information for the value |
1024 | // output: none, but sets the value on success |
1025 | // Return Value: S_OK on success or CORDBG_E_CLASS_NOT_LOADED or errors from WriteProcessMemory or |
1026 | // GetRemoteBuffer on failure |
1027 | void RefRemoteValueHome::SetValue(MemoryRange src, CordbType * pType) |
1028 | { |
1029 | // We had better have a remote address. |
1030 | _ASSERTE(!m_remoteValue.IsEmpty()); |
1031 | |
1032 | // send a Set Reference message to the right side with the address of this reference and whether or not |
1033 | // the reference points to a handle. |
1034 | |
1035 | // If it's a reference but not a GC root then just we can just treat it like raw data (like a DWORD). |
1036 | // This would include things like "int*", and E_T_FNPTR. If it is a GC root, then we need to go over to |
1037 | // the LS to update the WriteBarrier. |
1038 | if ((pType != NULL) && !pType->IsGCRoot()) |
1039 | { |
1040 | m_pProcess->SafeWriteBuffer(m_remoteValue, (BYTE *)src.StartAddress()); |
1041 | } |
1042 | else |
1043 | { |
1044 | DebuggerIPCEvent event; |
1045 | |
1046 | m_pProcess->InitIPCEvent(&event, DB_IPCE_SET_REFERENCE, true, VMPTR_AppDomain::NullPtr()); |
1047 | |
1048 | event.SetReference.objectRefAddress = CORDB_ADDRESS_TO_PTR(m_remoteValue.pAddress); |
1049 | event.SetReference.vmObjectHandle = VMPTR_OBJECTHANDLE::NullPtr(); |
1050 | event.SetReference.newReference = *((void **)src.StartAddress()); |
1051 | |
1052 | // Note: two-way event here... |
1053 | IfFailThrow(m_pProcess->SendIPCEvent(&event, sizeof(DebuggerIPCEvent))); |
1054 | |
1055 | _ASSERTE(event.type == DB_IPCE_SET_REFERENCE_RESULT); |
1056 | |
1057 | IfFailThrow(event.hr); |
1058 | } |
1059 | } // RefRemoteValueHome::SetValue |
1060 | |
1061 | // ============================================================================ |
1062 | // RefValueHome implementation |
1063 | // ============================================================================ |
1064 | |
1065 | // constructor |
1066 | // Only one of the location types should be non-NULL, but we pass all of them to the |
1067 | // constructor so we can instantiate m_pHome correctly. |
1068 | // Arguments: |
1069 | // input: pProcess - process to which the value belongs |
1070 | // remoteValue - a target location holding the object reference |
1071 | // ppRemoteRegAddr - information about the register that holds the object ref |
1072 | // vmObjHandle - an object handle that holds the object ref |
1073 | RefValueHome::RefValueHome(CordbProcess * pProcess, |
1074 | TargetBuffer remoteValue, |
1075 | EnregisteredValueHomeHolder * ppRemoteRegAddr, |
1076 | VMPTR_OBJECTHANDLE vmObjHandle) |
1077 | { |
1078 | if (!remoteValue.IsEmpty()) |
1079 | { |
1080 | NewHolder<ValueHome> pHome(new RefRemoteValueHome(pProcess, remoteValue)); |
1081 | m_fNullObjHandle = true; |
1082 | } |
1083 | else if (!vmObjHandle.IsNull()) |
1084 | { |
1085 | NewHolder<ValueHome> pHome(new HandleValueHome(pProcess, vmObjHandle)); |
1086 | m_fNullObjHandle = false; |
1087 | } |
1088 | else |
1089 | { |
1090 | NewHolder<ValueHome> pHome(new RegisterValueHome(pProcess, ppRemoteRegAddr)); |
1091 | m_fNullObjHandle = true; |
1092 | } |
1093 | |
1094 | |
1095 | } // RefValueHome::RefValueHome |
1096 | |
1097 | |