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