* 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;
}