1/*
2 * Copyright 2012-2015, Rene Gollent, rene@gollent.com
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "BListValueNode.h"
8
9#include <new>
10
11#include <AutoDeleter.h>
12
13#include "AddressValueNode.h"
14#include "Architecture.h"
15#include "StringValue.h"
16#include "TeamTypeInformation.h"
17#include "Tracing.h"
18#include "Type.h"
19#include "TypeLookupConstraints.h"
20#include "ValueLoader.h"
21#include "ValueLocation.h"
22#include "ValueNodeContainer.h"
23
24
25// maximum number of array elements to show by default
26static const int64 kMaxArrayElementCount = 20;
27
28
29//#pragma mark - BListValueNode::BListElementNodeChild
30
31
32class BListValueNode::BListElementNodeChild : public ValueNodeChild {
33public:
34								BListElementNodeChild(BListValueNode* parent,
35									int64 elementIndex, Type* type);
36	virtual						~BListElementNodeChild();
37
38	virtual	const BString&		Name() const { return fName; };
39	virtual	Type*				GetType() const { return fType; };
40	virtual	ValueNode*			Parent() const { return fParent; };
41
42	virtual status_t			ResolveLocation(ValueLoader* valueLoader,
43									ValueLocation*& _location);
44
45private:
46	Type*						fType;
47	BListValueNode*				fParent;
48	int64						fElementIndex;
49	BString						fName;
50};
51
52
53BListValueNode::BListElementNodeChild::BListElementNodeChild(
54	BListValueNode* parent, int64 elementIndex, Type* type)
55	:
56	ValueNodeChild(),
57	fType(type),
58	fParent(parent),
59	fElementIndex(elementIndex),
60	fName()
61{
62	fType->AcquireReference();
63	fParent->AcquireReference();
64	fName.SetToFormat("[%" B_PRId64 "]", fElementIndex);
65}
66
67
68BListValueNode::BListElementNodeChild::~BListElementNodeChild()
69{
70	fType->ReleaseReference();
71	fParent->ReleaseReference();
72}
73
74
75status_t
76BListValueNode::BListElementNodeChild::ResolveLocation(
77	ValueLoader* valueLoader, ValueLocation*& _location)
78{
79	uint8 addressSize = valueLoader->GetArchitecture()->AddressSize();
80	ValueLocation* location = new(std::nothrow) ValueLocation();
81	if (location == NULL)
82		return B_NO_MEMORY;
83
84
85	uint64 listAddress = fParent->fDataLocation.ToUInt64();
86	listAddress += fElementIndex * addressSize;
87
88	ValuePieceLocation piece;
89	piece.SetToMemory(listAddress);
90	piece.SetSize(addressSize);
91	location->AddPiece(piece);
92
93	_location = location;
94	return B_OK;
95}
96
97
98//#pragma mark - BListItemCountNodeChild
99
100class BListValueNode::BListItemCountNodeChild : public ValueNodeChild {
101public:
102								BListItemCountNodeChild(BVariant location,
103									BListValueNode* parent, Type* type);
104	virtual						~BListItemCountNodeChild();
105
106	virtual	const BString&		Name() const { return fName; };
107	virtual	Type*				GetType() const { return fType; };
108	virtual	ValueNode*			Parent() const { return fParent; };
109
110	virtual status_t			ResolveLocation(ValueLoader* valueLoader,
111									ValueLocation*& _location);
112
113private:
114	Type*						fType;
115	BListValueNode*				fParent;
116	BVariant					fLocation;
117	BString						fName;
118};
119
120
121BListValueNode::BListItemCountNodeChild::BListItemCountNodeChild(
122	BVariant location, BListValueNode* parent, Type* type)
123	:
124	ValueNodeChild(),
125	fType(type),
126	fParent(parent),
127	fLocation(location),
128	fName("Capacity")
129{
130	fType->AcquireReference();
131	fParent->AcquireReference();
132}
133
134
135BListValueNode::BListItemCountNodeChild::~BListItemCountNodeChild()
136{
137	fType->ReleaseReference();
138	fParent->ReleaseReference();
139}
140
141
142status_t
143BListValueNode::BListItemCountNodeChild::ResolveLocation(
144	ValueLoader* valueLoader, ValueLocation*& _location)
145{
146	ValueLocation* location = new(std::nothrow) ValueLocation();
147	if (location == NULL)
148		return B_NO_MEMORY;
149
150	ValuePieceLocation piece;
151	piece.SetToMemory(fLocation.ToUInt64());
152	piece.SetSize(sizeof(int32));
153	location->AddPiece(piece);
154
155	_location = location;
156	return B_OK;
157}
158
159
160//#pragma mark - BListValueNode
161
162BListValueNode::BListValueNode(ValueNodeChild* nodeChild,
163	Type* type)
164	:
165	ValueNode(nodeChild),
166	fType(type),
167	fItemCountType(NULL),
168	fItemCount(0),
169	fCountChildCreated(false)
170{
171	fType->AcquireReference();
172}
173
174
175BListValueNode::~BListValueNode()
176{
177	fType->ReleaseReference();
178	for (int32 i = 0; i < fChildren.CountItems(); i++)
179		fChildren.ItemAt(i)->ReleaseReference();
180
181	if (fItemCountType != NULL)
182		fItemCountType->ReleaseReference();
183}
184
185
186Type*
187BListValueNode::GetType() const
188{
189	return fType;
190}
191
192
193status_t
194BListValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader,
195	ValueLocation*& _location, Value*& _value)
196{
197	// get the location
198	ValueLocation* location = NodeChild()->Location();
199	if (location == NULL)
200		return B_BAD_VALUE;
201
202
203	// get the value type
204	type_code valueType;
205	if (valueLoader->GetArchitecture()->AddressSize() == 4) {
206		valueType = B_UINT32_TYPE;
207		TRACE_LOCALS("    -> 32 bit\n");
208	} else {
209		valueType = B_UINT64_TYPE;
210		TRACE_LOCALS("    -> 64 bit\n");
211	}
212
213	// load the value data
214
215	status_t error = B_OK;
216
217	ValueLocation* memberLocation = NULL;
218	CompoundType* baseType = dynamic_cast<CompoundType*>(fType);
219
220	if (baseType->CountTemplateParameters() != 0) {
221		// for BObjectList we need to walk up
222		// the hierarchy: BObjectList -> _PointerList_ -> BList
223		if (baseType->CountBaseTypes() == 0)
224			return B_BAD_DATA;
225
226		baseType = dynamic_cast<CompoundType*>(baseType->BaseTypeAt(0)
227			->GetType());
228		if (baseType == NULL || baseType->Name() != "_PointerList_")
229			return B_BAD_DATA;
230
231		if (baseType->CountBaseTypes() == 0)
232			return B_BAD_DATA;
233
234		baseType = dynamic_cast<CompoundType*>(baseType->BaseTypeAt(0)
235			->GetType());
236		if (baseType == NULL || baseType->Name() != "BList")
237			return B_BAD_DATA;
238
239	}
240
241	for (int32 i = 0; i < baseType->CountDataMembers(); i++) {
242		DataMember* member = baseType->DataMemberAt(i);
243		if (strcmp(member->Name(), "fObjectList") == 0) {
244			error = baseType->ResolveDataMemberLocation(member,
245				*location, memberLocation);
246			BReference<ValueLocation> locationRef(memberLocation, true);
247			if (error != B_OK) {
248				TRACE_LOCALS(
249					"BListValueNode::ResolvedLocationAndValue(): "
250					"failed to resolve location of header member: %s\n",
251					strerror(error));
252				return error;
253			}
254
255			error = valueLoader->LoadValue(memberLocation, valueType,
256				false, fDataLocation);
257			if (error != B_OK)
258				return error;
259		} else if (strcmp(member->Name(), "fItemCount") == 0) {
260			error = baseType->ResolveDataMemberLocation(member,
261				*location, memberLocation);
262			BReference<ValueLocation> locationRef(memberLocation, true);
263			if (error != B_OK) {
264				TRACE_LOCALS(
265					"BListValueNode::ResolvedLocationAndValue(): "
266					"failed to resolve location of header member: %s\n",
267					strerror(error));
268				return error;
269			}
270
271			fItemCountType = member->GetType();
272			fItemCountType->AcquireReference();
273
274			fItemCountLocation = memberLocation->PieceAt(0).address;
275
276			BVariant listSize;
277			error = valueLoader->LoadValue(memberLocation, B_INT32_TYPE,
278				false, listSize);
279			if (error != B_OK)
280				return error;
281
282			fItemCount = listSize.ToInt32();
283			TRACE_LOCALS(
284				"BListValueNode::ResolvedLocationAndValue(): "
285				"detected list size %" B_PRId32 "\n",
286				fItemCount);
287		}
288		memberLocation = NULL;
289	}
290
291	location->AcquireReference();
292	_location = location;
293	_value = NULL;
294
295	return B_OK;
296}
297
298
299status_t
300BListValueNode::CreateChildren(TeamTypeInformation* info)
301{
302	return CreateChildrenInRange(info, 0, kMaxArrayElementCount);
303}
304
305
306int32
307BListValueNode::CountChildren() const
308{
309	return fChildren.CountItems();
310}
311
312
313ValueNodeChild*
314BListValueNode::ChildAt(int32 index) const
315{
316	return fChildren.ItemAt(index);
317}
318
319
320bool
321BListValueNode::IsRangedContainer() const
322{
323	return true;
324}
325
326
327bool
328BListValueNode::IsContainerRangeFixed() const
329{
330	return true;
331}
332
333
334void
335BListValueNode::ClearChildren()
336{
337	fChildren.MakeEmpty();
338	fCountChildCreated = false;
339	if (fContainer != NULL)
340		fContainer->NotifyValueNodeChildrenDeleted(this);
341}
342
343
344status_t
345BListValueNode::CreateChildrenInRange(TeamTypeInformation* info,
346	int32 lowIndex, int32 highIndex)
347{
348	if (fLocationResolutionState != B_OK)
349		return fLocationResolutionState;
350
351	if (lowIndex < 0)
352		lowIndex = 0;
353	if (highIndex >= fItemCount)
354		highIndex = fItemCount - 1;
355
356	if (!fCountChildCreated && fItemCountType != NULL) {
357		BListItemCountNodeChild* countChild = new(std::nothrow)
358			BListItemCountNodeChild(fItemCountLocation, this, fItemCountType);
359
360		if (countChild == NULL)
361			return B_NO_MEMORY;
362
363		fCountChildCreated = true;
364		countChild->SetContainer(fContainer);
365		fChildren.AddItem(countChild);
366	}
367
368	BReference<Type> addressTypeRef;
369	Type* type = NULL;
370	CompoundType* objectType = dynamic_cast<CompoundType*>(fType);
371	if (objectType->CountTemplateParameters() != 0) {
372		AddressType* addressType = NULL;
373		status_t result = objectType->TemplateParameterAt(0)->GetType()
374			->CreateDerivedAddressType(DERIVED_TYPE_POINTER, addressType);
375		if (result != B_OK)
376			return result;
377
378		type = addressType;
379		addressTypeRef.SetTo(type, true);
380	} else {
381		BString typeName;
382		TypeLookupConstraints constraints;
383		constraints.SetTypeKind(TYPE_ADDRESS);
384		constraints.SetBaseTypeName("void");
385		status_t result = info->LookupTypeByName(typeName, constraints,
386			type);
387		if (result != B_OK)
388			return result;
389	}
390
391	for (int32 i = lowIndex; i <= highIndex; i++)
392	{
393		BListElementNodeChild* child =
394			new(std::nothrow) BListElementNodeChild(this, i, type);
395		if (child == NULL)
396			return B_NO_MEMORY;
397		child->SetContainer(fContainer);
398		fChildren.AddItem(child);
399	}
400
401	fChildrenCreated = true;
402
403	if (fContainer != NULL)
404		fContainer->NotifyValueNodeChildrenCreated(this);
405
406	return B_OK;
407}
408
409
410status_t
411BListValueNode::SupportedChildRange(int32& lowIndex, int32& highIndex) const
412{
413	lowIndex = 0;
414	highIndex = fItemCount - 1;
415
416	return B_OK;
417}
418
419