xref: /haiku/src/kits/debugger/value/ValueLoader.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
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