⛏️ index : haiku.git

/*
 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Copyright 2013-2015, Rene Gollent, rene@gollent.com.
 * Distributed under the terms of the MIT License.
 */


#include "ValueWriter.h"

#include "Architecture.h"
#include "BitBuffer.h"
#include "CpuState.h"
#include "DebuggerInterface.h"
#include "Register.h"
#include "TeamMemory.h"
#include "Tracing.h"
#include "ValueLocation.h"


ValueWriter::ValueWriter(Architecture* architecture,
	DebuggerInterface* interface, CpuState* cpuState, thread_id targetThread)
	:
	fArchitecture(architecture),
	fDebuggerInterface(interface),
	fCpuState(cpuState),
	fTargetThread(targetThread)
{
	fArchitecture->AcquireReference();
	fDebuggerInterface->AcquireReference();
	if (fCpuState != NULL)
		fCpuState->AcquireReference();
}


ValueWriter::~ValueWriter()
{
	fArchitecture->ReleaseReference();
	fDebuggerInterface->ReleaseReference();
	if (fCpuState != NULL)
		fCpuState->ReleaseReference();
}


status_t
ValueWriter::WriteValue(ValueLocation* location, BVariant& value)
{
	if (!location->IsWritable())
		return B_BAD_VALUE;

	int32 count = location->CountPieces();
	if (fCpuState == NULL) {
		for (int32 i = 0; i < count; i++) {
			const ValuePieceLocation piece = location->PieceAt(i);
			if (piece.type == VALUE_PIECE_LOCATION_REGISTER) {
				TRACE_LOCALS("  -> asked to write value with register piece, "
					"but no CPU state to write to.\n");
				return B_UNSUPPORTED;
			}
		}
	}

	bool cpuStateWriteNeeded = false;
	size_t byteOffset = 0;
	bool bigEndian = fArchitecture->IsBigEndian();
	const Register* registers = fArchitecture->Registers();
	for (int32 i = 0; i < count; i++) {
		ValuePieceLocation piece = location->PieceAt(
			bigEndian ? i : count - i - 1);
		uint32 bytesToWrite = piece.size;

		uint8* targetData = (uint8*)value.Bytes() + byteOffset;

		switch (piece.type) {
			case VALUE_PIECE_LOCATION_MEMORY:
			{
				target_addr_t address = piece.address;

				TRACE_LOCALS("  piece %" B_PRId32 ": memory address: %#"
					B_PRIx64 ", bits: %" B_PRIu32 "\n", i, address,
					bytesToWrite * 8);

				ssize_t bytesWritten = fDebuggerInterface->WriteMemory(address,
					targetData, bytesToWrite);

				if (bytesWritten < 0)
					return bytesWritten;
				if ((uint32)bytesWritten != bytesToWrite)
					return B_BAD_ADDRESS;

				break;
			}
			case VALUE_PIECE_LOCATION_REGISTER:
			{
				TRACE_LOCALS("  piece %" B_PRId32 ": register: %" B_PRIu32
					", bits: %" B_PRIu64 "\n", i, piece.reg, piece.bitSize);

				const Register* target = registers + piece.reg;
				BVariant pieceValue;
				switch (bytesToWrite) {
					case 1:
						pieceValue.SetTo(*(uint8*)targetData);
						break;
					case 2:
						pieceValue.SetTo(*(uint16*)targetData);
						break;
					case 4:
						pieceValue.SetTo(*(uint32*)targetData);
						break;
					case 8:
						pieceValue.SetTo(*(uint64*)targetData);
						break;
					default:
						TRACE_LOCALS("Asked to write unsupported piece size %"
							B_PRId32 " to register\n", bytesToWrite);
						return B_UNSUPPORTED;
				}

				if (!fCpuState->SetRegisterValue(target, pieceValue))
					return B_NO_MEMORY;

				cpuStateWriteNeeded = true;
				break;
			}
			default:
				return B_UNSUPPORTED;
		}

		byteOffset += bytesToWrite;
	}

	if (cpuStateWriteNeeded)
		return fDebuggerInterface->SetCpuState(fTargetThread, fCpuState);

	return B_OK;
}