vfs: check userland buffers before reading them.
[haiku.git] / src / kits / debugger / value / ValueLoader.cpp
blob78c7542a18e79ba2af8ca7354093a72bbdd22ae0
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 */
8 #include "ValueLoader.h"
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"
19 ValueLoader::ValueLoader(Architecture* architecture, TeamMemory* teamMemory,
20 CpuState* cpuState)
22 fArchitecture(architecture),
23 fTeamMemory(teamMemory),
24 fCpuState(cpuState)
26 fArchitecture->AcquireReference();
27 fTeamMemory->AcquireReference();
28 if (fCpuState != NULL)
29 fCpuState->AcquireReference();
33 ValueLoader::~ValueLoader()
35 fArchitecture->ReleaseReference();
36 fTeamMemory->ReleaseReference();
37 if (fCpuState != NULL)
38 fCpuState->ReleaseReference();
42 status_t
43 ValueLoader::LoadValue(ValueLocation* location, type_code valueType,
44 bool shortValueIsFine, BVariant& _value)
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;
61 if (piece.size > kMaxPieceSize) {
62 TRACE_LOCALS(" -> overly long piece size (%" B_PRIu64 " bytes)\n",
63 piece.size);
64 return B_UNSUPPORTED;
67 totalBitSize += piece.bitSize;
70 TRACE_LOCALS(" -> totalBitSize: %" B_PRIu64 "\n", totalBitSize);
72 if (totalBitSize == 0) {
73 TRACE_LOCALS(" -> no size\n");
74 return B_ENTRY_NOT_FOUND;
77 if (totalBitSize > 64) {
78 TRACE_LOCALS(" -> longer than 64 bits: unsupported\n");
79 return B_UNSUPPORTED;
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;
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);
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.
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:
119 target_addr_t address = piece.address;
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);
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;
140 if (bytesRead < 0)
141 return bytesRead;
142 if ((uint32)bytesRead != bytesToRead)
143 return B_BAD_ADDRESS;
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");
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]);
160 valueBuffer.AddBits(pieceBuffer, bitSize, bitOffset);
161 break;
163 case VALUE_PIECE_LOCATION_REGISTER:
165 TRACE_LOCALS(" piece %" B_PRId32 ": register: %" B_PRIu32
166 ", bits: %" B_PRIu32 "\n", i, piece.reg, bitSize);
168 if (fCpuState == NULL) {
169 WARNING("ValueLoader::LoadValue(): register piece, but no "
170 "CpuState\n");
171 return B_UNSUPPORTED;
174 BVariant registerValue;
175 if (!fCpuState->GetRegisterValue(registers + piece.reg,
176 registerValue)) {
177 return B_ENTRY_NOT_FOUND;
179 if (registerValue.Size() < bytesToRead)
180 return B_ENTRY_NOT_FOUND;
182 if (!bigEndian) {
183 registerValue.SwapEndianess();
184 bitOffset = registerValue.Size() * 8 - bitOffset - bitSize;
186 valueBuffer.AddBits(registerValue.Bytes(), bitSize, bitOffset);
187 break;
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;
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;
204 // convert to host endianess
205 #if B_HOST_IS_LENDIAN
206 value.SwapEndianess();
207 #endif
209 _value = value;
210 return B_OK;
214 status_t
215 ValueLoader::LoadRawValue(BVariant& location, size_t bytesToRead, void* _value)
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;
227 status_t
228 ValueLoader::LoadStringValue(BVariant& location, size_t maxSize, BString& _value)
230 static const size_t kMaxStringSize = 255;
232 return fTeamMemory->ReadMemoryString(location.ToUInt64(),
233 std::min(maxSize, kMaxStringSize), _value);