1/*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2013, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7#include <stdio.h>
8
9#include "ValueLocation.h"
10
11
12// #pragma mark - ValuePieceLocation
13
14
15ValuePieceLocation&
16ValuePieceLocation::Normalize(bool bigEndian)
17{
18	uint64 excessMSBs = bitOffset / 8;
19	uint64 excessLSBs = size - (bitOffset + bitSize + 7) / 8;
20
21	if (excessMSBs > 0 || excessLSBs > 0) {
22		switch (type) {
23			case VALUE_PIECE_LOCATION_MEMORY:
24				if (bigEndian)
25					address += excessMSBs;
26				else
27					address += excessLSBs;
28				bitOffset -= excessMSBs * 8;
29				size -= excessMSBs + excessLSBs;
30				break;
31			case VALUE_PIECE_LOCATION_UNKNOWN:
32				bitOffset -= excessMSBs * 8;
33				size -= excessMSBs + excessLSBs;
34				break;
35			case VALUE_PIECE_LOCATION_REGISTER:
36			default:
37				break;
38		}
39	}
40
41	return *this;
42}
43
44
45// #pragma mark - ValueLocation
46
47
48ValueLocation::ValueLocation()
49	:
50	fBigEndian(false),
51	fWritable(false)
52{
53}
54
55
56ValueLocation::ValueLocation(bool bigEndian)
57	:
58	fBigEndian(bigEndian),
59	fWritable(false)
60{
61}
62
63
64ValueLocation::ValueLocation(bool bigEndian, const ValuePieceLocation& piece)
65	:
66	fBigEndian(bigEndian)
67{
68	AddPiece(piece);
69}
70
71
72ValueLocation::ValueLocation(const ValueLocation& other)
73	:
74	fPieces(other.fPieces),
75	fBigEndian(other.fBigEndian)
76{
77}
78
79
80bool
81ValueLocation::SetToByteOffset(const ValueLocation& other, uint64 byteOffset,
82	uint64 byteSize)
83{
84	Clear();
85
86	fBigEndian = other.fBigEndian;
87	ValuePieceLocation piece = other.PieceAt(0);
88	piece.SetToMemory(piece.address + byteOffset);
89	piece.SetSize(byteSize);
90
91	return AddPiece(piece);
92}
93
94
95bool
96ValueLocation::SetTo(const ValueLocation& other, uint64 bitOffset,
97	uint64 bitSize)
98{
99	Clear();
100
101	fBigEndian = other.fBigEndian;
102
103	// compute the total bit size
104	int32 count = other.CountPieces();
105	uint64 totalBitSize = 0;
106	for (int32 i = 0; i < count; i++) {
107		const ValuePieceLocation &piece = other.PieceAt(i);
108		totalBitSize += piece.bitSize;
109	}
110
111	// adjust requested bit offset/size to something reasonable, if necessary
112	if (bitOffset + bitSize > totalBitSize) {
113		if (bitOffset >= totalBitSize)
114			return true;
115		bitSize = totalBitSize - bitOffset;
116	}
117
118	if (fBigEndian) {
119		// Big endian: Skip the superfluous most significant bits, copy the
120		// pieces we need (cutting the first and the last one as needed) and
121		// ignore the remaining pieces.
122
123		// skip pieces for the most significant bits we don't need anymore
124		uint64 bitsToSkip = bitOffset;
125		int32 i;
126		ValuePieceLocation piece;
127		for (i = 0; i < count; i++) {
128			const ValuePieceLocation& tempPiece = other.PieceAt(i);
129			if (tempPiece.bitSize > bitsToSkip) {
130				if (!piece.Copy(tempPiece))
131					return false;
132				break;
133			}
134			bitsToSkip -= tempPiece.bitSize;
135		}
136
137		// handle partial piece
138		if (bitsToSkip > 0) {
139			piece.bitOffset += bitsToSkip;
140			piece.bitSize -= bitsToSkip;
141			piece.Normalize(fBigEndian);
142		}
143
144		// handle remaining pieces
145		while (bitSize > 0) {
146			if (piece.bitSize > bitSize) {
147				// the piece is bigger than the remaining size -- cut it
148				piece.bitSize = bitSize;
149				piece.Normalize(fBigEndian);
150				bitSize = 0;
151			} else
152				bitSize -= piece.bitSize;
153
154			if (!AddPiece(piece))
155				return false;
156
157			if (++i >= count)
158				break;
159
160			if (!piece.Copy(other.PieceAt(i)))
161				return false;
162		}
163	} else {
164		// Little endian: Skip the superfluous least significant bits, copy the
165		// pieces we need (cutting the first and the last one as needed) and
166		// ignore the remaining pieces.
167
168		// skip pieces for the least significant bits we don't need anymore
169		uint64 bitsToSkip = totalBitSize - bitOffset - bitSize;
170		int32 i;
171		ValuePieceLocation piece;
172		for (i = 0; i < count; i++) {
173			const ValuePieceLocation& tempPiece = other.PieceAt(i);
174			if (tempPiece.bitSize > bitsToSkip) {
175				if (!piece.Copy(tempPiece))
176					return false;
177				break;
178			}
179			bitsToSkip -= piece.bitSize;
180		}
181
182		// handle partial piece
183		if (bitsToSkip > 0) {
184			piece.bitSize -= bitsToSkip;
185			piece.Normalize(fBigEndian);
186		}
187
188		// handle remaining pieces
189		while (bitSize > 0) {
190			if (piece.bitSize > bitSize) {
191				// the piece is bigger than the remaining size -- cut it
192				piece.bitOffset += piece.bitSize - bitSize;
193				piece.bitSize = bitSize;
194				piece.Normalize(fBigEndian);
195				bitSize = 0;
196			} else
197				bitSize -= piece.bitSize;
198
199			if (!AddPiece(piece))
200				return false;
201
202			if (++i >= count)
203				break;
204
205			if (!piece.Copy(other.PieceAt(i)))
206				return false;
207		}
208	}
209
210	return true;
211}
212
213
214void
215ValueLocation::Clear()
216{
217	fWritable = false;
218	fPieces.clear();
219}
220
221
222bool
223ValueLocation::AddPiece(const ValuePieceLocation& piece)
224{
225	// Just add, don't normalize. This allows for using the class with different
226	// semantics (e.g. in the DWARF code).
227	try {
228		fPieces.push_back(piece);
229	} catch (...) {
230		return false;
231	}
232
233	if (fPieces.size() == 1)
234		fWritable = piece.writable;
235	else
236		fWritable = fWritable && piece.writable;
237
238	return true;
239}
240
241
242int32
243ValueLocation::CountPieces() const
244{
245	return fPieces.size();
246}
247
248
249ValuePieceLocation
250ValueLocation::PieceAt(int32 index) const
251{
252	if (index < 0 || index >= (int32)fPieces.size())
253		return ValuePieceLocation();
254
255	return fPieces[index];
256}
257
258
259bool
260ValueLocation::SetPieceAt(int32 index, const ValuePieceLocation& piece)
261{
262	if (index < 0 || index >= (int32)fPieces.size())
263		return false;
264
265	return fPieces[index].Copy(piece);
266}
267
268
269ValueLocation&
270ValueLocation::operator=(const ValueLocation& other)
271{
272	fPieces = other.fPieces;
273	fBigEndian = other.fBigEndian;
274	return *this;
275}
276
277
278void
279ValueLocation::Dump() const
280{
281	int32 count = fPieces.size();
282	printf("ValueLocation: %s endian, %" B_PRId32 " pieces:\n",
283		fBigEndian ? "big" : "little", count);
284
285	for (int32 i = 0; i < count; i++) {
286		const ValuePieceLocation& piece = fPieces[i];
287		switch (piece.type) {
288			case VALUE_PIECE_LOCATION_INVALID:
289				printf("  invalid\n");
290				continue;
291			case VALUE_PIECE_LOCATION_UNKNOWN:
292				printf("  unknown");
293				break;
294			case VALUE_PIECE_LOCATION_MEMORY:
295				printf("  address %#" B_PRIx64, piece.address);
296				break;
297			case VALUE_PIECE_LOCATION_REGISTER:
298				printf("  register %" B_PRIu32, piece.reg);
299				break;
300			case VALUE_PIECE_LOCATION_IMPLICIT:
301				printf("  implicit value: ");
302				for (uint32 j = 0; j < piece.size; j++)
303					printf("%x ", ((char *)piece.value)[j]);
304				break;
305		}
306
307		printf(" size: %" B_PRIu64 " (%" B_PRIu64 " bits), offset: %" B_PRIu64
308			" bits\n", piece.size, piece.bitSize, piece.bitOffset);
309	}
310}
311