1/*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2012, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "DwarfImageDebugInfo.h"
9
10#include <errno.h>
11#include <stdio.h>
12#include <unistd.h>
13
14#include <algorithm>
15#include <new>
16
17#include <AutoDeleter.h>
18#include <AutoLocker.h>
19
20#include "Architecture.h"
21#include "BasicFunctionDebugInfo.h"
22#include "CLanguage.h"
23#include "CompilationUnit.h"
24#include "CppLanguage.h"
25#include "CpuState.h"
26#include "DebuggerInterface.h"
27#include "DebugInfoEntries.h"
28#include "Demangler.h"
29#include "DisassembledCode.h"
30#include "Dwarf.h"
31#include "DwarfFile.h"
32#include "DwarfFunctionDebugInfo.h"
33#include "DwarfStackFrameDebugInfo.h"
34#include "DwarfTargetInterface.h"
35#include "DwarfTypeFactory.h"
36#include "DwarfTypes.h"
37#include "DwarfUtils.h"
38#include "ElfFile.h"
39#include "FileManager.h"
40#include "FileSourceCode.h"
41#include "FunctionID.h"
42#include "FunctionInstance.h"
43#include "GlobalTypeLookup.h"
44#include "Image.h"
45#include "ImageDebugInfo.h"
46#include "InstructionInfo.h"
47#include "LocatableFile.h"
48#include "Register.h"
49#include "RegisterMap.h"
50#include "SourceFile.h"
51#include "StackFrame.h"
52#include "Statement.h"
53#include "StringUtils.h"
54#include "SymbolInfo.h"
55#include "TargetAddressRangeList.h"
56#include "Team.h"
57#include "TeamMemory.h"
58#include "Tracing.h"
59#include "TypeLookupConstraints.h"
60#include "UnsupportedLanguage.h"
61#include "Variable.h"
62#include "ValueLocation.h"
63
64
65namespace {
66
67
68// #pragma mark - HasTypePredicate
69
70
71template<typename EntryType>
72struct HasTypePredicate {
73	inline bool operator()(EntryType* entry) const
74	{
75		return entry->GetType() != NULL;
76	}
77};
78
79}
80
81
82// #pragma mark - BasicTargetInterface
83
84
85struct DwarfImageDebugInfo::BasicTargetInterface : DwarfTargetInterface {
86	BasicTargetInterface(const Register* registers, int32 registerCount,
87		RegisterMap* fromDwarfMap, Architecture* architecture,
88		TeamMemory* teamMemory)
89		:
90		fRegisters(registers),
91		fRegisterCount(registerCount),
92		fFromDwarfMap(fromDwarfMap),
93		fArchitecture(architecture),
94		fTeamMemory(teamMemory)
95	{
96		fFromDwarfMap->AcquireReference();
97	}
98
99	~BasicTargetInterface()
100	{
101		fFromDwarfMap->ReleaseReference();
102	}
103
104	virtual uint32 CountRegisters() const
105	{
106		return fRegisterCount;
107	}
108
109	virtual uint32 RegisterValueType(uint32 index) const
110	{
111		const Register* reg = _RegisterAt(index);
112		return reg != NULL ? reg->ValueType() : 0;
113	}
114
115	virtual bool GetRegisterValue(uint32 index, BVariant& _value) const
116	{
117		return false;
118	}
119
120	virtual bool SetRegisterValue(uint32 index, const BVariant& value)
121	{
122		return false;
123	}
124
125	virtual bool IsCalleePreservedRegister(uint32 index) const
126	{
127		const Register* reg = _RegisterAt(index);
128		return reg != NULL && reg->IsCalleePreserved();
129	}
130
131	virtual status_t InitRegisterRules(CfaContext& context) const
132	{
133		return fArchitecture->InitRegisterRules(context);
134	}
135
136	virtual bool ReadMemory(target_addr_t address, void* buffer,
137		size_t size) const
138	{
139		ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, size);
140		return bytesRead >= 0 && (size_t)bytesRead == size;
141	}
142
143	virtual bool ReadValueFromMemory(target_addr_t address,
144		uint32 valueType, BVariant& _value) const
145	{
146		return fArchitecture->ReadValueFromMemory(address, valueType, _value)
147			== B_OK;
148	}
149
150	virtual bool ReadValueFromMemory(target_addr_t addressSpace,
151		target_addr_t address, uint32 valueType, BVariant& _value) const
152	{
153		return fArchitecture->ReadValueFromMemory(addressSpace, address,
154			valueType, _value) == B_OK;
155	}
156
157protected:
158	const Register* _RegisterAt(uint32 dwarfIndex) const
159	{
160		int32 index = fFromDwarfMap->MapRegisterIndex(dwarfIndex);
161		return index >= 0 && index < fRegisterCount ? fRegisters + index : NULL;
162	}
163
164protected:
165	const Register*	fRegisters;
166	int32			fRegisterCount;
167	RegisterMap*	fFromDwarfMap;
168	Architecture*	fArchitecture;
169	TeamMemory*		fTeamMemory;
170};
171
172
173// #pragma mark - UnwindTargetInterface
174
175
176struct DwarfImageDebugInfo::UnwindTargetInterface : BasicTargetInterface {
177	UnwindTargetInterface(const Register* registers, int32 registerCount,
178		RegisterMap* fromDwarfMap, RegisterMap* toDwarfMap, CpuState* cpuState,
179		Architecture* architecture, TeamMemory* teamMemory)
180		:
181		BasicTargetInterface(registers, registerCount, fromDwarfMap,
182			architecture, teamMemory),
183		fToDwarfMap(toDwarfMap),
184		fCpuState(cpuState)
185	{
186		fToDwarfMap->AcquireReference();
187		fCpuState->AcquireReference();
188	}
189
190	~UnwindTargetInterface()
191	{
192		fToDwarfMap->ReleaseReference();
193		fCpuState->ReleaseReference();
194	}
195
196	virtual bool GetRegisterValue(uint32 index, BVariant& _value) const
197	{
198		const Register* reg = _RegisterAt(index);
199		if (reg == NULL)
200			return false;
201		return fCpuState->GetRegisterValue(reg, _value);
202	}
203
204	virtual bool SetRegisterValue(uint32 index, const BVariant& value)
205	{
206		const Register* reg = _RegisterAt(index);
207		if (reg == NULL)
208			return false;
209		return fCpuState->SetRegisterValue(reg, value);
210	}
211
212private:
213	RegisterMap*	fToDwarfMap;
214	CpuState*		fCpuState;
215};
216
217
218// #pragma mark - EntryListWrapper
219
220
221/*!	Wraps a DebugInfoEntryList, which is a typedef and thus cannot appear in
222	the header, since our policy disallows us to include DWARF headers there.
223*/
224struct DwarfImageDebugInfo::EntryListWrapper {
225	const DebugInfoEntryList&	list;
226
227	EntryListWrapper(const DebugInfoEntryList& list)
228		:
229		list(list)
230	{
231	}
232};
233
234
235// #pragma mark - DwarfImageDebugInfo
236
237
238DwarfImageDebugInfo::DwarfImageDebugInfo(const ImageInfo& imageInfo,
239	DebuggerInterface* interface, Architecture* architecture,
240	FileManager* fileManager, GlobalTypeLookup* typeLookup,
241	GlobalTypeCache* typeCache, DwarfFile* file)
242	:
243	fLock("dwarf image debug info"),
244	fImageInfo(imageInfo),
245	fDebuggerInterface(interface),
246	fArchitecture(architecture),
247	fFileManager(fileManager),
248	fTypeLookup(typeLookup),
249	fTypeCache(typeCache),
250	fFile(file),
251	fTextSegment(NULL),
252	fRelocationDelta(0),
253	fTextSectionStart(0),
254	fTextSectionEnd(0),
255	fPLTSectionStart(0),
256	fPLTSectionEnd(0)
257{
258	fDebuggerInterface->AcquireReference();
259	fFile->AcquireReference();
260	fTypeCache->AcquireReference();
261}
262
263
264DwarfImageDebugInfo::~DwarfImageDebugInfo()
265{
266	fDebuggerInterface->ReleaseReference();
267	fFile->ReleaseReference();
268	fTypeCache->ReleaseReference();
269}
270
271
272status_t
273DwarfImageDebugInfo::Init()
274{
275	status_t error = fLock.InitCheck();
276	if (error != B_OK)
277		return error;
278
279	fTextSegment = fFile->GetElfFile()->TextSegment();
280	if (fTextSegment == NULL)
281		return B_ENTRY_NOT_FOUND;
282
283	fRelocationDelta = fImageInfo.TextBase() - fTextSegment->LoadAddress();
284
285	ElfSection* section = fFile->GetElfFile()->FindSection(".text");
286	if (section != NULL) {
287		fTextSectionStart = section->LoadAddress() + fRelocationDelta;
288		fTextSectionEnd = fTextSectionStart + section->Size();
289	}
290
291	section = fFile->GetElfFile()->FindSection(".plt");
292	if (section != NULL) {
293		fPLTSectionStart = section->LoadAddress() + fRelocationDelta;
294		fPLTSectionEnd = fPLTSectionStart + section->Size();
295	}
296
297	return B_OK;
298}
299
300
301status_t
302DwarfImageDebugInfo::GetFunctions(BObjectList<FunctionDebugInfo>& functions)
303{
304	TRACE_IMAGES("DwarfImageDebugInfo::GetFunctions()\n");
305	TRACE_IMAGES("  %" B_PRId32 " compilation units\n",
306		fFile->CountCompilationUnits());
307
308	for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i);
309			i++) {
310		DIECompileUnitBase* unitEntry = unit->UnitEntry();
311//		printf("  %s:\n", unitEntry->Name());
312//		printf("    address ranges:\n");
313//		TargetAddressRangeList* rangeList = unitEntry->AddressRanges();
314//		if (rangeList != NULL) {
315//			int32 count = rangeList->CountRanges();
316//			for (int32 i = 0; i < count; i++) {
317//				TargetAddressRange range = rangeList->RangeAt(i);
318//				printf("      %#llx - %#llx\n", range.Start(), range.End());
319//			}
320//		} else {
321//			printf("      %#llx - %#llx\n", (target_addr_t)unitEntry->LowPC(),
322//				(target_addr_t)unitEntry->HighPC());
323//		}
324
325//		printf("    functions:\n");
326		for (DebugInfoEntryList::ConstIterator it
327					= unitEntry->OtherChildren().GetIterator();
328				DebugInfoEntry* entry = it.Next();) {
329			if (entry->Tag() != DW_TAG_subprogram)
330				continue;
331
332			DIESubprogram* subprogramEntry = static_cast<DIESubprogram*>(entry);
333
334			// ignore declarations and inlined functions
335			if (subprogramEntry->IsDeclaration()
336				|| subprogramEntry->Inline() == DW_INL_inlined
337				|| subprogramEntry->Inline() == DW_INL_declared_inlined) {
338				continue;
339			}
340
341			// get the name
342			BString name;
343			DwarfUtils::GetFullyQualifiedDIEName(subprogramEntry, name);
344			if (name.Length() == 0)
345				continue;
346
347			// get the address ranges
348			TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit,
349				subprogramEntry->AddressRangesOffset());
350			if (rangeList == NULL) {
351				target_addr_t lowPC = subprogramEntry->LowPC();
352				target_addr_t highPC = subprogramEntry->HighPC();
353				if (lowPC >= highPC)
354					continue;
355
356				rangeList = new(std::nothrow) TargetAddressRangeList(
357					TargetAddressRange(lowPC, highPC - lowPC));
358				if (rangeList == NULL)
359					return B_NO_MEMORY;
360						// TODO: Clean up already added functions!
361			}
362			BReference<TargetAddressRangeList> rangeListReference(rangeList,
363				true);
364
365			// get the source location
366			const char* directoryPath = NULL;
367			const char* fileName = NULL;
368			int32 line = -1;
369			int32 column = -1;
370			DwarfUtils::GetDeclarationLocation(fFile, subprogramEntry,
371				directoryPath, fileName, line, column);
372
373			LocatableFile* file = NULL;
374			if (fileName != NULL) {
375				file = fFileManager->GetSourceFile(directoryPath,
376					fileName);
377			}
378			BReference<LocatableFile> fileReference(file, true);
379
380			// create and add the functions
381			DwarfFunctionDebugInfo* function
382				= new(std::nothrow) DwarfFunctionDebugInfo(this, unit,
383					subprogramEntry, rangeList, name, file,
384					SourceLocation(line, std::max(column, (int32)0)));
385			if (function == NULL || !functions.AddItem(function)) {
386				delete function;
387				return B_NO_MEMORY;
388					// TODO: Clean up already added functions!
389			}
390
391//			BString name;
392//			DwarfUtils::GetFullyQualifiedDIEName(subprogramEntry, name);
393//			printf("      subprogram entry: %p, name: %s, declaration: %d\n",
394//				subprogramEntry, name.String(),
395//				subprogramEntry->IsDeclaration());
396//
397//			rangeList = subprogramEntry->AddressRanges();
398//			if (rangeList != NULL) {
399//				int32 count = rangeList->CountRanges();
400//				for (int32 i = 0; i < count; i++) {
401//					TargetAddressRange range = rangeList->RangeAt(i);
402//					printf("        %#llx - %#llx\n", range.Start(), range.End());
403//				}
404//			} else {
405//				printf("        %#llx - %#llx\n",
406//					(target_addr_t)subprogramEntry->LowPC(),
407//					(target_addr_t)subprogramEntry->HighPC());
408//			}
409		}
410	}
411
412	if (fFile->CountCompilationUnits() != 0)
413		return B_OK;
414
415	// if we had no compilation units, fall back to providing basic
416	// debug infos with DWARF-supported call frame unwinding
417	return SpecificImageDebugInfo::GetFunctionsFromSymbols(functions,
418		fDebuggerInterface, fImageInfo, this);
419}
420
421
422status_t
423DwarfImageDebugInfo::GetType(GlobalTypeCache* cache,
424	const BString& name, const TypeLookupConstraints& constraints,
425	Type*& _type)
426{
427	int32 registerCount = fArchitecture->CountRegisters();
428	const Register* registers = fArchitecture->Registers();
429
430	// get the DWARF -> architecture register map
431	RegisterMap* fromDwarfMap;
432	status_t error = fArchitecture->GetDwarfRegisterMaps(NULL, &fromDwarfMap);
433	if (error != B_OK)
434		return error;
435	BReference<RegisterMap> fromDwarfMapReference(fromDwarfMap, true);
436
437	// create the target interface
438	BasicTargetInterface *inputInterface
439		= new(std::nothrow) BasicTargetInterface(registers, registerCount,
440			fromDwarfMap, fArchitecture, fDebuggerInterface);
441
442	if (inputInterface == NULL)
443		return B_NO_MEMORY;
444
445	BReference<BasicTargetInterface> inputInterfaceReference(inputInterface,
446		true);
447
448	// iterate through all compilation units
449	for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i);
450		i++) {
451		DwarfTypeContext* typeContext = NULL;
452		BReference<DwarfTypeContext> typeContextReference;
453
454		// iterate through all types of the compilation unit
455		for (DebugInfoEntryList::ConstIterator it
456				= unit->UnitEntry()->Types().GetIterator();
457			DIEType* typeEntry = dynamic_cast<DIEType*>(it.Next());) {
458			if (typeEntry->IsDeclaration())
459				continue;
460
461			if (constraints.HasTypeKind()) {
462				if (dwarf_tag_to_type_kind(typeEntry->Tag())
463					!= constraints.TypeKind())
464				continue;
465
466				if (!_EvaluateBaseTypeConstraints(typeEntry,
467					constraints))
468					continue;
469			}
470
471			if (constraints.HasSubtypeKind()
472				&& dwarf_tag_to_subtype_kind(typeEntry->Tag())
473					!= constraints.SubtypeKind())
474				continue;
475
476			BString typeEntryName;
477			DwarfUtils::GetFullyQualifiedDIEName(typeEntry, typeEntryName);
478			if (typeEntryName != name)
479				continue;
480
481			// The name matches and the entry is not just a declaration --
482			// create the type. First create the type context lazily.
483			if (typeContext == NULL) {
484				typeContext = new(std::nothrow)
485					DwarfTypeContext(fArchitecture, fImageInfo.ImageID(), fFile,
486					unit, NULL, 0, 0, fRelocationDelta, inputInterface,
487					fromDwarfMap);
488				if (typeContext == NULL)
489					return B_NO_MEMORY;
490				typeContextReference.SetTo(typeContext, true);
491			}
492
493			// create the type
494			DwarfType* type;
495			DwarfTypeFactory typeFactory(typeContext, fTypeLookup, cache);
496			error = typeFactory.CreateType(typeEntry, type);
497			if (error != B_OK)
498				continue;
499
500			_type = type;
501			return B_OK;
502		}
503	}
504
505	return B_ENTRY_NOT_FOUND;
506}
507
508
509AddressSectionType
510DwarfImageDebugInfo::GetAddressSectionType(target_addr_t address)
511{
512	if (address >= fTextSectionStart && address < fTextSectionEnd)
513		return ADDRESS_SECTION_TYPE_FUNCTION;
514
515 	if (address >= fPLTSectionStart && address < fPLTSectionEnd)
516		return ADDRESS_SECTION_TYPE_PLT;
517
518	return ADDRESS_SECTION_TYPE_UNKNOWN;
519}
520
521
522status_t
523DwarfImageDebugInfo::CreateFrame(Image* image,
524	FunctionInstance* functionInstance, CpuState* cpuState,
525	bool getFullFrameInfo, target_addr_t returnFunctionAddress,
526	StackFrame*& _frame, CpuState*& _previousCpuState)
527{
528	DwarfFunctionDebugInfo* function = dynamic_cast<DwarfFunctionDebugInfo*>(
529		functionInstance->GetFunctionDebugInfo());
530
531	FunctionID* functionID = functionInstance->GetFunctionID();
532	BReference<FunctionID> functionIDReference;
533	if (functionID != NULL)
534		functionIDReference.SetTo(functionID, true);
535
536	DIESubprogram* entry = function != NULL
537		? function->SubprogramEntry() : NULL;
538
539	TRACE_CFI("DwarfImageDebugInfo::CreateFrame(): subprogram DIE: %p, "
540		"function: %s\n", entry,
541		functionID->FunctionName().String());
542
543	int32 registerCount = fArchitecture->CountRegisters();
544	const Register* registers = fArchitecture->Registers();
545
546	// get the DWARF <-> architecture register maps
547	RegisterMap* toDwarfMap;
548	RegisterMap* fromDwarfMap;
549	status_t error = fArchitecture->GetDwarfRegisterMaps(&toDwarfMap,
550		&fromDwarfMap);
551	if (error != B_OK)
552		return error;
553	BReference<RegisterMap> toDwarfMapReference(toDwarfMap, true);
554	BReference<RegisterMap> fromDwarfMapReference(fromDwarfMap, true);
555
556	// create a clean CPU state for the previous frame
557	CpuState* previousCpuState;
558	error = fArchitecture->CreateCpuState(previousCpuState);
559	if (error != B_OK)
560		return error;
561	BReference<CpuState> previousCpuStateReference(previousCpuState, true);
562
563	// create the target interfaces
564	UnwindTargetInterface* inputInterface
565		= new(std::nothrow) UnwindTargetInterface(registers, registerCount,
566			fromDwarfMap, toDwarfMap, cpuState, fArchitecture,
567			fDebuggerInterface);
568	if (inputInterface == NULL)
569		return B_NO_MEMORY;
570	BReference<UnwindTargetInterface> inputInterfaceReference(inputInterface,
571		true);
572
573	UnwindTargetInterface* outputInterface
574		= new(std::nothrow) UnwindTargetInterface(registers, registerCount,
575			fromDwarfMap, toDwarfMap, previousCpuState, fArchitecture,
576			fDebuggerInterface);
577	if (outputInterface == NULL)
578		return B_NO_MEMORY;
579	BReference<UnwindTargetInterface> outputInterfaceReference(outputInterface,
580		true);
581
582	// do the unwinding
583	target_addr_t instructionPointer
584		= cpuState->InstructionPointer() - fRelocationDelta;
585	target_addr_t framePointer;
586	CompilationUnit* unit = function != NULL ? function->GetCompilationUnit()
587			: NULL;
588	error = fFile->UnwindCallFrame(unit, fArchitecture->AddressSize(), entry,
589		instructionPointer, inputInterface, outputInterface, framePointer);
590
591	if (error != B_OK) {
592		TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error));
593		return B_UNSUPPORTED;
594	}
595
596	TRACE_CFI_ONLY(
597		TRACE_CFI("unwound registers:\n");
598		for (int32 i = 0; i < registerCount; i++) {
599			const Register* reg = registers + i;
600			BVariant value;
601			if (previousCpuState->GetRegisterValue(reg, value)) {
602				TRACE_CFI("  %3s: %#" B_PRIx64 "\n", reg->Name(),
603					value.ToUInt64());
604			} else
605				TRACE_CFI("  %3s: undefined\n", reg->Name());
606		}
607	)
608
609	// create the stack frame debug info
610	DIESubprogram* subprogramEntry = function != NULL ?
611		function->SubprogramEntry() : NULL;
612	DwarfStackFrameDebugInfo* stackFrameDebugInfo
613		= new(std::nothrow) DwarfStackFrameDebugInfo(fArchitecture,
614			fImageInfo.ImageID(), fFile, unit, subprogramEntry, fTypeLookup,
615			fTypeCache, instructionPointer, framePointer, fRelocationDelta,
616			inputInterface, fromDwarfMap);
617	if (stackFrameDebugInfo == NULL)
618		return B_NO_MEMORY;
619	BReference<DwarfStackFrameDebugInfo> stackFrameDebugInfoReference(
620		stackFrameDebugInfo, true);
621
622	error = stackFrameDebugInfo->Init();
623	if (error != B_OK)
624		return error;
625
626	// create the stack frame
627	StackFrame* frame = new(std::nothrow) StackFrame(STACK_FRAME_TYPE_STANDARD,
628		cpuState, framePointer, cpuState->InstructionPointer(),
629		stackFrameDebugInfo);
630	if (frame == NULL)
631		return B_NO_MEMORY;
632	BReference<StackFrame> frameReference(frame, true);
633
634	error = frame->Init();
635	if (error != B_OK)
636		return error;
637
638	frame->SetReturnAddress(previousCpuState->InstructionPointer());
639		// Note, this is correct, since we actually retrieved the return
640		// address. Our caller will fix the IP for us.
641
642	// The subprogram entry may not be available since this may be a case
643	// where .eh_frame was used to unwind the stack without other DWARF
644	// info being available.
645	if (subprogramEntry != NULL && getFullFrameInfo) {
646		// create function parameter objects
647		for (DebugInfoEntryList::ConstIterator it
648			= subprogramEntry->Parameters().GetIterator();
649			DebugInfoEntry* entry = it.Next();) {
650			if (entry->Tag() != DW_TAG_formal_parameter)
651				continue;
652
653			BString parameterName;
654			DwarfUtils::GetDIEName(entry, parameterName);
655			if (parameterName.Length() == 0)
656				continue;
657
658			DIEFormalParameter* parameterEntry
659				= dynamic_cast<DIEFormalParameter*>(entry);
660			Variable* parameter;
661			if (stackFrameDebugInfo->CreateParameter(functionID,
662				parameterEntry, parameter) != B_OK) {
663				continue;
664			}
665			BReference<Variable> parameterReference(parameter, true);
666
667			if (!frame->AddParameter(parameter))
668				return B_NO_MEMORY;
669		}
670
671		// create objects for the local variables
672		_CreateLocalVariables(unit, frame, functionID, *stackFrameDebugInfo,
673			instructionPointer, functionInstance->Address() - fRelocationDelta,
674			subprogramEntry->Variables(), subprogramEntry->Blocks());
675
676		// TODO: re-enable once PIC and false positive issues
677		// are properly dealt with
678#if 0
679		if (returnFunctionAddress != 0) {
680			_CreateReturnValue(returnFunctionAddress, image, frame,
681				*stackFrameDebugInfo);
682		}
683#endif
684	}
685
686	_frame = frameReference.Detach();
687	_previousCpuState = previousCpuStateReference.Detach();
688
689	frame->SetPreviousCpuState(_previousCpuState);
690
691	return B_OK;
692}
693
694
695status_t
696DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* _function,
697	target_addr_t address, Statement*& _statement)
698{
699	TRACE_CODE("DwarfImageDebugInfo::GetStatement(function: %p, address: %#"
700		B_PRIx64 ")\n", _function, address);
701
702	DwarfFunctionDebugInfo* function
703		= dynamic_cast<DwarfFunctionDebugInfo*>(_function);
704	if (function == NULL) {
705		TRACE_LINES("  -> no dwarf function\n");
706		return B_BAD_VALUE;
707	}
708
709	AutoLocker<BLocker> locker(fLock);
710
711	// check whether we have the source code
712	CompilationUnit* unit = function->GetCompilationUnit();
713	LocatableFile* file = function->SourceFile();
714	if (file == NULL) {
715		TRACE_CODE("  -> no source file\n");
716
717		// no source code -- rather return the assembly statement
718		return fArchitecture->GetStatement(function, address, _statement);
719	}
720
721	// get the index of the source file in the compilation unit for cheaper
722	// comparison below
723	int32 fileIndex = _GetSourceFileIndex(unit, file);
724
725	// Get the statement by executing the line number program for the
726	// compilation unit.
727	LineNumberProgram& program = unit->GetLineNumberProgram();
728	if (!program.IsValid()) {
729		TRACE_CODE("  -> no line number program\n");
730		return B_BAD_DATA;
731	}
732
733	// adjust address
734	address -= fRelocationDelta;
735
736	LineNumberProgram::State state;
737	program.GetInitialState(state);
738
739	target_addr_t statementAddress = 0;
740	int32 statementLine = -1;
741	int32 statementColumn = -1;
742	while (program.GetNextRow(state)) {
743		// skip statements of other files
744		if (state.file != fileIndex)
745			continue;
746
747		if (statementAddress != 0
748			&& (state.isStatement || state.isSequenceEnd)) {
749			target_addr_t endAddress = state.address;
750			if (address >= statementAddress && address < endAddress) {
751				ContiguousStatement* statement = new(std::nothrow)
752					ContiguousStatement(
753						SourceLocation(statementLine, statementColumn),
754						TargetAddressRange(fRelocationDelta + statementAddress,
755							endAddress - statementAddress));
756				if (statement == NULL)
757					return B_NO_MEMORY;
758
759				_statement = statement;
760				return B_OK;
761			}
762
763			statementAddress = 0;
764		}
765
766		if (state.isStatement) {
767			statementAddress = state.address;
768			statementLine = state.line - 1;
769			statementColumn = std::max(state.column - 1, (int32)0);
770		}
771	}
772
773	TRACE_CODE("  -> no line number program match\n");
774	return B_ENTRY_NOT_FOUND;
775}
776
777
778status_t
779DwarfImageDebugInfo::GetStatementAtSourceLocation(FunctionDebugInfo* _function,
780	const SourceLocation& sourceLocation, Statement*& _statement)
781{
782	DwarfFunctionDebugInfo* function
783		= dynamic_cast<DwarfFunctionDebugInfo*>(_function);
784	if (function == NULL)
785		return B_BAD_VALUE;
786
787	target_addr_t functionStartAddress = function->Address() - fRelocationDelta;
788	target_addr_t functionEndAddress = functionStartAddress + function->Size();
789
790	TRACE_LINES2("DwarfImageDebugInfo::GetStatementAtSourceLocation(%p, "
791		"(%" B_PRId32 ", %" B_PRId32 ")): function range: %#" B_PRIx64 " - %#"
792		B_PRIx64 "\n", function, sourceLocation.Line(), sourceLocation.Column(),
793		functionStartAddress, functionEndAddress);
794
795	AutoLocker<BLocker> locker(fLock);
796
797	// get the source file
798	LocatableFile* file = function->SourceFile();
799	if (file == NULL)
800		return B_ENTRY_NOT_FOUND;
801
802	CompilationUnit* unit = function->GetCompilationUnit();
803
804	// get the index of the source file in the compilation unit for cheaper
805	// comparison below
806	int32 fileIndex = _GetSourceFileIndex(unit, file);
807
808	// Get the statement by executing the line number program for the
809	// compilation unit.
810	LineNumberProgram& program = unit->GetLineNumberProgram();
811	if (!program.IsValid())
812		return B_BAD_DATA;
813
814	LineNumberProgram::State state;
815	program.GetInitialState(state);
816
817	target_addr_t statementAddress = 0;
818	int32 statementLine = -1;
819	int32 statementColumn = -1;
820	while (program.GetNextRow(state)) {
821		bool isOurFile = state.file == fileIndex;
822
823		if (statementAddress != 0
824			&& (!isOurFile || state.isStatement || state.isSequenceEnd)) {
825			target_addr_t endAddress = state.address;
826
827			if (statementAddress < endAddress) {
828				TRACE_LINES2("  statement: %#" B_PRIx64 " - %#" B_PRIx64
829					", location: (%" B_PRId32 ", %" B_PRId32 ")\n",
830					statementAddress, endAddress, statementLine,
831				 	statementColumn);
832			}
833
834			if (statementAddress < endAddress
835				&& statementAddress >= functionStartAddress
836				&& statementAddress < functionEndAddress
837				&& statementLine == (int32)sourceLocation.Line()
838				&& statementColumn == (int32)sourceLocation.Column()) {
839				TRACE_LINES2("  -> found statement!\n");
840
841				ContiguousStatement* statement = new(std::nothrow)
842					ContiguousStatement(
843						SourceLocation(statementLine, statementColumn),
844						TargetAddressRange(fRelocationDelta + statementAddress,
845							endAddress - statementAddress));
846				if (statement == NULL)
847					return B_NO_MEMORY;
848
849				_statement = statement;
850				return B_OK;
851			}
852
853			statementAddress = 0;
854		}
855
856		// skip statements of other files
857		if (!isOurFile)
858			continue;
859
860		if (state.isStatement) {
861			statementAddress = state.address;
862			statementLine = state.line - 1;
863			statementColumn = std::max(state.column - 1, (int32)0);
864		}
865	}
866
867	return B_ENTRY_NOT_FOUND;
868}
869
870
871status_t
872DwarfImageDebugInfo::GetSourceLanguage(FunctionDebugInfo* _function,
873	SourceLanguage*& _language)
874{
875	DwarfFunctionDebugInfo* function
876		= dynamic_cast<DwarfFunctionDebugInfo*>(_function);
877	if (function == NULL)
878		return B_BAD_VALUE;
879
880	SourceLanguage* language;
881	CompilationUnit* unit = function->GetCompilationUnit();
882	switch (unit->UnitEntry()->Language()) {
883		case DW_LANG_C89:
884		case DW_LANG_C:
885		case DW_LANG_C99:
886			language = new(std::nothrow) CLanguage;
887			break;
888		case DW_LANG_C_plus_plus:
889			language = new(std::nothrow) CppLanguage;
890			break;
891		case 0:
892		default:
893			language = new(std::nothrow) UnsupportedLanguage;
894			break;
895	}
896
897	if (language == NULL)
898		return B_NO_MEMORY;
899
900	_language = language;
901	return B_OK;
902}
903
904
905ssize_t
906DwarfImageDebugInfo::ReadCode(target_addr_t address, void* buffer, size_t size)
907{
908	target_addr_t offset = address - fRelocationDelta
909		- fTextSegment->LoadAddress() + fTextSegment->FileOffset();
910	ssize_t bytesRead = pread(fFile->GetElfFile()->FD(), buffer, size, offset);
911	return bytesRead >= 0 ? bytesRead : errno;
912}
913
914
915status_t
916DwarfImageDebugInfo::AddSourceCodeInfo(LocatableFile* file,
917	FileSourceCode* sourceCode)
918{
919	bool addedAny = false;
920	for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i);
921			i++) {
922		int32 fileIndex = _GetSourceFileIndex(unit, file);
923		if (fileIndex < 0)
924			continue;
925
926		status_t error = _AddSourceCodeInfo(unit, sourceCode, fileIndex);
927		if (error == B_NO_MEMORY)
928			return error;
929		addedAny |= error == B_OK;
930	}
931
932	return addedAny ? B_OK : B_ENTRY_NOT_FOUND;
933}
934
935
936status_t
937DwarfImageDebugInfo::_AddSourceCodeInfo(CompilationUnit* unit,
938	FileSourceCode* sourceCode, int32 fileIndex)
939{
940	// Get the statements by executing the line number program for the
941	// compilation unit and filtering the rows for our source file.
942	LineNumberProgram& program = unit->GetLineNumberProgram();
943	if (!program.IsValid())
944		return B_BAD_DATA;
945
946	LineNumberProgram::State state;
947	program.GetInitialState(state);
948
949	target_addr_t statementAddress = 0;
950	int32 statementLine = -1;
951	int32 statementColumn = -1;
952	while (program.GetNextRow(state)) {
953		TRACE_LINES2("  %#" B_PRIx64 "  (%" B_PRId32 ", %" B_PRId32 ", %"
954			B_PRId32 ")  %d\n", state.address, state.file, state.line,
955			state.column, state.isStatement);
956
957		bool isOurFile = state.file == fileIndex;
958
959		if (statementAddress != 0
960			&& (!isOurFile || state.isStatement || state.isSequenceEnd)) {
961			target_addr_t endAddress = state.address;
962			if (endAddress > statementAddress) {
963				// add the statement
964				status_t error = sourceCode->AddSourceLocation(
965					SourceLocation(statementLine, statementColumn));
966				if (error != B_OK)
967					return error;
968
969				TRACE_LINES2("  -> statement: %#" B_PRIx64 " - %#" B_PRIx64
970					", source location: (%" B_PRId32 ", %" B_PRId32 ")\n",
971					statementAddress, endAddress, statementLine,
972				 	statementColumn);
973			}
974
975			statementAddress = 0;
976		}
977
978		// skip statements of other files
979		if (!isOurFile)
980			continue;
981
982		if (state.isStatement) {
983			statementAddress = state.address;
984			statementLine = state.line - 1;
985			statementColumn = std::max(state.column - 1, (int32)0);
986		}
987	}
988
989	return B_OK;
990}
991
992
993int32
994DwarfImageDebugInfo::_GetSourceFileIndex(CompilationUnit* unit,
995	LocatableFile* sourceFile) const
996{
997	// get the index of the source file in the compilation unit for cheaper
998	// comparison below
999	const char* directory;
1000	for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) {
1001		LocatableFile* file = fFileManager->GetSourceFile(directory, fileName);
1002		if (file != NULL) {
1003			file->ReleaseReference();
1004			if (file == sourceFile) {
1005				return i + 1;
1006					// indices are one-based
1007			}
1008		}
1009	}
1010
1011	return -1;
1012}
1013
1014
1015status_t
1016DwarfImageDebugInfo::_CreateLocalVariables(CompilationUnit* unit,
1017	StackFrame* frame, FunctionID* functionID,
1018	DwarfStackFrameDebugInfo& factory, target_addr_t instructionPointer,
1019	target_addr_t lowPC, const EntryListWrapper& variableEntries,
1020	const EntryListWrapper& blockEntries)
1021{
1022	TRACE_LOCALS("DwarfImageDebugInfo::_CreateLocalVariables(): ip: %#" B_PRIx64
1023		", low PC: %#" B_PRIx64 "\n", instructionPointer, lowPC);
1024
1025	// iterate through the variables and add the ones in scope
1026	for (DebugInfoEntryList::ConstIterator it
1027			= variableEntries.list.GetIterator();
1028		DIEVariable* variableEntry = dynamic_cast<DIEVariable*>(it.Next());) {
1029
1030		TRACE_LOCALS("  variableEntry %p, scope start: %" B_PRIu64 "\n",
1031			variableEntry, variableEntry->StartScope());
1032
1033		// check the variable's scope
1034		if (instructionPointer < lowPC + variableEntry->StartScope())
1035			continue;
1036
1037		// add the variable
1038		Variable* variable;
1039		if (factory.CreateLocalVariable(functionID, variableEntry, variable)
1040				!= B_OK) {
1041			continue;
1042		}
1043		BReference<Variable> variableReference(variable, true);
1044
1045		if (!frame->AddLocalVariable(variable))
1046			return B_NO_MEMORY;
1047	}
1048
1049	// iterate through the blocks and find the one we're currently in (if any)
1050	for (DebugInfoEntryList::ConstIterator it = blockEntries.list.GetIterator();
1051		DIELexicalBlock* block = dynamic_cast<DIELexicalBlock*>(it.Next());) {
1052
1053		TRACE_LOCALS("  lexical block: %p\n", block);
1054
1055		// check whether the block has low/high PC attributes
1056		if (block->LowPC() != 0) {
1057			TRACE_LOCALS("    has lowPC\n");
1058
1059			// yep, compare with the instruction pointer
1060			if (instructionPointer < block->LowPC()
1061				|| instructionPointer >= block->HighPC()) {
1062				continue;
1063			}
1064		} else {
1065			TRACE_LOCALS("    no lowPC\n");
1066
1067			// check the address ranges instead
1068			TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit,
1069				block->AddressRangesOffset());
1070			if (rangeList == NULL) {
1071				TRACE_LOCALS("    failed to get ranges\n");
1072				continue;
1073			}
1074			BReference<TargetAddressRangeList> rangeListReference(rangeList,
1075				true);
1076
1077			if (!rangeList->Contains(instructionPointer)) {
1078				TRACE_LOCALS("    ranges don't contain IP\n");
1079				continue;
1080			}
1081		}
1082
1083		// found a block -- recurse
1084		return _CreateLocalVariables(unit, frame, functionID, factory,
1085			instructionPointer, lowPC, block->Variables(), block->Blocks());
1086	}
1087
1088	return B_OK;
1089}
1090
1091
1092status_t
1093DwarfImageDebugInfo::_CreateReturnValue(target_addr_t returnFunctionAddress,
1094	Image* image, StackFrame* frame, DwarfStackFrameDebugInfo& factory)
1095{
1096	if (!image->ContainsAddress(returnFunctionAddress)) {
1097		// our current image doesn't contain the target function,
1098		// locate the one which does.
1099		image = image->GetTeam()->ImageByAddress(returnFunctionAddress);
1100		if (image == NULL)
1101			return B_BAD_VALUE;
1102	}
1103
1104	status_t result = B_OK;
1105	FunctionInstance* targetFunction;
1106	if (returnFunctionAddress >= fPLTSectionStart
1107		&& returnFunctionAddress < fPLTSectionEnd) {
1108		// TODO: handle resolving PLT entries
1109		// to their target function
1110		return B_UNSUPPORTED;
1111	}
1112
1113	ImageDebugInfo* imageInfo = image->GetImageDebugInfo();
1114	targetFunction = imageInfo->FunctionAtAddress(returnFunctionAddress);
1115	if (targetFunction != NULL) {
1116		DwarfFunctionDebugInfo* targetInfo =
1117			dynamic_cast<DwarfFunctionDebugInfo*>(
1118				targetFunction->GetFunctionDebugInfo());
1119		if (targetInfo != NULL) {
1120			DIESubprogram* subProgram = targetInfo->SubprogramEntry();
1121			DIEType* returnType = subProgram->ReturnType();
1122			if (returnType == NULL) {
1123				// check if we have a specification, and if so, if that has
1124				// a return type
1125				subProgram = dynamic_cast<DIESubprogram*>(subProgram->Specification());
1126				if (subProgram != NULL)
1127					returnType = subProgram->ReturnType();
1128
1129				// function doesn't return a value, we're done.
1130				if (returnType == NULL)
1131					return B_OK;
1132			}
1133
1134			uint32 byteSize = 0;
1135			if (returnType->ByteSize() == NULL) {
1136				if (dynamic_cast<DIEAddressingType*>(returnType) != NULL)
1137					byteSize = fArchitecture->AddressSize();
1138			} else
1139				byteSize = returnType->ByteSize()->constant;
1140
1141			ValueLocation* location;
1142			result = fArchitecture->GetReturnAddressLocation(frame,
1143				byteSize, location);
1144			if (result != B_OK)
1145				return result;
1146
1147			BReference<ValueLocation> locationReference(location, true);
1148			Variable* variable = NULL;
1149			BReference<FunctionID> idReference(
1150				targetFunction->GetFunctionID(), true);
1151			result = factory.CreateReturnValue(idReference, returnType,
1152				location, variable);
1153			if (result != B_OK)
1154				return result;
1155
1156			BReference<Variable> variableReference(variable, true);
1157			if (!frame->AddLocalVariable(variable))
1158				return B_NO_MEMORY;
1159		}
1160	}
1161
1162	return B_OK;
1163}
1164
1165
1166bool
1167DwarfImageDebugInfo::_EvaluateBaseTypeConstraints(DIEType* type,
1168	const TypeLookupConstraints& constraints)
1169{
1170	if (constraints.HasBaseTypeName()) {
1171		BString baseEntryName;
1172		DIEType* baseTypeOwnerEntry = NULL;
1173
1174		switch (constraints.TypeKind()) {
1175			case TYPE_ADDRESS:
1176			{
1177				DIEAddressingType* addressType =
1178					dynamic_cast<DIEAddressingType*>(type);
1179				if (addressType != NULL) {
1180					baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate(
1181						addressType, HasTypePredicate<DIEAddressingType>());
1182				}
1183				break;
1184			}
1185			case TYPE_ARRAY:
1186			{
1187				DIEArrayType* arrayType =
1188					dynamic_cast<DIEArrayType*>(type);
1189				if (arrayType != NULL) {
1190					baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate(
1191						arrayType, HasTypePredicate<DIEArrayType>());
1192				}
1193				break;
1194			}
1195			default:
1196				break;
1197		}
1198
1199		if (baseTypeOwnerEntry != NULL) {
1200			DwarfUtils::GetFullyQualifiedDIEName(baseTypeOwnerEntry,
1201				baseEntryName);
1202
1203			if (baseEntryName != constraints.BaseTypeName())
1204				return false;
1205		}
1206	}
1207
1208	return true;
1209}
1210