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