1/*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copryight 2012-2014, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "DwarfTypes.h"
9
10#include <new>
11
12#include "Architecture.h"
13#include "ArrayIndexPath.h"
14#include "CompilationUnit.h"
15#include "Dwarf.h"
16#include "DwarfFile.h"
17#include "DwarfTargetInterface.h"
18#include "DwarfUtils.h"
19#include "Register.h"
20#include "RegisterMap.h"
21#include "Tracing.h"
22#include "ValueLocation.h"
23
24
25namespace {
26
27
28// #pragma mark - HasBitStridePredicate
29
30
31template<typename EntryType>
32struct HasBitStridePredicate {
33	inline bool operator()(EntryType* entry) const
34	{
35		return entry->BitStride()->IsValid();
36	}
37};
38
39
40// #pragma mark - HasByteStridePredicate
41
42
43template<typename EntryType>
44struct HasByteStridePredicate {
45	inline bool operator()(EntryType* entry) const
46	{
47		return entry->ByteStride()->IsValid();
48	}
49};
50
51
52}	// unnamed namespace
53
54
55type_kind
56dwarf_tag_to_type_kind(int32 tag)
57{
58	switch (tag) {
59		case DW_TAG_class_type:
60		case DW_TAG_structure_type:
61		case DW_TAG_union_type:
62		case DW_TAG_interface_type:
63			return TYPE_COMPOUND;
64
65		case DW_TAG_base_type:
66			return TYPE_PRIMITIVE;
67
68		case DW_TAG_pointer_type:
69		case DW_TAG_reference_type:
70			return TYPE_ADDRESS;
71
72		case DW_TAG_const_type:
73		case DW_TAG_packed_type:
74		case DW_TAG_volatile_type:
75		case DW_TAG_restrict_type:
76		case DW_TAG_shared_type:
77			return TYPE_MODIFIED;
78
79		case DW_TAG_typedef:
80			return TYPE_TYPEDEF;
81
82		case DW_TAG_array_type:
83			return TYPE_ARRAY;
84
85		case DW_TAG_enumeration_type:
86			return TYPE_ENUMERATION;
87
88		case DW_TAG_subrange_type:
89			return TYPE_SUBRANGE;
90
91		case DW_TAG_unspecified_type:
92			return TYPE_UNSPECIFIED;
93
94		case DW_TAG_subroutine_type:
95			return TYPE_FUNCTION;
96
97		case DW_TAG_ptr_to_member_type:
98			return TYPE_POINTER_TO_MEMBER;
99
100	}
101
102	return TYPE_UNSPECIFIED;
103}
104
105
106int32
107dwarf_tag_to_subtype_kind(int32 tag)
108{
109	switch (tag) {
110		case DW_TAG_class_type:
111			return COMPOUND_TYPE_CLASS;
112
113		case DW_TAG_structure_type:
114			return COMPOUND_TYPE_STRUCT;
115
116		case DW_TAG_union_type:
117			return COMPOUND_TYPE_UNION;
118
119		case DW_TAG_interface_type:
120			return COMPOUND_TYPE_INTERFACE;
121
122		case DW_TAG_pointer_type:
123			return DERIVED_TYPE_POINTER;
124
125		case DW_TAG_reference_type:
126			return DERIVED_TYPE_REFERENCE;
127	}
128
129	return -1;
130}
131
132
133// #pragma mark - DwarfTypeContext
134
135
136DwarfTypeContext::DwarfTypeContext(Architecture* architecture, image_id imageID,
137	DwarfFile* file, CompilationUnit* compilationUnit,
138	DIESubprogram* subprogramEntry, target_addr_t instructionPointer,
139	target_addr_t framePointer, target_addr_t relocationDelta,
140	DwarfTargetInterface* targetInterface, RegisterMap* fromDwarfRegisterMap)
141	:
142	fArchitecture(architecture),
143	fImageID(imageID),
144	fFile(file),
145	fCompilationUnit(compilationUnit),
146	fSubprogramEntry(subprogramEntry),
147	fInstructionPointer(instructionPointer),
148	fFramePointer(framePointer),
149	fRelocationDelta(relocationDelta),
150	fTargetInterface(targetInterface),
151	fFromDwarfRegisterMap(fromDwarfRegisterMap)
152{
153	fArchitecture->AcquireReference();
154	fFile->AcquireReference();
155	if (fTargetInterface != NULL)
156		fTargetInterface->AcquireReference();
157}
158
159
160DwarfTypeContext::~DwarfTypeContext()
161{
162	fArchitecture->ReleaseReference();
163	fFile->ReleaseReference();
164	if (fTargetInterface != NULL)
165		fTargetInterface->ReleaseReference();
166}
167
168
169uint8
170DwarfTypeContext::AddressSize() const
171{
172	return fCompilationUnit != NULL ? fCompilationUnit->AddressSize()
173		: fArchitecture->AddressSize();
174}
175
176
177bool
178DwarfTypeContext::IsBigEndian() const
179{
180	return fCompilationUnit != NULL ? fCompilationUnit->IsBigEndian()
181		: fArchitecture->IsBigEndian();
182}
183
184
185// #pragma mark - DwarfType
186
187
188DwarfType::DwarfType(DwarfTypeContext* typeContext, const BString& name,
189	const DIEType* entry)
190	:
191	fTypeContext(typeContext),
192	fName(name),
193	fByteSize(0)
194{
195	fTypeContext->AcquireReference();
196
197	GetTypeID(entry, fID);
198}
199
200
201DwarfType::~DwarfType()
202{
203	fTypeContext->ReleaseReference();
204}
205
206
207/*static*/ bool
208DwarfType::GetTypeID(const DIEType* entry, BString& _id)
209{
210	char buffer[32];
211	snprintf(buffer, sizeof(buffer), "dwarf:%p", entry);
212	BString id = buffer;
213	if (id.Length() == 0)
214		return false;
215
216	_id = id;
217	return true;
218}
219
220
221image_id
222DwarfType::ImageID() const
223{
224	return fTypeContext->ImageID();
225}
226
227
228const BString&
229DwarfType::ID() const
230{
231	return fID;
232}
233
234
235const BString&
236DwarfType::Name() const
237{
238	return fName;
239}
240
241
242target_size_t
243DwarfType::ByteSize() const
244{
245	return fByteSize;
246}
247
248
249status_t
250DwarfType::CreateDerivedAddressType(address_type_kind addressType,
251	AddressType*& _resultType)
252{
253	BString derivedName;
254	derivedName.SetToFormat("%s%c", fName.String(),
255		addressType == DERIVED_TYPE_POINTER ? '*' : '&');
256	DwarfAddressType* resultType = new(std::nothrow)
257		DwarfAddressType(fTypeContext, derivedName, NULL, addressType, this);
258
259	if (resultType == NULL)
260		return B_NO_MEMORY;
261
262	resultType->SetByteSize(fTypeContext->GetArchitecture()->AddressSize());
263
264	_resultType = resultType;
265	return B_OK;
266}
267
268
269status_t
270DwarfType::CreateDerivedArrayType(int64 lowerBound, int64 elementCount,
271	bool extendExisting, ArrayType*& _resultType)
272{
273	DwarfArrayType* resultType = NULL;
274	BReference<DwarfType> baseTypeReference;
275	if (extendExisting)
276		resultType = dynamic_cast<DwarfArrayType*>(this);
277
278	if (resultType == NULL) {
279		BString derivedName;
280		derivedName.SetToFormat("%s[]", fName.String());
281		resultType = new(std::nothrow)
282			DwarfArrayType(fTypeContext, derivedName, NULL, this);
283		baseTypeReference.SetTo(resultType, true);
284	}
285
286	if (resultType == NULL)
287		return B_NO_MEMORY;
288
289	DwarfSubrangeType* subrangeType = new(std::nothrow) DwarfSubrangeType(
290		fTypeContext, fName, NULL, resultType, BVariant(lowerBound),
291		BVariant(lowerBound + elementCount - 1));
292	if (subrangeType == NULL)
293		return B_NO_MEMORY;
294
295	BReference<DwarfSubrangeType> subrangeReference(subrangeType, true);
296
297	DwarfArrayDimension* dimension = new(std::nothrow) DwarfArrayDimension(
298		subrangeType);
299	if (dimension == NULL)
300		return B_NO_MEMORY;
301	BReference<DwarfArrayDimension> dimensionReference(dimension, true);
302
303	if (!resultType->AddDimension(dimension))
304		return B_NO_MEMORY;
305
306	baseTypeReference.Detach();
307
308	_resultType = resultType;
309	return B_OK;
310}
311
312
313status_t
314DwarfType::ResolveObjectDataLocation(const ValueLocation& objectLocation,
315	ValueLocation*& _location)
316{
317	// TODO: In some source languages the object address might be a pointer
318	// to a descriptor, not the actual object data.
319
320	// If the given location looks good already, just clone it.
321	int32 count = objectLocation.CountPieces();
322	if (count == 0)
323		return B_BAD_VALUE;
324
325	ValuePieceLocation piece;
326	if (!piece.Copy(objectLocation.PieceAt(0)))
327		return B_NO_MEMORY;
328
329	if (count > 1 || piece.type != VALUE_PIECE_LOCATION_MEMORY
330		|| piece.size != 0 || piece.bitSize != 0) {
331		ValueLocation* location
332			= new(std::nothrow) ValueLocation(objectLocation);
333		if (location == NULL || location->CountPieces() != count) {
334			delete location;
335			return B_NO_MEMORY;
336		}
337
338		_location = location;
339		return B_OK;
340	}
341
342	// The location contains just a single address piece with a zero size
343	// -- set the type's size.
344	piece.SetSize(ByteSize());
345		// TODO: Use bit size and bit offset, if specified!
346
347	ValueLocation* location = new(std::nothrow) ValueLocation(
348		objectLocation.IsBigEndian());
349	if (location == NULL || !location->AddPiece(piece)) {
350		delete location;
351		return B_NO_MEMORY;
352	}
353
354	_location = location;
355	return B_OK;
356}
357
358
359status_t
360DwarfType::ResolveObjectDataLocation(target_addr_t objectAddress,
361	ValueLocation*& _location)
362{
363	ValuePieceLocation piece;
364	piece.SetToMemory(objectAddress);
365	piece.SetSize(0);
366		// We set the piece size to 0 as an indicator that the size has to be
367		// set.
368		// TODO: We could set the byte size from type, but that may not be
369		// accurate. We may want to add bit offset and size to Type.
370
371	ValueLocation location(fTypeContext->GetArchitecture()->IsBigEndian());
372	if (!location.AddPiece(piece))
373		return B_NO_MEMORY;
374
375	return ResolveObjectDataLocation(location, _location);
376}
377
378
379status_t
380DwarfType::ResolveLocation(DwarfTypeContext* typeContext,
381	const LocationDescription* description, target_addr_t objectAddress,
382	bool hasObjectAddress, ValueLocation& _location)
383{
384	status_t error = typeContext->File()->ResolveLocation(
385		typeContext->GetCompilationUnit(),
386		typeContext->AddressSize(), typeContext->IsBigEndian(),
387		typeContext->SubprogramEntry(), description,
388		typeContext->TargetInterface(), typeContext->InstructionPointer(),
389		objectAddress, hasObjectAddress, typeContext->FramePointer(),
390		typeContext->RelocationDelta(), _location);
391	if (error != B_OK)
392		return error;
393
394	// translate the DWARF register indices and the bit offset/size semantics
395	const Register* registers = typeContext->GetArchitecture()->Registers();
396	bool bigEndian = typeContext->GetArchitecture()->IsBigEndian();
397	int32 count = _location.CountPieces();
398	for (int32 i = 0; i < count; i++) {
399		ValuePieceLocation piece;
400		if (!piece.Copy(_location.PieceAt(i)))
401			return B_NO_MEMORY;
402
403		if (piece.type == VALUE_PIECE_LOCATION_REGISTER) {
404			int32 reg = typeContext->FromDwarfRegisterMap()->MapRegisterIndex(
405				piece.reg);
406			if (reg >= 0) {
407				piece.reg = reg;
408				// The bit offset for registers is to the least
409				// significant bit, while we want the offset to the most
410				// significant bit.
411				if (registers[reg].BitSize() > piece.bitSize) {
412					piece.bitOffset = registers[reg].BitSize() - piece.bitSize
413						- piece.bitOffset;
414				}
415			} else
416				piece.SetToUnknown();
417		} else if (piece.type == VALUE_PIECE_LOCATION_MEMORY) {
418			// Whether the bit offset is to the least or most significant bit
419			// is target architecture and source language specific.
420			// TODO: Check whether this is correct!
421			// TODO: Source language!
422			if (!bigEndian && piece.size * 8 > piece.bitSize) {
423				piece.bitOffset = piece.size * 8 - piece.bitSize
424					- piece.bitOffset;
425			}
426		}
427
428		piece.Normalize(bigEndian);
429		if (!_location.SetPieceAt(i, piece))
430			return B_NO_MEMORY;
431	}
432
433	// If we only have one piece and that doesn't have a size, try to retrieve
434	// the size of the type.
435	if (count == 1) {
436		ValuePieceLocation piece;
437		if (!piece.Copy(_location.PieceAt(0)))
438			return B_NO_MEMORY;
439
440		if (piece.IsValid() && piece.size == 0 && piece.bitSize == 0) {
441			piece.SetSize(ByteSize());
442				// TODO: Use bit size and bit offset, if specified!
443			if (!_location.SetPieceAt(0, piece))
444				return B_NO_MEMORY;
445
446			TRACE_LOCALS("  set single piece size to %" B_PRIu64 "\n",
447				ByteSize());
448		}
449	}
450
451	return B_OK;
452}
453
454
455// #pragma mark - DwarfInheritance
456
457
458DwarfInheritance::DwarfInheritance(DIEInheritance* entry, DwarfType* type)
459	:
460	fEntry(entry),
461	fType(type)
462{
463	fType->AcquireReference();
464}
465
466
467DwarfInheritance::~DwarfInheritance()
468{
469	fType->ReleaseReference();
470}
471
472
473Type*
474DwarfInheritance::GetType() const
475{
476	return fType;
477}
478
479
480// #pragma mark - DwarfDataMember
481
482
483DwarfDataMember::DwarfDataMember(DIEMember* entry, const BString& name,
484	DwarfType* type)
485	:
486	fEntry(entry),
487	fName(name),
488	fType(type)
489{
490	fType->AcquireReference();
491}
492
493
494DwarfDataMember::~DwarfDataMember()
495{
496	fType->ReleaseReference();
497}
498
499const char*
500DwarfDataMember::Name() const
501{
502	return fName.Length() > 0 ? fName.String() : NULL;
503}
504
505
506Type*
507DwarfDataMember::GetType() const
508{
509	return fType;
510}
511
512
513// #pragma mark - DwarfEnumeratorValue
514
515
516DwarfEnumeratorValue::DwarfEnumeratorValue(DIEEnumerator* entry,
517	const BString& name, const BVariant& value)
518	:
519	fEntry(entry),
520	fName(name),
521	fValue(value)
522{
523}
524
525
526DwarfEnumeratorValue::~DwarfEnumeratorValue()
527{
528}
529
530const char*
531DwarfEnumeratorValue::Name() const
532{
533	return fName.Length() > 0 ? fName.String() : NULL;
534}
535
536
537BVariant
538DwarfEnumeratorValue::Value() const
539{
540	return fValue;
541}
542
543
544// #pragma mark - DwarfArrayDimension
545
546
547DwarfArrayDimension::DwarfArrayDimension(DwarfType* type)
548	:
549	fType(type)
550{
551	fType->AcquireReference();
552}
553
554
555DwarfArrayDimension::~DwarfArrayDimension()
556{
557	fType->ReleaseReference();
558}
559
560
561Type*
562DwarfArrayDimension::GetType() const
563{
564	return fType;
565}
566
567
568// #pragma mark - DwarfFunctionParameter
569
570
571DwarfFunctionParameter::DwarfFunctionParameter(DIEFormalParameter* entry,
572	const BString& name, DwarfType* type)
573	:
574	fEntry(entry),
575	fName(name),
576	fType(type)
577{
578	fType->AcquireReference();
579}
580
581
582DwarfFunctionParameter::~DwarfFunctionParameter()
583{
584	fType->ReleaseReference();
585}
586
587
588const char*
589DwarfFunctionParameter::Name() const
590{
591	return fName.Length() > 0 ? fName.String() : NULL;
592}
593
594
595Type*
596DwarfFunctionParameter::GetType() const
597{
598	return fType;
599}
600
601
602// #pragma mark - DwarfTemplateParameter
603
604
605DwarfTemplateParameter::DwarfTemplateParameter(DebugInfoEntry* entry,
606	DwarfType* type)
607	:
608	fEntry(entry),
609	fType(type)
610{
611	fType->AcquireReference();
612	DIETemplateTypeParameter* typeParameter
613		= dynamic_cast<DIETemplateTypeParameter *>(entry);
614	if (typeParameter != NULL)
615		fTemplateKind = TEMPLATE_TYPE_TYPE;
616	else {
617		DIETemplateValueParameter* valueParameter
618			= dynamic_cast<DIETemplateValueParameter *>(entry);
619		fTemplateKind = TEMPLATE_TYPE_VALUE;
620		const ConstantAttributeValue* constValue = valueParameter
621			->ConstValue();
622		switch (constValue->attributeClass) {
623			case ATTRIBUTE_CLASS_CONSTANT:
624				fValue.SetTo(constValue->constant);
625				break;
626			case ATTRIBUTE_CLASS_STRING:
627				fValue.SetTo(constValue->string);
628				break;
629			// TODO: ATTRIBUTE_CLASS_BLOCK_DATA
630		}
631	}
632}
633
634
635DwarfTemplateParameter::~DwarfTemplateParameter()
636{
637	fType->ReleaseReference();
638}
639
640
641// #pragma mark - DwarfPrimitiveType
642
643
644DwarfPrimitiveType::DwarfPrimitiveType(DwarfTypeContext* typeContext,
645	const BString& name, DIEBaseType* entry, uint32 typeConstant)
646	:
647	DwarfType(typeContext, name, entry),
648	fEntry(entry),
649	fTypeConstant(typeConstant)
650{
651}
652
653
654DIEType*
655DwarfPrimitiveType::GetDIEType() const
656{
657	return fEntry;
658}
659
660
661uint32
662DwarfPrimitiveType::TypeConstant() const
663{
664	return fTypeConstant;
665}
666
667
668// #pragma mark - DwarfCompoundType
669
670
671DwarfCompoundType::DwarfCompoundType(DwarfTypeContext* typeContext,
672	const BString& name, DIECompoundType* entry,
673	compound_type_kind compoundKind)
674	:
675	DwarfType(typeContext, name, entry),
676	fCompoundKind(compoundKind),
677	fEntry(entry)
678{
679}
680
681
682DwarfCompoundType::~DwarfCompoundType()
683{
684	for (int32 i = 0;
685			DwarfInheritance* inheritance = fInheritances.ItemAt(i); i++) {
686		inheritance->ReleaseReference();
687	}
688	for (int32 i = 0; DwarfDataMember* member = fDataMembers.ItemAt(i); i++)
689		member->ReleaseReference();
690
691	for (int32 i = 0; DwarfTemplateParameter* parameter
692		= fTemplateParameters.ItemAt(i); i++) {
693		parameter->ReleaseReference();
694	}
695}
696
697
698compound_type_kind
699DwarfCompoundType::CompoundKind() const
700{
701	return fCompoundKind;
702}
703
704
705int32
706DwarfCompoundType::CountBaseTypes() const
707{
708	return fInheritances.CountItems();
709}
710
711
712BaseType*
713DwarfCompoundType::BaseTypeAt(int32 index) const
714{
715	return fInheritances.ItemAt(index);
716}
717
718
719int32
720DwarfCompoundType::CountDataMembers() const
721{
722	return fDataMembers.CountItems();
723}
724
725
726DataMember*
727DwarfCompoundType::DataMemberAt(int32 index) const
728{
729	return fDataMembers.ItemAt(index);
730}
731
732
733int32
734DwarfCompoundType::CountTemplateParameters() const
735{
736	return fTemplateParameters.CountItems();
737}
738
739
740TemplateParameter*
741DwarfCompoundType::TemplateParameterAt(int32 index) const
742{
743	return fTemplateParameters.ItemAt(index);
744}
745
746
747status_t
748DwarfCompoundType::ResolveBaseTypeLocation(BaseType* _baseType,
749	const ValueLocation& parentLocation, ValueLocation*& _location)
750{
751	DwarfInheritance* baseType = dynamic_cast<DwarfInheritance*>(_baseType);
752	if (baseType == NULL)
753		return B_BAD_VALUE;
754
755	return _ResolveDataMemberLocation(baseType->GetDwarfType(),
756		baseType->Entry()->Location(), parentLocation, false, _location);
757}
758
759
760status_t
761DwarfCompoundType::ResolveDataMemberLocation(DataMember* _member,
762	const ValueLocation& parentLocation, ValueLocation*& _location)
763{
764	DwarfDataMember* member = dynamic_cast<DwarfDataMember*>(_member);
765	if (member == NULL)
766		return B_BAD_VALUE;
767	DwarfTypeContext* typeContext = TypeContext();
768
769	bool isBitField = true;
770	DIEMember* memberEntry = member->Entry();
771	// TODO: handle DW_AT_data_bit_offset
772	if (!memberEntry->ByteSize()->IsValid()
773		&& !memberEntry->BitOffset()->IsValid()
774		&& !memberEntry->BitSize()->IsValid()) {
775		isBitField = false;
776	}
777
778	ValueLocation* location;
779	status_t error = _ResolveDataMemberLocation(member->GetDwarfType(),
780		member->Entry()->Location(), parentLocation, isBitField, location);
781	if (error != B_OK)
782		return error;
783
784	// If the member isn't a bit field, we're done.
785	if (!isBitField) {
786		_location = location;
787		return B_OK;
788	}
789
790	BReference<ValueLocation> locationReference(location);
791
792	// get the byte size
793	target_addr_t byteSize;
794	if (memberEntry->ByteSize()->IsValid()) {
795		BVariant value;
796		error = typeContext->File()->EvaluateDynamicValue(
797			typeContext->GetCompilationUnit(),
798			typeContext->AddressSize(), typeContext->IsBigEndian(),
799			typeContext->SubprogramEntry(), memberEntry->ByteSize(),
800			typeContext->TargetInterface(), typeContext->InstructionPointer(),
801			typeContext->FramePointer(), value);
802		if (error != B_OK)
803			return error;
804		byteSize = value.ToUInt64();
805	} else
806		byteSize = ByteSize();
807
808	// get the bit offset
809	uint64 bitOffset = 0;
810	if (memberEntry->BitOffset()->IsValid()) {
811		BVariant value;
812		error = typeContext->File()->EvaluateDynamicValue(
813			typeContext->GetCompilationUnit(),
814			typeContext->AddressSize(), typeContext->IsBigEndian(),
815			typeContext->SubprogramEntry(), memberEntry->BitOffset(),
816			typeContext->TargetInterface(), typeContext->InstructionPointer(),
817			typeContext->FramePointer(), value);
818		if (error != B_OK)
819			return error;
820		bitOffset = value.ToUInt64();
821	}
822
823	// get the bit size
824	uint64 bitSize = byteSize * 8;
825	if (memberEntry->BitSize()->IsValid()) {
826		BVariant value;
827		error = typeContext->File()->EvaluateDynamicValue(
828			typeContext->GetCompilationUnit(),
829			typeContext->AddressSize(), typeContext->IsBigEndian(),
830			typeContext->SubprogramEntry(), memberEntry->BitSize(),
831			typeContext->TargetInterface(), typeContext->InstructionPointer(),
832			typeContext->FramePointer(), value);
833		if (error != B_OK)
834			return error;
835		bitSize = value.ToUInt64();
836	}
837
838	TRACE_LOCALS("bit field: byte size: %" B_PRIu64 ", bit offset/size: %"
839		B_PRIu64 "/%" B_PRIu64 "\n", byteSize, bitOffset, bitSize);
840
841	if (bitOffset + bitSize > byteSize * 8)
842		return B_BAD_VALUE;
843
844	// create the bit field value location
845	ValueLocation* bitFieldLocation = new(std::nothrow) ValueLocation;
846	if (bitFieldLocation == NULL)
847		return B_NO_MEMORY;
848	BReference<ValueLocation> bitFieldLocationReference(bitFieldLocation, true);
849
850	if (!bitFieldLocation->SetTo(*location, bitOffset, bitSize))
851		return B_NO_MEMORY;
852
853	_location = bitFieldLocationReference.Detach();
854	return B_OK;
855}
856
857
858DIEType*
859DwarfCompoundType::GetDIEType() const
860{
861	return fEntry;
862}
863
864
865bool
866DwarfCompoundType::AddInheritance(DwarfInheritance* inheritance)
867{
868	if (!fInheritances.AddItem(inheritance))
869		return false;
870
871	inheritance->AcquireReference();
872	return true;
873}
874
875
876bool
877DwarfCompoundType::AddDataMember(DwarfDataMember* member)
878{
879	if (!fDataMembers.AddItem(member))
880		return false;
881
882	member->AcquireReference();
883	return true;
884}
885
886
887bool
888DwarfCompoundType::AddTemplateParameter(DwarfTemplateParameter* parameter)
889{
890	if (!fTemplateParameters.AddItem(parameter))
891		return false;
892
893	parameter->AcquireReference();
894	return true;
895}
896
897
898status_t
899DwarfCompoundType::_ResolveDataMemberLocation(DwarfType* memberType,
900	const MemberLocation* memberLocation,
901	const ValueLocation& parentLocation, bool isBitField,
902	ValueLocation*& _location)
903{
904	// create the value location object for the member
905	ValueLocation* location = new(std::nothrow) ValueLocation(
906		parentLocation.IsBigEndian());
907	if (location == NULL)
908		return B_NO_MEMORY;
909	BReference<ValueLocation> locationReference(location, true);
910
911	switch (memberLocation->attributeClass) {
912		case ATTRIBUTE_CLASS_CONSTANT:
913		{
914			if (isBitField) {
915				if (!location->SetTo(parentLocation,
916					memberLocation->constant * 8,
917					memberType->ByteSize() * 8)) {
918					return B_NO_MEMORY;
919				}
920			} else {
921				if (!location->SetToByteOffset(parentLocation,
922					memberLocation->constant,
923					memberType->ByteSize())) {
924					return B_NO_MEMORY;
925				}
926			}
927
928			break;
929		}
930		case ATTRIBUTE_CLASS_BLOCK:
931		case ATTRIBUTE_CLASS_LOCLISTPTR:
932		{
933			// The attribute is a location description. Since we need to push
934			// the parent object value onto the stack, we require the parent
935			// location to be a memory location.
936			if (parentLocation.CountPieces() != 1)
937				return B_BAD_VALUE;
938			const ValuePieceLocation& piece = parentLocation.PieceAt(0);
939
940			if (piece.type != VALUE_PIECE_LOCATION_MEMORY)
941				return B_BAD_VALUE;
942
943			// convert member location to location description
944			LocationDescription locationDescription;
945			if (memberLocation->attributeClass == ATTRIBUTE_CLASS_BLOCK) {
946				locationDescription.SetToExpression(
947					memberLocation->expression.data,
948					memberLocation->expression.length);
949			} else {
950				locationDescription.SetToLocationList(
951					memberLocation->listOffset);
952			}
953
954			// evaluate the location description
955			status_t error = memberType->ResolveLocation(TypeContext(),
956				&locationDescription, piece.address, true, *location);
957			if (error != B_OK)
958				return error;
959
960			break;
961		}
962		default:
963		{
964			// for unions the member location can be omitted -- all members
965			// start at the beginning of the parent object
966			if (fEntry->Tag() != DW_TAG_union_type)
967				return B_BAD_VALUE;
968
969			// since all members start at the same location, set up
970			// the location by hand since we don't want the size difference
971			// between the overall union and the member being
972			// factored into the assigned address.
973			ValuePieceLocation piece;
974			if (!piece.Copy(parentLocation.PieceAt(0)))
975				return B_NO_MEMORY;
976
977			piece.SetSize(memberType->ByteSize());
978			if (!location->AddPiece(piece))
979				return B_NO_MEMORY;
980
981			break;
982		}
983	}
984
985	_location = locationReference.Detach();
986	return B_OK;
987}
988
989
990// #pragma mark - DwarfArrayType
991
992
993DwarfArrayType::DwarfArrayType(DwarfTypeContext* typeContext,
994	const BString& name, DIEArrayType* entry, DwarfType* baseType)
995	:
996	DwarfType(typeContext, name, entry),
997	fEntry(entry),
998	fBaseType(baseType)
999{
1000	fBaseType->AcquireReference();
1001}
1002
1003
1004DwarfArrayType::~DwarfArrayType()
1005{
1006	for (int32 i = 0;
1007		DwarfArrayDimension* dimension = fDimensions.ItemAt(i); i++) {
1008		dimension->ReleaseReference();
1009	}
1010
1011	fBaseType->ReleaseReference();
1012}
1013
1014
1015Type*
1016DwarfArrayType::BaseType() const
1017{
1018	return fBaseType;
1019}
1020
1021
1022int32
1023DwarfArrayType::CountDimensions() const
1024{
1025	return fDimensions.CountItems();
1026}
1027
1028
1029ArrayDimension*
1030DwarfArrayType::DimensionAt(int32 index) const
1031{
1032	return fDimensions.ItemAt(index);
1033}
1034
1035
1036status_t
1037DwarfArrayType::ResolveElementLocation(const ArrayIndexPath& indexPath,
1038	const ValueLocation& parentLocation, ValueLocation*& _location)
1039{
1040	if (indexPath.CountIndices() != CountDimensions())
1041		return B_BAD_VALUE;
1042	DwarfTypeContext* typeContext = TypeContext();
1043
1044	// If the array entry has a bit stride, get it. Otherwise fall back to the
1045	// element type size.
1046	int64 bitStride;
1047	DIEArrayType* bitStrideOwnerEntry = NULL;
1048	if (fEntry != NULL && (bitStrideOwnerEntry = DwarfUtils::GetDIEByPredicate(
1049			fEntry, HasBitStridePredicate<DIEArrayType>()))) {
1050		BVariant value;
1051		status_t error = typeContext->File()->EvaluateDynamicValue(
1052			typeContext->GetCompilationUnit(),
1053			typeContext->AddressSize(), typeContext->IsBigEndian(),
1054			typeContext->SubprogramEntry(), bitStrideOwnerEntry->BitStride(),
1055			typeContext->TargetInterface(), typeContext->InstructionPointer(),
1056			typeContext->FramePointer(), value);
1057		if (error != B_OK)
1058			return error;
1059		if (!value.IsInteger())
1060			return B_BAD_VALUE;
1061		bitStride = value.ToInt64();
1062	} else
1063		bitStride = BaseType()->ByteSize() * 8;
1064
1065	// Iterate backward through the dimensions and compute the total offset of
1066	// the element.
1067	int64 elementOffset = 0;
1068	DwarfArrayDimension* previousDimension = NULL;
1069	int64 previousDimensionStride = 0;
1070	for (int32 dimensionIndex = CountDimensions() - 1;
1071			dimensionIndex >= 0; dimensionIndex--) {
1072		DwarfArrayDimension* dimension = DwarfDimensionAt(dimensionIndex);
1073		int64 index = indexPath.IndexAt(dimensionIndex);
1074
1075		// If the dimension has a special bit/byte stride, get it.
1076		int64 dimensionStride = 0;
1077		DwarfType* dimensionType = dimension->GetDwarfType();
1078		DIEArrayIndexType* dimensionTypeEntry = dimensionType != NULL
1079			? dynamic_cast<DIEArrayIndexType*>(dimensionType->GetDIEType())
1080			: NULL;
1081		if (dimensionTypeEntry != NULL) {
1082			DIEArrayIndexType* bitStrideOwnerEntry
1083				= DwarfUtils::GetDIEByPredicate(dimensionTypeEntry,
1084					HasBitStridePredicate<DIEArrayIndexType>());
1085			if (bitStrideOwnerEntry != NULL) {
1086				BVariant value;
1087				status_t error = typeContext->File()->EvaluateDynamicValue(
1088					typeContext->GetCompilationUnit(),
1089					typeContext->AddressSize(), typeContext->IsBigEndian(),
1090					typeContext->SubprogramEntry(),
1091					bitStrideOwnerEntry->BitStride(),
1092					typeContext->TargetInterface(),
1093					typeContext->InstructionPointer(),
1094					typeContext->FramePointer(), value);
1095				if (error != B_OK)
1096					return error;
1097				if (!value.IsInteger())
1098					return B_BAD_VALUE;
1099				dimensionStride = value.ToInt64();
1100			} else {
1101				DIEArrayIndexType* byteStrideOwnerEntry
1102					= DwarfUtils::GetDIEByPredicate(dimensionTypeEntry,
1103						HasByteStridePredicate<DIEArrayIndexType>());
1104				if (byteStrideOwnerEntry != NULL) {
1105					BVariant value;
1106					status_t error = typeContext->File()->EvaluateDynamicValue(
1107						typeContext->GetCompilationUnit(),
1108						typeContext->AddressSize(), typeContext->IsBigEndian(),
1109						typeContext->SubprogramEntry(),
1110						byteStrideOwnerEntry->ByteStride(),
1111						typeContext->TargetInterface(),
1112						typeContext->InstructionPointer(),
1113						typeContext->FramePointer(), value);
1114					if (error != B_OK)
1115						return error;
1116					if (!value.IsInteger())
1117						return B_BAD_VALUE;
1118					dimensionStride = value.ToInt64() * 8;
1119				}
1120			}
1121		}
1122
1123		// If we don't have a stride for the dimension yet, use the stride of
1124		// the previous dimension multiplied by the size of the dimension.
1125		if (dimensionStride == 0) {
1126			if (previousDimension != NULL) {
1127				dimensionStride = previousDimensionStride
1128					* previousDimension->CountElements();
1129			} else {
1130				// the last dimension -- use the element bit stride
1131				dimensionStride = bitStride;
1132			}
1133		}
1134
1135		// If the dimension stride is still 0 (that can happen, if the dimension
1136		// doesn't have a stride and the previous dimension's element count is
1137		// not known), we can only resolve the first element.
1138		if (dimensionStride == 0 && index != 0) {
1139			WARNING("No dimension bit stride for dimension %" B_PRId32 " and "
1140				"element index is not 0.\n", dimensionIndex);
1141			return B_BAD_VALUE;
1142		}
1143
1144		elementOffset += dimensionStride * index;
1145
1146		previousDimension = dimension;
1147		previousDimensionStride = dimensionStride;
1148	}
1149
1150	TRACE_LOCALS("total element bit offset: %" B_PRId64 "\n", elementOffset);
1151
1152	// create the value location object for the element
1153	ValueLocation* location = new(std::nothrow) ValueLocation(
1154		parentLocation.IsBigEndian());
1155	if (location == NULL)
1156		return B_NO_MEMORY;
1157	BReference<ValueLocation> locationReference(location, true);
1158
1159	// If we have a single memory piece location for the array, we compute the
1160	// element's location by hand -- not uncommonly the array size isn't known.
1161	if (parentLocation.CountPieces() == 1) {
1162		ValuePieceLocation piece;
1163		if (!piece.Copy(parentLocation.PieceAt(0)))
1164			return B_NO_MEMORY;
1165
1166		if (piece.type == VALUE_PIECE_LOCATION_MEMORY) {
1167			int64 byteOffset = elementOffset >= 0
1168				? elementOffset / 8 : (elementOffset - 7) / 8;
1169			piece.SetToMemory(piece.address + byteOffset);
1170			piece.SetSize(BaseType()->ByteSize());
1171			// TODO: Support bit offsets correctly!
1172			// TODO: Support bit fields (primitive types) correctly!
1173
1174			if (!location->AddPiece(piece))
1175				return B_NO_MEMORY;
1176
1177			_location = locationReference.Detach();
1178			return B_OK;
1179		}
1180	}
1181
1182	// We can't deal with negative element offsets at this point. It doesn't
1183	// make a lot of sense anyway, if the array location consists of multiple
1184	// pieces or lives in a register.
1185	if (elementOffset < 0) {
1186		WARNING("Negative element offset unsupported for multiple location "
1187			"pieces or register pieces.\n");
1188		return B_UNSUPPORTED;
1189	}
1190
1191	if (!location->SetTo(parentLocation, elementOffset,
1192			BaseType()->ByteSize() * 8)) {
1193		return B_NO_MEMORY;
1194	}
1195
1196	_location = locationReference.Detach();
1197	return B_OK;
1198}
1199
1200
1201
1202DIEType*
1203DwarfArrayType::GetDIEType() const
1204{
1205	return fEntry;
1206}
1207
1208
1209bool
1210DwarfArrayType::AddDimension(DwarfArrayDimension* dimension)
1211{
1212	if (!fDimensions.AddItem(dimension))
1213		return false;
1214
1215	dimension->AcquireReference();
1216	return true;
1217}
1218
1219
1220// #pragma mark - DwarfModifiedType
1221
1222
1223DwarfModifiedType::DwarfModifiedType(DwarfTypeContext* typeContext,
1224	const BString& name, DIEModifiedType* entry, uint32 modifiers,
1225	DwarfType* baseType)
1226	:
1227	DwarfType(typeContext, name, entry),
1228	fEntry(entry),
1229	fModifiers(modifiers),
1230	fBaseType(baseType)
1231{
1232	fBaseType->AcquireReference();
1233}
1234
1235
1236DwarfModifiedType::~DwarfModifiedType()
1237{
1238	fBaseType->ReleaseReference();
1239}
1240
1241
1242uint32
1243DwarfModifiedType::Modifiers() const
1244{
1245	return fModifiers;
1246}
1247
1248
1249Type*
1250DwarfModifiedType::BaseType() const
1251{
1252	return fBaseType;
1253}
1254
1255
1256DIEType*
1257DwarfModifiedType::GetDIEType() const
1258{
1259	return fEntry;
1260}
1261
1262
1263// #pragma mark - DwarfTypedefType
1264
1265
1266DwarfTypedefType::DwarfTypedefType(DwarfTypeContext* typeContext,
1267	const BString& name, DIETypedef* entry, DwarfType* baseType)
1268	:
1269	DwarfType(typeContext, name, entry),
1270	fEntry(entry),
1271	fBaseType(baseType)
1272{
1273	fBaseType->AcquireReference();
1274}
1275
1276
1277DwarfTypedefType::~DwarfTypedefType()
1278{
1279	fBaseType->ReleaseReference();
1280}
1281
1282
1283Type*
1284DwarfTypedefType::BaseType() const
1285{
1286	return fBaseType;
1287}
1288
1289
1290DIEType*
1291DwarfTypedefType::GetDIEType() const
1292{
1293	return fEntry;
1294}
1295
1296
1297// #pragma mark - DwarfAddressType
1298
1299
1300DwarfAddressType::DwarfAddressType(DwarfTypeContext* typeContext,
1301	const BString& name, DIEAddressingType* entry,
1302	address_type_kind addressKind, DwarfType* baseType)
1303	:
1304	DwarfType(typeContext, name, entry),
1305	fEntry(entry),
1306	fAddressKind(addressKind),
1307	fBaseType(baseType)
1308{
1309	fBaseType->AcquireReference();
1310}
1311
1312
1313DwarfAddressType::~DwarfAddressType()
1314{
1315	fBaseType->ReleaseReference();
1316}
1317
1318
1319address_type_kind
1320DwarfAddressType::AddressKind() const
1321{
1322	return fAddressKind;
1323}
1324
1325
1326Type*
1327DwarfAddressType::BaseType() const
1328{
1329	return fBaseType;
1330}
1331
1332
1333DIEType*
1334DwarfAddressType::GetDIEType() const
1335{
1336	return fEntry;
1337}
1338
1339
1340// #pragma mark - DwarfEnumerationType
1341
1342
1343DwarfEnumerationType::DwarfEnumerationType(DwarfTypeContext* typeContext,
1344	const BString& name, DIEEnumerationType* entry, DwarfType* baseType)
1345	:
1346	DwarfType(typeContext, name, entry),
1347	fEntry(entry),
1348	fBaseType(baseType)
1349{
1350	if (fBaseType != NULL)
1351		fBaseType->AcquireReference();
1352}
1353
1354
1355DwarfEnumerationType::~DwarfEnumerationType()
1356{
1357	for (int32 i = 0; DwarfEnumeratorValue* value = fValues.ItemAt(i); i++)
1358		value->ReleaseReference();
1359
1360	if (fBaseType != NULL)
1361		fBaseType->ReleaseReference();
1362}
1363
1364
1365Type*
1366DwarfEnumerationType::BaseType() const
1367{
1368	return fBaseType;
1369}
1370
1371
1372int32
1373DwarfEnumerationType::CountValues() const
1374{
1375	return fValues.CountItems();
1376}
1377
1378
1379EnumeratorValue*
1380DwarfEnumerationType::ValueAt(int32 index) const
1381{
1382	return fValues.ItemAt(index);
1383}
1384
1385
1386DIEType*
1387DwarfEnumerationType::GetDIEType() const
1388{
1389	return fEntry;
1390}
1391
1392
1393bool
1394DwarfEnumerationType::AddValue(DwarfEnumeratorValue* value)
1395{
1396	if (!fValues.AddItem(value))
1397		return false;
1398
1399	value->AcquireReference();
1400	return true;
1401}
1402
1403
1404// #pragma mark - DwarfSubrangeType
1405
1406
1407DwarfSubrangeType::DwarfSubrangeType(DwarfTypeContext* typeContext,
1408	const BString& name, DIESubrangeType* entry, Type* baseType,
1409	const BVariant& lowerBound, const BVariant& upperBound)
1410	:
1411	DwarfType(typeContext, name, entry),
1412	fEntry(entry),
1413	fBaseType(baseType),
1414	fLowerBound(lowerBound),
1415	fUpperBound(upperBound)
1416{
1417	fBaseType->AcquireReference();
1418}
1419
1420
1421DwarfSubrangeType::~DwarfSubrangeType()
1422{
1423	fBaseType->ReleaseReference();
1424}
1425
1426
1427Type*
1428DwarfSubrangeType::BaseType() const
1429{
1430	return fBaseType;
1431}
1432
1433
1434DIEType*
1435DwarfSubrangeType::GetDIEType() const
1436{
1437	return fEntry;
1438}
1439
1440
1441BVariant
1442DwarfSubrangeType::LowerBound() const
1443{
1444	return fLowerBound;
1445}
1446
1447
1448BVariant
1449DwarfSubrangeType::UpperBound() const
1450{
1451	return fUpperBound;
1452}
1453
1454
1455// #pragma mark - DwarfUnspecifiedType
1456
1457
1458DwarfUnspecifiedType::DwarfUnspecifiedType(DwarfTypeContext* typeContext,
1459	const BString& name, DIEUnspecifiedType* entry)
1460	:
1461	DwarfType(typeContext, name, entry),
1462	fEntry(entry)
1463{
1464}
1465
1466
1467DwarfUnspecifiedType::~DwarfUnspecifiedType()
1468{
1469}
1470
1471
1472DIEType*
1473DwarfUnspecifiedType::GetDIEType() const
1474{
1475	return fEntry;
1476}
1477
1478
1479// #pragma mark - DwarfFunctionType
1480
1481
1482DwarfFunctionType::DwarfFunctionType(DwarfTypeContext* typeContext,
1483	const BString& name, DIESubroutineType* entry, DwarfType* returnType)
1484	:
1485	DwarfType(typeContext, name, entry),
1486	fEntry(entry),
1487	fReturnType(returnType),
1488	fHasVariableArguments(false)
1489{
1490	if (fReturnType != NULL)
1491		fReturnType->AcquireReference();
1492}
1493
1494
1495DwarfFunctionType::~DwarfFunctionType()
1496{
1497	for (int32 i = 0;
1498		DwarfFunctionParameter* parameter = fParameters.ItemAt(i); i++) {
1499		parameter->ReleaseReference();
1500	}
1501
1502	if (fReturnType != NULL)
1503		fReturnType->ReleaseReference();
1504}
1505
1506
1507Type*
1508DwarfFunctionType::ReturnType() const
1509{
1510	return fReturnType;
1511}
1512
1513
1514int32
1515DwarfFunctionType::CountParameters() const
1516{
1517	return fParameters.CountItems();
1518}
1519
1520
1521FunctionParameter*
1522DwarfFunctionType::ParameterAt(int32 index) const
1523{
1524	return fParameters.ItemAt(index);
1525}
1526
1527
1528bool
1529DwarfFunctionType::HasVariableArguments() const
1530{
1531	return fHasVariableArguments;
1532}
1533
1534
1535void
1536DwarfFunctionType::SetHasVariableArguments(bool hasVarArgs)
1537{
1538	fHasVariableArguments = hasVarArgs;
1539}
1540
1541
1542DIEType*
1543DwarfFunctionType::GetDIEType() const
1544{
1545	return fEntry;
1546}
1547
1548
1549bool
1550DwarfFunctionType::AddParameter(DwarfFunctionParameter* parameter)
1551{
1552	if (!fParameters.AddItem(parameter))
1553		return false;
1554
1555	parameter->AcquireReference();
1556	return true;
1557}
1558
1559
1560// #pragma mark - DwarfPointerToMemberType
1561
1562
1563DwarfPointerToMemberType::DwarfPointerToMemberType(
1564	DwarfTypeContext* typeContext, const BString& name,
1565	DIEPointerToMemberType* entry, DwarfCompoundType* containingType,
1566	DwarfType* baseType)
1567	:
1568	DwarfType(typeContext, name, entry),
1569	fEntry(entry),
1570	fContainingType(containingType),
1571	fBaseType(baseType)
1572{
1573	fContainingType->AcquireReference();
1574	fBaseType->AcquireReference();
1575}
1576
1577
1578DwarfPointerToMemberType::~DwarfPointerToMemberType()
1579{
1580	fContainingType->ReleaseReference();
1581	fBaseType->ReleaseReference();
1582}
1583
1584
1585CompoundType*
1586DwarfPointerToMemberType::ContainingType() const
1587{
1588	return fContainingType;
1589}
1590
1591
1592Type*
1593DwarfPointerToMemberType::BaseType() const
1594{
1595	return fBaseType;
1596}
1597
1598
1599DIEType*
1600DwarfPointerToMemberType::GetDIEType() const
1601{
1602	return fEntry;
1603}
1604