1/* 2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include "ValueLoader.h" 8 9#include "Architecture.h" 10#include "BitBuffer.h" 11#include "CpuState.h" 12#include "Register.h" 13#include "TeamMemory.h" 14#include "TeamTypeInformation.h" 15#include "Tracing.h" 16#include "TypeLookupConstraints.h" 17#include "ValueLocation.h" 18 19 20ValueLoader::ValueLoader(Architecture* architecture, TeamMemory* teamMemory, 21 TeamTypeInformation* typeInformation, CpuState* cpuState) 22 : 23 fArchitecture(architecture), 24 fTeamMemory(teamMemory), 25 fTypeInformation(typeInformation), 26 fCpuState(cpuState) 27{ 28 fArchitecture->AcquireReference(); 29 fTeamMemory->AcquireReference(); 30 fTypeInformation->AcquireReference(); 31 if (fCpuState != NULL) 32 fCpuState->AcquireReference(); 33} 34 35 36ValueLoader::ValueLoader(const ValueLoader& other) 37 : 38 fArchitecture(other.fArchitecture), 39 fTeamMemory(other.fTeamMemory), 40 fTypeInformation(other.fTypeInformation), 41 fCpuState(other.fCpuState) 42{ 43 fArchitecture->AcquireReference(); 44 fTeamMemory->AcquireReference(); 45 fTypeInformation->AcquireReference(); 46 if (fCpuState != NULL) 47 fCpuState->AcquireReference(); 48} 49 50 51ValueLoader::~ValueLoader() 52{ 53 fArchitecture->ReleaseReference(); 54 fTeamMemory->ReleaseReference(); 55 fTypeInformation->ReleaseReference(); 56 if (fCpuState != NULL) 57 fCpuState->ReleaseReference(); 58} 59 60 61status_t 62ValueLoader::LoadValue(ValueLocation* location, type_code valueType, 63 bool shortValueIsFine, BVariant& _value) 64{ 65 static const size_t kMaxPieceSize = 16; 66 uint64 totalBitSize = 0; 67 int32 count = location->CountPieces(); 68 for (int32 i = 0; i < count; i++) { 69 ValuePieceLocation piece = location->PieceAt(i); 70 switch (piece.type) { 71 case VALUE_PIECE_LOCATION_INVALID: 72 case VALUE_PIECE_LOCATION_UNKNOWN: 73 return B_ENTRY_NOT_FOUND; 74 case VALUE_PIECE_LOCATION_MEMORY: 75 case VALUE_PIECE_LOCATION_REGISTER: 76 break; 77 } 78 79 if (piece.size > kMaxPieceSize) { 80 TRACE_LOCALS(" -> overly long piece size (%" B_PRIu64 " bytes)\n", 81 piece.size); 82 return B_UNSUPPORTED; 83 } 84 85 totalBitSize += piece.bitSize; 86 } 87 88 TRACE_LOCALS(" -> totalBitSize: %" B_PRIu64 "\n", totalBitSize); 89 90 if (totalBitSize == 0) { 91 TRACE_LOCALS(" -> no size\n"); 92 return B_ENTRY_NOT_FOUND; 93 } 94 95 if (totalBitSize > 64) { 96 TRACE_LOCALS(" -> longer than 64 bits: unsupported\n"); 97 return B_UNSUPPORTED; 98 } 99 100 uint64 valueBitSize = BVariant::SizeOfType(valueType) * 8; 101 if (!shortValueIsFine && totalBitSize < valueBitSize) { 102 TRACE_LOCALS(" -> too short for value type (%" B_PRIu64 " vs. %" 103 B_PRIu64 " bits)\n", totalBitSize, valueBitSize); 104 return B_BAD_VALUE; 105 } 106 107 // Load the data. Since the BitBuffer class we're using only supports big 108 // endian bit semantics, we convert all data to big endian before pushing 109 // them to the buffer. For later conversion to BVariant we need to make sure 110 // the final buffer has the size of the value type, so we pad the most 111 // significant bits with zeros. 112 BitBuffer valueBuffer; 113 if (totalBitSize < valueBitSize) 114 valueBuffer.AddZeroBits(valueBitSize - totalBitSize); 115 116 bool bigEndian = fArchitecture->IsBigEndian(); 117 const Register* registers = fArchitecture->Registers(); 118 for (int32 i = 0; i < count; i++) { 119 ValuePieceLocation piece = location->PieceAt( 120 bigEndian ? i : count - i - 1); 121 uint32 bytesToRead = piece.size; 122 uint32 bitSize = piece.bitSize; 123 uint8 bitOffset = piece.bitOffset; 124 125 switch (piece.type) { 126 case VALUE_PIECE_LOCATION_INVALID: 127 case VALUE_PIECE_LOCATION_UNKNOWN: 128 return B_ENTRY_NOT_FOUND; 129 case VALUE_PIECE_LOCATION_MEMORY: 130 { 131 target_addr_t address = piece.address; 132 133 TRACE_LOCALS(" piece %" B_PRId32 ": memory address: %#" 134 B_PRIx64 ", bits: %" B_PRIu32 "\n", i, address, bitSize); 135 136 uint8 pieceBuffer[kMaxPieceSize]; 137 ssize_t bytesRead = fTeamMemory->ReadMemory(address, 138 pieceBuffer, bytesToRead); 139 if (bytesRead < 0) 140 return bytesRead; 141 if ((uint32)bytesRead != bytesToRead) 142 return B_BAD_ADDRESS; 143 144 TRACE_LOCALS_ONLY( 145 TRACE_LOCALS(" -> read: "); 146 for (ssize_t k = 0; k < bytesRead; k++) 147 TRACE_LOCALS("%02x", pieceBuffer[k]); 148 TRACE_LOCALS("\n"); 149 ) 150 151 // convert to big endian 152 if (!bigEndian) { 153 for (int32 k = bytesRead / 2 - 1; k >= 0; k--) { 154 std::swap(pieceBuffer[k], 155 pieceBuffer[bytesRead - k - 1]); 156 } 157 } 158 159 valueBuffer.AddBits(pieceBuffer, bitSize, bitOffset); 160 break; 161 } 162 case VALUE_PIECE_LOCATION_REGISTER: 163 { 164 TRACE_LOCALS(" piece %" B_PRId32 ": register: %" B_PRIu32 165 ", bits: %" B_PRIu32 "\n", i, piece.reg, bitSize); 166 167 if (fCpuState == NULL) { 168 WARNING("ValueLoader::LoadValue(): register piece, but no " 169 "CpuState\n"); 170 return B_UNSUPPORTED; 171 } 172 173 BVariant registerValue; 174 if (!fCpuState->GetRegisterValue(registers + piece.reg, 175 registerValue)) { 176 return B_ENTRY_NOT_FOUND; 177 } 178 if (registerValue.Size() < bytesToRead) 179 return B_ENTRY_NOT_FOUND; 180 181 if (!bigEndian) 182 registerValue.SwapEndianess(); 183 valueBuffer.AddBits(registerValue.Bytes(), bitSize, bitOffset); 184 break; 185 } 186 } 187 } 188 189 // If we don't have enough bits in the buffer apparently adding some failed. 190 if (valueBuffer.BitSize() < valueBitSize) 191 return B_NO_MEMORY; 192 193 // convert the bits into something we can work with 194 BVariant value; 195 status_t error = value.SetToTypedData(valueBuffer.Bytes(), valueType); 196 if (error != B_OK) { 197 TRACE_LOCALS(" -> failed to set typed data: %s\n", strerror(error)); 198 return error; 199 } 200 201 // convert to host endianess 202 #if B_HOST_IS_LENDIAN 203 value.SwapEndianess(); 204 #endif 205 206 _value = value; 207 return B_OK; 208} 209 210 211status_t 212ValueLoader::LoadRawValue(BVariant& location, size_t bytesToRead, void* _value) 213{ 214 ssize_t bytesRead = fTeamMemory->ReadMemory(location.ToUInt64(), 215 _value, bytesToRead); 216 if (bytesRead < 0) 217 return bytesRead; 218 if ((uint32)bytesRead != bytesToRead) 219 return B_BAD_ADDRESS; 220 return B_OK; 221} 222 223 224status_t 225ValueLoader::LoadStringValue(BVariant& location, size_t maxSize, BString& _value) 226{ 227 static const size_t kMaxStringSize = 255; 228 229 return fTeamMemory->ReadMemoryString(location.ToUInt64(), 230 std::min(maxSize, kMaxStringSize), _value); 231} 232 233 234status_t 235ValueLoader::LookupTypeByName(const BString& name, 236 const TypeLookupConstraints& constraints, Type*& _type) 237{ 238 return fTypeInformation->LookupTypeByName(name, constraints, _type); 239} 240