xref: /haiku/src/kits/debugger/value/ValueWriter.cpp (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
1 /*
2  * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2013-2015, Rene Gollent, rene@gollent.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "ValueWriter.h"
9 
10 #include "Architecture.h"
11 #include "BitBuffer.h"
12 #include "CpuState.h"
13 #include "DebuggerInterface.h"
14 #include "Register.h"
15 #include "TeamMemory.h"
16 #include "Tracing.h"
17 #include "ValueLocation.h"
18 
19 
20 ValueWriter::ValueWriter(Architecture* architecture,
21 	DebuggerInterface* interface, CpuState* cpuState, thread_id targetThread)
22 	:
23 	fArchitecture(architecture),
24 	fDebuggerInterface(interface),
25 	fCpuState(cpuState),
26 	fTargetThread(targetThread)
27 {
28 	fArchitecture->AcquireReference();
29 	fDebuggerInterface->AcquireReference();
30 	if (fCpuState != NULL)
31 		fCpuState->AcquireReference();
32 }
33 
34 
35 ValueWriter::~ValueWriter()
36 {
37 	fArchitecture->ReleaseReference();
38 	fDebuggerInterface->ReleaseReference();
39 	if (fCpuState != NULL)
40 		fCpuState->ReleaseReference();
41 }
42 
43 
44 status_t
45 ValueWriter::WriteValue(ValueLocation* location, BVariant& value)
46 {
47 	if (!location->IsWritable())
48 		return B_BAD_VALUE;
49 
50 	int32 count = location->CountPieces();
51 	if (fCpuState == NULL) {
52 		for (int32 i = 0; i < count; i++) {
53 			const ValuePieceLocation piece = location->PieceAt(i);
54 			if (piece.type == VALUE_PIECE_LOCATION_REGISTER) {
55 				TRACE_LOCALS("  -> asked to write value with register piece, "
56 					"but no CPU state to write to.\n");
57 				return B_UNSUPPORTED;
58 			}
59 		}
60 	}
61 
62 	bool cpuStateWriteNeeded = false;
63 	size_t byteOffset = 0;
64 	bool bigEndian = fArchitecture->IsBigEndian();
65 	const Register* registers = fArchitecture->Registers();
66 	for (int32 i = 0; i < count; i++) {
67 		ValuePieceLocation piece = location->PieceAt(
68 			bigEndian ? i : count - i - 1);
69 		uint32 bytesToWrite = piece.size;
70 
71 		uint8* targetData = (uint8*)value.Bytes() + byteOffset;
72 
73 		switch (piece.type) {
74 			case VALUE_PIECE_LOCATION_MEMORY:
75 			{
76 				target_addr_t address = piece.address;
77 
78 				TRACE_LOCALS("  piece %" B_PRId32 ": memory address: %#"
79 					B_PRIx64 ", bits: %" B_PRIu32 "\n", i, address,
80 					bytesToWrite * 8);
81 
82 				ssize_t bytesWritten = fDebuggerInterface->WriteMemory(address,
83 					targetData, bytesToWrite);
84 
85 				if (bytesWritten < 0)
86 					return bytesWritten;
87 				if ((uint32)bytesWritten != bytesToWrite)
88 					return B_BAD_ADDRESS;
89 
90 				break;
91 			}
92 			case VALUE_PIECE_LOCATION_REGISTER:
93 			{
94 				TRACE_LOCALS("  piece %" B_PRId32 ": register: %" B_PRIu32
95 					", bits: %" B_PRIu64 "\n", i, piece.reg, piece.bitSize);
96 
97 				const Register* target = registers + piece.reg;
98 				BVariant pieceValue;
99 				switch (bytesToWrite) {
100 					case 1:
101 						pieceValue.SetTo(*(uint8*)targetData);
102 						break;
103 					case 2:
104 						pieceValue.SetTo(*(uint16*)targetData);
105 						break;
106 					case 4:
107 						pieceValue.SetTo(*(uint32*)targetData);
108 						break;
109 					case 8:
110 						pieceValue.SetTo(*(uint64*)targetData);
111 						break;
112 					default:
113 						TRACE_LOCALS("Asked to write unsupported piece size %"
114 							B_PRId32 " to register\n", bytesToWrite);
115 						return B_UNSUPPORTED;
116 				}
117 
118 				if (!fCpuState->SetRegisterValue(target, pieceValue))
119 					return B_NO_MEMORY;
120 
121 				cpuStateWriteNeeded = true;
122 				break;
123 			}
124 			default:
125 				return B_UNSUPPORTED;
126 		}
127 
128 		byteOffset += bytesToWrite;
129 	}
130 
131 	if (cpuStateWriteNeeded)
132 		return fDebuggerInterface->SetCpuState(fTargetThread, fCpuState);
133 
134 	return B_OK;
135 }
136