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
17EnregisteredValueHome::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)
30void 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
48void 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)
187void 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)
239void 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)
256void 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)
270void 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)
294void 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)
317void 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)
329void 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)
353void 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)
379void 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)
391void 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)
414void 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)
441void 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)
451void 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
577void 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
604void 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
613void 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
623void 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
648void 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
658void 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//
673RegisterValueHome::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
694void 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
705void 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
715void 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
722void 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
770void 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
782void 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
800void 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
845void 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.
859bool 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//
880CORDB_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
897void 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
911void 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
933void 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
946void 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
954void 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
970void 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
1011RefRemoteValueHome ::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
1027void 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
1073RefValueHome::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