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
20ValueWriter::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
35ValueWriter::~ValueWriter()
36{
37	fArchitecture->ReleaseReference();
38	fDebuggerInterface->ReleaseReference();
39	if (fCpuState != NULL)
40		fCpuState->ReleaseReference();
41}
42
43
44status_t
45ValueWriter::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