* 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 "ValueLoader.h"
#include "Architecture.h"
#include "BitBuffer.h"
#include "CpuState.h"
#include "Register.h"
#include "TeamMemory.h"
#include "Tracing.h"
#include "ValueLocation.h"
ValueLoader::ValueLoader(Architecture* architecture, TeamMemory* teamMemory,
CpuState* cpuState)
:
fArchitecture(architecture),
fTeamMemory(teamMemory),
fCpuState(cpuState)
{
fArchitecture->AcquireReference();
fTeamMemory->AcquireReference();
if (fCpuState != NULL)
fCpuState->AcquireReference();
}
ValueLoader::~ValueLoader()
{
fArchitecture->ReleaseReference();
fTeamMemory->ReleaseReference();
if (fCpuState != NULL)
fCpuState->ReleaseReference();
}
status_t
ValueLoader::LoadValue(ValueLocation* location, type_code valueType,
bool shortValueIsFine, BVariant& _value)
{
static const size_t kMaxPieceSize = 16;
uint64 totalBitSize = 0;
int32 count = location->CountPieces();
for (int32 i = 0; i < count; i++) {
ValuePieceLocation piece = location->PieceAt(i);
switch (piece.type) {
case VALUE_PIECE_LOCATION_INVALID:
case VALUE_PIECE_LOCATION_UNKNOWN:
return B_ENTRY_NOT_FOUND;
case VALUE_PIECE_LOCATION_MEMORY:
case VALUE_PIECE_LOCATION_REGISTER:
case VALUE_PIECE_LOCATION_IMPLICIT:
break;
}
if (piece.size > kMaxPieceSize) {
TRACE_LOCALS(" -> overly long piece size (%" B_PRIu64 " bytes)\n",
piece.size);
return B_UNSUPPORTED;
}
totalBitSize += piece.bitSize;
}
TRACE_LOCALS(" -> totalBitSize: %" B_PRIu64 "\n", totalBitSize);
if (totalBitSize == 0) {
TRACE_LOCALS(" -> no size\n");
return B_ENTRY_NOT_FOUND;
}
if (totalBitSize > 64) {
TRACE_LOCALS(" -> longer than 64 bits: unsupported\n");
return B_UNSUPPORTED;
}
uint64 valueBitSize = BVariant::SizeOfType(valueType) * 8;
if (!shortValueIsFine && totalBitSize < valueBitSize) {
TRACE_LOCALS(" -> too short for value type (%" B_PRIu64 " vs. %"
B_PRIu64 " bits)\n", totalBitSize, valueBitSize);
return B_BAD_VALUE;
}
BitBuffer valueBuffer;
if (totalBitSize < valueBitSize)
valueBuffer.AddZeroBits(valueBitSize - totalBitSize);
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 bytesToRead = piece.size;
uint32 bitSize = piece.bitSize;
uint8 bitOffset = piece.bitOffset;
switch (piece.type) {
case VALUE_PIECE_LOCATION_INVALID:
case VALUE_PIECE_LOCATION_UNKNOWN:
return B_ENTRY_NOT_FOUND;
case VALUE_PIECE_LOCATION_MEMORY:
case VALUE_PIECE_LOCATION_IMPLICIT:
{
target_addr_t address = piece.address;
if (piece.type == VALUE_PIECE_LOCATION_MEMORY) {
TRACE_LOCALS(" piece %" B_PRId32 ": memory address: %#"
B_PRIx64 ", bits: %" B_PRIu32 "\n", i, address,
bitSize);
} else {
TRACE_LOCALS(" piece %" B_PRId32 ": implicit value, "
"bits: %" B_PRIu32 "\n", i, bitSize);
}
uint8 pieceBuffer[kMaxPieceSize];
ssize_t bytesRead;
if (piece.type == VALUE_PIECE_LOCATION_MEMORY) {
bytesRead = fTeamMemory->ReadMemory(address,
pieceBuffer, bytesToRead);
} else {
memcpy(pieceBuffer, piece.value, piece.size);
bytesRead = piece.size;
}
if (bytesRead < 0)
return bytesRead;
if ((uint32)bytesRead != bytesToRead)
return B_BAD_ADDRESS;
TRACE_LOCALS_ONLY(
TRACE_LOCALS(" -> read: ");
for (ssize_t k = 0; k < bytesRead; k++)
TRACE_LOCALS("%02x", pieceBuffer[k]);
TRACE_LOCALS("\n");
)
if (!bigEndian) {
for (int32 k = bytesRead / 2 - 1; k >= 0; k--) {
std::swap(pieceBuffer[k],
pieceBuffer[bytesRead - k - 1]);
}
}
valueBuffer.AddBits(pieceBuffer, bitSize, bitOffset);
break;
}
case VALUE_PIECE_LOCATION_REGISTER:
{
TRACE_LOCALS(" piece %" B_PRId32 ": register: %" B_PRIu32
", bits: %" B_PRIu32 "\n", i, piece.reg, bitSize);
if (fCpuState == NULL) {
WARNING("ValueLoader::LoadValue(): register piece, but no "
"CpuState\n");
return B_UNSUPPORTED;
}
BVariant registerValue;
if (!fCpuState->GetRegisterValue(registers + piece.reg,
registerValue)) {
return B_ENTRY_NOT_FOUND;
}
if (registerValue.Size() < bytesToRead)
return B_ENTRY_NOT_FOUND;
if (!bigEndian) {
registerValue.SwapEndianess();
bitOffset = registerValue.Size() * 8 - bitOffset - bitSize;
}
valueBuffer.AddBits(registerValue.Bytes(), bitSize, bitOffset);
break;
}
}
}
if (valueBuffer.BitSize() < valueBitSize)
return B_NO_MEMORY;
BVariant value;
status_t error = value.SetToTypedData(valueBuffer.Bytes(), valueType);
if (error != B_OK) {
TRACE_LOCALS(" -> failed to set typed data: %s\n", strerror(error));
return error;
}
#if B_HOST_IS_LENDIAN
value.SwapEndianess();
#endif
_value = value;
return B_OK;
}
status_t
ValueLoader::LoadRawValue(BVariant& location, size_t bytesToRead, void* _value)
{
ssize_t bytesRead = fTeamMemory->ReadMemory(location.ToUInt64(),
_value, bytesToRead);
if (bytesRead < 0)
return bytesRead;
if ((uint32)bytesRead != bytesToRead)
return B_BAD_ADDRESS;
return B_OK;
}
status_t
ValueLoader::LoadStringValue(BVariant& location, size_t maxSize, BString& _value)
{
static const size_t kMaxStringSize = 255;
return fTeamMemory->ReadMemoryString(location.ToUInt64(),
std::min(maxSize, kMaxStringSize), _value);
}