/*
 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Copyright 2012-2018, Rene Gollent, rene@gollent.com.
 * Distributed under the terms of the MIT License.
 */
 
 
#include "DwarfImageDebugInfo.h"
 
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
 
#include <algorithm>
#include <new>
 
#include <AutoDeleter.h>
#include <AutoLocker.h>
 
#include "Architecture.h"
#include "BasicFunctionDebugInfo.h"
#include "CLanguage.h"
#include "CompilationUnit.h"
#include "CppLanguage.h"
#include "CpuState.h"
#include "DebuggerInterface.h"
#include "DebugInfoEntries.h"
#include "Demangler.h"
#include "DisassembledCode.h"
#include "Dwarf.h"
#include "DwarfFile.h"
#include "DwarfFunctionDebugInfo.h"
#include "DwarfStackFrameDebugInfo.h"
#include "DwarfTargetInterface.h"
#include "DwarfTypeFactory.h"
#include "DwarfTypes.h"
#include "DwarfUtils.h"
#include "ElfFile.h"
#include "FileManager.h"
#include "FileSourceCode.h"
#include "FunctionID.h"
#include "FunctionInstance.h"
#include "GlobalTypeLookup.h"
#include "Image.h"
#include "ImageDebugInfo.h"
#include "InstructionInfo.h"
#include "LocatableFile.h"
#include "Register.h"
#include "RegisterMap.h"
#include "SourceFile.h"
#include "StackFrame.h"
#include "Statement.h"
#include "StringUtils.h"
#include "SymbolInfo.h"
#include "TargetAddressRangeList.h"
#include "Team.h"
#include "TeamFunctionSourceInformation.h"
#include "TeamMemory.h"
#include "Tracing.h"
#include "TypeLookupConstraints.h"
#include "UnsupportedLanguage.h"
#include "Variable.h"
#include "ValueLocation.h"
 
 
namespace {
 
 
// #pragma mark - HasTypePredicate
 
 
template<typename EntryType>
struct HasTypePredicate {
	inline bool operator()(EntryType* entry) const
	{
		return entry->GetType() != NULL;
	}
};
 
}
 
 
// #pragma mark - BasicTargetInterface
 
 
struct DwarfImageDebugInfo::BasicTargetInterface : DwarfTargetInterface {
	BasicTargetInterface(const Register* registers, int32 registerCount,
		RegisterMap* fromDwarfMap, Architecture* architecture,
		TeamMemory* teamMemory)
		:
		fRegisters(registers),
		fRegisterCount(registerCount),
		fFromDwarfMap(fromDwarfMap),
		fArchitecture(architecture),
		fTeamMemory(teamMemory)
	{
		fFromDwarfMap->AcquireReference();
	}
 
	~BasicTargetInterface()
	{
		fFromDwarfMap->ReleaseReference();
	}
 
	virtual uint32 CountRegisters() const
	{
		return fRegisterCount;
	}
 
	virtual uint32 RegisterValueType(uint32 index) const
	{
		const Register* reg = _RegisterAt(index);
		return reg != NULL ? reg->ValueType() : 0;
	}
 
	virtual bool GetRegisterValue(uint32 index, BVariant& _value) const
	{
		return false;
	}
 
	virtual bool SetRegisterValue(uint32 index, const BVariant& value)
	{
		return false;
	}
 
	virtual bool IsCalleePreservedRegister(uint32 index) const
	{
		const Register* reg = _RegisterAt(index);
		return reg != NULL && reg->IsCalleePreserved();
	}
 
	virtual status_t InitRegisterRules(CfaContext& context) const
	{
		return fArchitecture->InitRegisterRules(context);
	}
 
	virtual bool ReadMemory(target_addr_t address, void* buffer,
		size_t size) const
	{
		ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, size);
		return bytesRead >= 0 && (size_t)bytesRead == size;
	}
 
	virtual bool ReadValueFromMemory(target_addr_t address,
		uint32 valueType, BVariant& _value) const
	{
		return fArchitecture->ReadValueFromMemory(address, valueType, _value)
			== B_OK;
	}
 
	virtual bool ReadValueFromMemory(target_addr_t addressSpace,
		target_addr_t address, uint32 valueType, BVariant& _value) const
	{
		return fArchitecture->ReadValueFromMemory(addressSpace, address,
			valueType, _value) == B_OK;
	}
 
protected:
	const Register* _RegisterAt(uint32 dwarfIndex) const
	{
		int32 index = fFromDwarfMap->MapRegisterIndex(dwarfIndex);
		return index >= 0 && index < fRegisterCount ? fRegisters + index : NULL;
	}
 
protected:
	const Register*	fRegisters;
	int32			fRegisterCount;
	RegisterMap*	fFromDwarfMap;
	Architecture*	fArchitecture;
	TeamMemory*		fTeamMemory;
};
 
 
// #pragma mark - UnwindTargetInterface
 
 
struct DwarfImageDebugInfo::UnwindTargetInterface : BasicTargetInterface {
	UnwindTargetInterface(const Register* registers, int32 registerCount,
		RegisterMap* fromDwarfMap, RegisterMap* toDwarfMap, CpuState* cpuState,
		Architecture* architecture, TeamMemory* teamMemory)
		:
		BasicTargetInterface(registers, registerCount, fromDwarfMap,
			architecture, teamMemory),
		fToDwarfMap(toDwarfMap),
		fCpuState(cpuState)
	{
		fToDwarfMap->AcquireReference();
		fCpuState->AcquireReference();
	}
 
	~UnwindTargetInterface()
	{
		fToDwarfMap->ReleaseReference();
		fCpuState->ReleaseReference();
	}
 
	virtual bool GetRegisterValue(uint32 index, BVariant& _value) const
	{
		const Register* reg = _RegisterAt(index);
		if (reg == NULL)
			return false;
		return fCpuState->GetRegisterValue(reg, _value);
	}
 
	virtual bool SetRegisterValue(uint32 index, const BVariant& value)
	{
		const Register* reg = _RegisterAt(index);
		if (reg == NULL)
			return false;
		return fCpuState->SetRegisterValue(reg, value);
	}
 
private:
	RegisterMap*	fToDwarfMap;
	CpuState*		fCpuState;
};
 
 
// #pragma mark - EntryListWrapper
 
 
/*!	Wraps a DebugInfoEntryList, which is a typedef and thus cannot appear in
	the header, since our policy disallows us to include DWARF headers there.
*/
struct DwarfImageDebugInfo::EntryListWrapper {
	const DebugInfoEntryList&	list;
 
	EntryListWrapper(const DebugInfoEntryList& list)
		:
		list(list)
	{
	}
};
 
 
// #pragma mark - DwarfImageDebugInfo::TypeNameKey
 
 
struct DwarfImageDebugInfo::TypeNameKey {
	BString			typeName;
 
	TypeNameKey(const BString& typeName)
		:
		typeName(typeName)
	{
	}
 
	uint32 HashValue() const
	{
		return StringUtils::HashValue(typeName);
	}
 
	bool operator==(const TypeNameKey& other) const
	{
		return typeName == other.typeName;
	}
};
 
 
// #pragma mark - DwarfImageDebugInfo::TypeNameEntry
 
 
struct DwarfImageDebugInfo::TypeNameEntry : TypeNameKey {
	TypeNameEntry* next;
	TypeEntryList types;
 
	TypeNameEntry(const BString& name)
		:
		TypeNameKey(name),
		types(10, true)
	{
	}
 
	~TypeNameEntry()
	{
	}
 
};
 
 
// #pragma mark - DwarfImageDebugInfo::TypeNameEntryHashDefinition
 
 
struct DwarfImageDebugInfo::TypeNameEntryHashDefinition {
	typedef TypeNameKey		KeyType;
	typedef	TypeNameEntry	ValueType;
 
	size_t HashKey(const TypeNameKey& key) const
	{
		return key.HashValue();
	}
 
	size_t Hash(const TypeNameEntry* value) const
	{
		return value->HashValue();
	}
 
	bool Compare(const TypeNameKey& key,
		const TypeNameEntry* value) const
	{
		return key == *value;
	}
 
	TypeNameEntry*& GetLink(TypeNameEntry* value) const
	{
		return value->next;
	}
};
 
 
// #pragma mark - DwarfImageDebugInfo::TypeEntryInfo
 
 
struct DwarfImageDebugInfo::TypeEntryInfo {
	DIEType* type;
	CompilationUnit* unit;
 
	TypeEntryInfo(DIEType* type, CompilationUnit* unit)
		:
		type(type),
		unit(unit)
	{
	}
};
 
 
// #pragma mark - DwarfImageDebugInfo
 
 
DwarfImageDebugInfo::DwarfImageDebugInfo(const ImageInfo& imageInfo,
	DebuggerInterface* interface, Architecture* architecture,
	FileManager* fileManager, GlobalTypeLookup* typeLookup,
	GlobalTypeCache* typeCache, TeamFunctionSourceInformation* sourceInfo,
	DwarfFile* file)
	:
	fLock("dwarf image debug info"),
	fImageInfo(imageInfo),
	fDebuggerInterface(interface),
	fArchitecture(architecture),
	fFileManager(fileManager),
	fTypeLookup(typeLookup),
	fTypeCache(typeCache),
	fSourceInfo(sourceInfo),
	fTypeNameTable(NULL),
	fFile(file),
	fTextSegment(NULL),
	fRelocationDelta(0),
	fTextSectionStart(0),
	fTextSectionEnd(0),
	fPLTSectionStart(0),
	fPLTSectionEnd(0)
{
	fDebuggerInterface->AcquireReference();
	fFile->AcquireReference();
	fTypeCache->AcquireReference();
}
 
 
DwarfImageDebugInfo::~DwarfImageDebugInfo()
{
	fDebuggerInterface->ReleaseReference();
	fFile->ReleaseReference();
	fTypeCache->ReleaseReference();
 
	TypeNameEntry* entry = fTypeNameTable->Clear(true);
	while (entry != NULL) {
		TypeNameEntry* next = entry->next;
		delete entry;
		entry = next;
	}
	delete fTypeNameTable;
}
 
 
status_t
DwarfImageDebugInfo::Init()
{
	status_t error = fLock.InitCheck();
	if (error != B_OK)
		return error;
 
	fTextSegment = fFile->GetElfFile()->TextSegment();
	if (fTextSegment == NULL)
		return B_ENTRY_NOT_FOUND;
 
	fRelocationDelta = fImageInfo.TextBase() - fTextSegment->LoadAddress();
 
	ElfSection* section = fFile->GetElfFile()->FindSection(".text");
	if (section != NULL) {
		fTextSectionStart = section->LoadAddress() + fRelocationDelta;
		fTextSectionEnd = fTextSectionStart + section->Size();
	}
 
	section = fFile->GetElfFile()->FindSection(".plt");
	if (section != NULL) {
		fPLTSectionStart = section->LoadAddress() + fRelocationDelta;
		fPLTSectionEnd = fPLTSectionStart + section->Size();
	}
 
	return _BuildTypeNameTable();
}
 
 
status_t
DwarfImageDebugInfo::GetFunctions(const BObjectList<SymbolInfo>& symbols,
	BObjectList<FunctionDebugInfo>& functions)
{
	TRACE_IMAGES("DwarfImageDebugInfo::GetFunctions()\n");
	TRACE_IMAGES("  %" B_PRId32 " compilation units\n",
		fFile->CountCompilationUnits());
 
	status_t error = B_OK;
	for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i);
			i++) {
		DIECompileUnitBase* unitEntry = unit->UnitEntry();
//		printf("  %s:\n", unitEntry->Name());
//		printf("    address ranges:\n");
//		TargetAddressRangeList* rangeList = unitEntry->AddressRanges();
//		if (rangeList != NULL) {
//			int32 count = rangeList->CountRanges();
//			for (int32 i = 0; i < count; i++) {
//				TargetAddressRange range = rangeList->RangeAt(i);
//				printf("      %#llx - %#llx\n", range.Start(), range.End());
//			}
//		} else {
//			printf("      %#llx - %#llx\n", (target_addr_t)unitEntry->LowPC(),
//				(target_addr_t)unitEntry->HighPC());
//		}
 
//		printf("    functions:\n");
		for (DebugInfoEntryList::ConstIterator it
					= unitEntry->OtherChildren().GetIterator();
				DebugInfoEntry* entry = it.Next();) {
			if (entry->Tag() == DW_TAG_subprogram) {
				DIESubprogram* subprogramEntry
					= static_cast<DIESubprogram*>(entry);
				error = _AddFunction(subprogramEntry, unit, functions);
				if (error != B_OK)
					return error;
			}
 
			DIENamespace* nsEntry = dynamic_cast<DIENamespace*>(entry);
			if (nsEntry != NULL) {
				error = _RecursiveTraverseNamespaceForFunctions(nsEntry, unit,
					functions);
				if (error != B_OK)
					return error;
			}
		}
	}
 
	if (fFile->CountCompilationUnits() != 0)
		return B_OK;
 
	// if we had no compilation units, fall back to providing basic
	// debug infos with DWARF-supported call frame unwinding,
	// if available.
	if (fFile->HasFrameInformation()) {
		return SpecificImageDebugInfo::GetFunctionsFromSymbols(symbols,
			functions, fDebuggerInterface, fImageInfo, this);
	}
 
	return B_OK;
}
 
 
status_t
DwarfImageDebugInfo::GetType(GlobalTypeCache* cache, const BString& name,
	const TypeLookupConstraints& constraints, Type*& _type)
{
	TypeNameEntry* entry = fTypeNameTable->Lookup(name);
	if (entry == NULL)
		return B_ENTRY_NOT_FOUND;
 
	for (int32 i = 0; TypeEntryInfo* info = entry->types.ItemAt(i); i++) {
		DIEType* typeEntry = info->type;
		if (constraints.HasTypeKind()) {
			if (dwarf_tag_to_type_kind(typeEntry->Tag())
				!= constraints.TypeKind()) {
				continue;
			}
 
			if (!_EvaluateBaseTypeConstraints(typeEntry, constraints))
				continue;
		}
 
		if (constraints.HasSubtypeKind()
			&& dwarf_tag_to_subtype_kind(typeEntry->Tag())
				!= constraints.SubtypeKind()) {
			continue;
		}
 
		int32 registerCount = fArchitecture->CountRegisters();
		const Register* registers = fArchitecture->Registers();
 
		// get the DWARF <-> architecture register maps
		RegisterMap* toDwarfMap;
		RegisterMap* fromDwarfMap;
		status_t error = fArchitecture->GetDwarfRegisterMaps(&toDwarfMap,
			&fromDwarfMap);
		if (error != B_OK)
			return error;
 
		BReference<RegisterMap> toDwarfMapReference(toDwarfMap, true);
		BReference<RegisterMap> fromDwarfMapReference(fromDwarfMap, true);
 
		// create the target interface
		BasicTargetInterface* targetInterface
			= new(std::nothrow) BasicTargetInterface(registers, registerCount,
				fromDwarfMap, fArchitecture, fDebuggerInterface);
		if (targetInterface == NULL)
			return B_NO_MEMORY;
 
		BReference<BasicTargetInterface> targetInterfaceReference(
			targetInterface, true);
 
		DwarfTypeContext* typeContext = new(std::nothrow)
			DwarfTypeContext(fArchitecture, fImageInfo.ImageID(), fFile,
				info->unit, NULL, 0, 0, fRelocationDelta, targetInterface, NULL);
		if (typeContext == NULL)
			return B_NO_MEMORY;
		BReference<DwarfTypeContext> typeContextReference(typeContext, true);
 
		// create the type
		DwarfType* type;
		DwarfTypeFactory typeFactory(typeContext, fTypeLookup, cache);
		error = typeFactory.CreateType(typeEntry, type);
		if (error != B_OK)
			continue;
 
		_type = type;
		return B_OK;
	}
 
	return B_ENTRY_NOT_FOUND;
}
 
 
bool
DwarfImageDebugInfo::HasType(const BString& name,
	const TypeLookupConstraints& constraints) const
{
	TypeNameEntry* entry = fTypeNameTable->Lookup(name);
	if (entry == NULL)
		return false;
 
	for (int32 i = 0; TypeEntryInfo* info = entry->types.ItemAt(i); i++) {
		DIEType* typeEntry = info->type;
		if (constraints.HasTypeKind()) {
			if (dwarf_tag_to_type_kind(typeEntry->Tag())
				!= constraints.TypeKind()) {
				continue;
			}
 
			if (!_EvaluateBaseTypeConstraints(typeEntry, constraints))
				continue;
		}
 
		if (constraints.HasSubtypeKind()
			&& dwarf_tag_to_subtype_kind(typeEntry->Tag())
				!= constraints.SubtypeKind()) {
			continue;
		}
 
		return true;
	}
 
	return false;
}
 
 
AddressSectionType
DwarfImageDebugInfo::GetAddressSectionType(target_addr_t address)
{
	if (address >= fTextSectionStart && address < fTextSectionEnd)
		return ADDRESS_SECTION_TYPE_FUNCTION;
 
 	if (address >= fPLTSectionStart && address < fPLTSectionEnd)
		return ADDRESS_SECTION_TYPE_PLT;
 
	return ADDRESS_SECTION_TYPE_UNKNOWN;
}
 
 
status_t
DwarfImageDebugInfo::CreateFrame(Image* image,
	FunctionInstance* functionInstance, CpuState* cpuState,
	bool getFullFrameInfo, ReturnValueInfoList* returnValueInfos,
	StackFrame*& _frame, CpuState*& _previousCpuState)
{
	DwarfFunctionDebugInfo* function = dynamic_cast<DwarfFunctionDebugInfo*>(
		functionInstance->GetFunctionDebugInfo());
 
	FunctionID* functionID = functionInstance->GetFunctionID();
	BReference<FunctionID> functionIDReference;
	if (functionID != NULL)
		functionIDReference.SetTo(functionID, true);
 
	DIESubprogram* entry = function != NULL
		? function->SubprogramEntry() : NULL;
 
	TRACE_CFI("DwarfImageDebugInfo::CreateFrame(): subprogram DIE: %p, "
		"function: %s\n", entry,
		functionID->FunctionName().String());
 
	int32 registerCount = fArchitecture->CountRegisters();
	const Register* registers = fArchitecture->Registers();
 
	// get the DWARF <-> architecture register maps
	RegisterMap* toDwarfMap;
	RegisterMap* fromDwarfMap;
	status_t error = fArchitecture->GetDwarfRegisterMaps(&toDwarfMap,
		&fromDwarfMap);
	if (error != B_OK)
		return error;
	BReference<RegisterMap> toDwarfMapReference(toDwarfMap, true);
	BReference<RegisterMap> fromDwarfMapReference(fromDwarfMap, true);
 
	// create a clean CPU state for the previous frame
	CpuState* previousCpuState;
	error = fArchitecture->CreateCpuState(previousCpuState);
	if (error != B_OK)
		return error;
	BReference<CpuState> previousCpuStateReference(previousCpuState, true);
 
	// create the target interfaces
	UnwindTargetInterface* inputInterface
		= new(std::nothrow) UnwindTargetInterface(registers, registerCount,
			fromDwarfMap, toDwarfMap, cpuState, fArchitecture,
			fDebuggerInterface);
	if (inputInterface == NULL)
		return B_NO_MEMORY;
	BReference<UnwindTargetInterface> inputInterfaceReference(inputInterface,
		true);
 
	UnwindTargetInterface* outputInterface
		= new(std::nothrow) UnwindTargetInterface(registers, registerCount,
			fromDwarfMap, toDwarfMap, previousCpuState, fArchitecture,
			fDebuggerInterface);
	if (outputInterface == NULL)
		return B_NO_MEMORY;
	BReference<UnwindTargetInterface> outputInterfaceReference(outputInterface,
		true);
 
	// do the unwinding
	target_addr_t instructionPointer
		= cpuState->InstructionPointer() - fRelocationDelta;
	target_addr_t framePointer;
	CompilationUnit* unit = function != NULL ? function->GetCompilationUnit()
			: NULL;
	error = fFile->UnwindCallFrame(unit, fArchitecture->AddressSize(), entry,
		instructionPointer, inputInterface, outputInterface, framePointer);
 
	if (error != B_OK) {
		TRACE_CFI("Failed to unwind call frame: %s\n", strerror(error));
		return B_UNSUPPORTED;
	}
 
	TRACE_CFI_ONLY(
		TRACE_CFI("unwound registers:\n");
		for (int32 i = 0; i < registerCount; i++) {
			const Register* reg = registers + i;
			BVariant value;
			if (previousCpuState->GetRegisterValue(reg, value)) {
				TRACE_CFI("  %3s: %#" B_PRIx64 "\n", reg->Name(),
					value.ToUInt64());
			} else
				TRACE_CFI("  %3s: undefined\n", reg->Name());
		}
	)
 
	// create the stack frame debug info
	DIESubprogram* subprogramEntry = function != NULL ?
		function->SubprogramEntry() : NULL;
	DwarfStackFrameDebugInfo* stackFrameDebugInfo
		= new(std::nothrow) DwarfStackFrameDebugInfo(fArchitecture,
			fImageInfo.ImageID(), fFile, unit, subprogramEntry, fTypeLookup,
			fTypeCache, instructionPointer, framePointer, fRelocationDelta,
			inputInterface, fromDwarfMap);
	if (stackFrameDebugInfo == NULL)
		return B_NO_MEMORY;
	BReference<DwarfStackFrameDebugInfo> stackFrameDebugInfoReference(
		stackFrameDebugInfo, true);
 
	error = stackFrameDebugInfo->Init();
	if (error != B_OK)
		return error;
 
	// create the stack frame
	StackFrame* frame = new(std::nothrow) StackFrame(STACK_FRAME_TYPE_STANDARD,
		cpuState, framePointer, cpuState->InstructionPointer(),
		stackFrameDebugInfo);
	if (frame == NULL)
		return B_NO_MEMORY;
	BReference<StackFrame> frameReference(frame, true);
 
	error = frame->Init();
	if (error != B_OK)
		return error;
 
	frame->SetReturnAddress(previousCpuState->InstructionPointer());
		// Note, this is correct, since we actually retrieved the return
		// address. Our caller will fix the IP for us.
 
	// The subprogram entry may not be available since this may be a case
	// where .eh_frame was used to unwind the stack without other DWARF
	// info being available.
	if (subprogramEntry != NULL && getFullFrameInfo) {
		// create function parameter objects
		for (DebugInfoEntryList::ConstIterator it
			= subprogramEntry->Parameters().GetIterator();
			DebugInfoEntry* entry = it.Next();) {
			if (entry->Tag() != DW_TAG_formal_parameter)
				continue;
 
			BString parameterName;
			DwarfUtils::GetDIEName(entry, parameterName);
			if (parameterName.Length() == 0)
				continue;
 
			DIEFormalParameter* parameterEntry
				= dynamic_cast<DIEFormalParameter*>(entry);
			Variable* parameter;
			if (stackFrameDebugInfo->CreateParameter(functionID,
				parameterEntry, parameter) != B_OK) {
				continue;
			}
			BReference<Variable> parameterReference(parameter, true);
 
			if (!frame->AddParameter(parameter))
				return B_NO_MEMORY;
		}
 
		// create objects for the local variables
		_CreateLocalVariables(unit, frame, functionID, *stackFrameDebugInfo,
			instructionPointer, functionInstance->Address() - fRelocationDelta,
			subprogramEntry->Variables(), subprogramEntry->Blocks());
 
		if (returnValueInfos != NULL && !returnValueInfos->IsEmpty()) {
			_CreateReturnValues(returnValueInfos, image, frame,
				*stackFrameDebugInfo);
		}
	}
 
	_frame = frameReference.Detach();
	_previousCpuState = previousCpuStateReference.Detach();
 
	frame->SetPreviousCpuState(_previousCpuState);
 
	return B_OK;
}
 
 
status_t
DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* _function,
	target_addr_t address, Statement*& _statement)
{
	TRACE_CODE("DwarfImageDebugInfo::GetStatement(function: %p, address: %#"
		B_PRIx64 ")\n", _function, address);
 
	DwarfFunctionDebugInfo* function
		= dynamic_cast<DwarfFunctionDebugInfo*>(_function);
	if (function == NULL) {
		TRACE_LINES("  -> no dwarf function\n");
		// fall back to assembly
		return fArchitecture->GetStatement(function, address, _statement);
	}
 
	AutoLocker<BLocker> locker(fLock);
 
	// check whether we have the source code
	CompilationUnit* unit = function->GetCompilationUnit();
	LocatableFile* file = function->SourceFile();
	if (file == NULL) {
		TRACE_CODE("  -> no source file\n");
 
		// no source code -- rather return the assembly statement
		return fArchitecture->GetStatement(function, address, _statement);
	}
 
	SourceCode* sourceCode = NULL;
	status_t error = fSourceInfo->GetActiveSourceCode(_function, sourceCode);
	BReference<SourceCode> sourceReference(sourceCode, true);
	if (error != B_OK || dynamic_cast<DisassembledCode*>(sourceCode) != NULL) {
		// either no source code or disassembly is currently active (i.e.
		// due to failing to locate the source file on disk or the user
		// deliberately switching to disassembly view).
		// return the assembly statement.
		return fArchitecture->GetStatement(function, address, _statement);
	}
 
	// get the index of the source file in the compilation unit for cheaper
	// comparison below
	int32 fileIndex = _GetSourceFileIndex(unit, file);
 
	// Get the statement by executing the line number program for the
	// compilation unit.
	LineNumberProgram& program = unit->GetLineNumberProgram();
	if (!program.IsValid()) {
		TRACE_CODE("  -> no line number program\n");
		return B_BAD_DATA;
	}
 
	// adjust address
	address -= fRelocationDelta;
 
	LineNumberProgram::State state;
	program.GetInitialState(state);
 
	target_addr_t statementAddress = 0;
	int32 statementLine = -1;
	int32 statementColumn = -1;
	while (program.GetNextRow(state)) {
		// skip statements of other files
		if (state.file != fileIndex)
			continue;
 
		if (statementAddress != 0
			&& (state.isStatement || state.isSequenceEnd)) {
			target_addr_t endAddress = state.address;
			if (address >= statementAddress && address < endAddress) {
				ContiguousStatement* statement = new(std::nothrow)
					ContiguousStatement(
						SourceLocation(statementLine, statementColumn),
						TargetAddressRange(fRelocationDelta + statementAddress,
							endAddress - statementAddress));
				if (statement == NULL)
					return B_NO_MEMORY;
 
				_statement = statement;
				return B_OK;
			}
 
			statementAddress = 0;
		}
 
		if (state.isStatement) {
			statementAddress = state.address;
			statementLine = state.line - 1;
			statementColumn = std::max(state.column - 1, (int32)0);
		}
	}
 
	TRACE_CODE("  -> no line number program match\n");
	return B_ENTRY_NOT_FOUND;
}
 
 
status_t
DwarfImageDebugInfo::GetStatementAtSourceLocation(FunctionDebugInfo* _function,
	const SourceLocation& sourceLocation, Statement*& _statement)
{
	DwarfFunctionDebugInfo* function
		= dynamic_cast<DwarfFunctionDebugInfo*>(_function);
	if (function == NULL)
		return B_BAD_VALUE;
 
	target_addr_t functionStartAddress = function->Address() - fRelocationDelta;
	target_addr_t functionEndAddress = functionStartAddress + function->Size();
 
	TRACE_LINES2("DwarfImageDebugInfo::GetStatementAtSourceLocation(%p, "
		"(%" B_PRId32 ", %" B_PRId32 ")): function range: %#" B_PRIx64 " - %#"
		B_PRIx64 "\n", function, sourceLocation.Line(), sourceLocation.Column(),
		functionStartAddress, functionEndAddress);
 
	AutoLocker<BLocker> locker(fLock);
 
	// get the source file
	LocatableFile* file = function->SourceFile();
	if (file == NULL)
		return B_ENTRY_NOT_FOUND;
 
	CompilationUnit* unit = function->GetCompilationUnit();
 
	// get the index of the source file in the compilation unit for cheaper
	// comparison below
	int32 fileIndex = _GetSourceFileIndex(unit, file);
 
	// Get the statement by executing the line number program for the
	// compilation unit.
	LineNumberProgram& program = unit->GetLineNumberProgram();
	if (!program.IsValid())
		return B_BAD_DATA;
 
	LineNumberProgram::State state;
	program.GetInitialState(state);
 
	target_addr_t statementAddress = 0;
	int32 statementLine = -1;
	int32 statementColumn = -1;
	while (program.GetNextRow(state)) {
		bool isOurFile = state.file == fileIndex;
 
		if (statementAddress != 0
			&& (!isOurFile || state.isStatement || state.isSequenceEnd)) {
			target_addr_t endAddress = state.address;
 
			if (statementAddress < endAddress) {
				TRACE_LINES2("  statement: %#" B_PRIx64 " - %#" B_PRIx64
					", location: (%" B_PRId32 ", %" B_PRId32 ")\n",
					statementAddress, endAddress, statementLine,
				 	statementColumn);
			}
 
			if (statementAddress < endAddress
				&& statementAddress >= functionStartAddress
				&& statementAddress < functionEndAddress
				&& statementLine == (int32)sourceLocation.Line()
				&& statementColumn == (int32)sourceLocation.Column()) {
				TRACE_LINES2("  -> found statement!\n");
 
				ContiguousStatement* statement = new(std::nothrow)
					ContiguousStatement(
						SourceLocation(statementLine, statementColumn),
						TargetAddressRange(fRelocationDelta + statementAddress,
							endAddress - statementAddress));
				if (statement == NULL)
					return B_NO_MEMORY;
 
				_statement = statement;
				return B_OK;
			}
 
			statementAddress = 0;
		}
 
		// skip statements of other files
		if (!isOurFile)
			continue;
 
		if (state.isStatement) {
			statementAddress = state.address;
			statementLine = state.line - 1;
			statementColumn = std::max(state.column - 1, (int32)0);
		}
	}
 
	return B_ENTRY_NOT_FOUND;
}
 
 
status_t
DwarfImageDebugInfo::GetSourceLanguage(FunctionDebugInfo* _function,
	SourceLanguage*& _language)
{
	DwarfFunctionDebugInfo* function
		= dynamic_cast<DwarfFunctionDebugInfo*>(_function);
	if (function == NULL)
		return B_BAD_VALUE;
 
	SourceLanguage* language;
	CompilationUnit* unit = function->GetCompilationUnit();
	switch (unit->UnitEntry()->Language()) {
		case DW_LANG_C89:
		case DW_LANG_C:
		case DW_LANG_C99:
			language = new(std::nothrow) CLanguage;
			break;
		case DW_LANG_C_plus_plus:
			language = new(std::nothrow) CppLanguage;
			break;
		case 0:
		default:
			language = new(std::nothrow) UnsupportedLanguage;
			break;
	}
 
	if (language == NULL)
		return B_NO_MEMORY;
 
	_language = language;
	return B_OK;
}
 
 
ssize_t
DwarfImageDebugInfo::ReadCode(target_addr_t address, void* buffer, size_t size)
{
	target_addr_t offset = address - fRelocationDelta
		- fTextSegment->LoadAddress() + fTextSegment->FileOffset();
	ssize_t bytesRead = pread(fFile->GetElfFile()->FD(), buffer, size, offset);
	return bytesRead >= 0 ? bytesRead : errno;
}
 
 
status_t
DwarfImageDebugInfo::AddSourceCodeInfo(LocatableFile* file,
	FileSourceCode* sourceCode)
{
	bool addedAny = false;
	for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i);
			i++) {
		int32 fileIndex = _GetSourceFileIndex(unit, file);
		if (fileIndex < 0)
			continue;
 
		status_t error = _AddSourceCodeInfo(unit, sourceCode, fileIndex);
		if (error == B_NO_MEMORY)
			return error;
		addedAny |= error == B_OK;
	}
 
	return addedAny ? B_OK : B_ENTRY_NOT_FOUND;
}
 
 
status_t
DwarfImageDebugInfo::_AddSourceCodeInfo(CompilationUnit* unit,
	FileSourceCode* sourceCode, int32 fileIndex)
{
	// Get the statements by executing the line number program for the
	// compilation unit and filtering the rows for our source file.
	LineNumberProgram& program = unit->GetLineNumberProgram();
	if (!program.IsValid())
		return B_BAD_DATA;
 
	LineNumberProgram::State state;
	program.GetInitialState(state);
 
	target_addr_t statementAddress = 0;
	int32 statementLine = -1;
	int32 statementColumn = -1;
	while (program.GetNextRow(state)) {
		TRACE_LINES2("  %#" B_PRIx64 "  (%" B_PRId32 ", %" B_PRId32 ", %"
			B_PRId32 ")  %d\n", state.address, state.file, state.line,
			state.column, state.isStatement);
 
		bool isOurFile = state.file == fileIndex;
 
		if (statementAddress != 0
			&& (!isOurFile || state.isStatement || state.isSequenceEnd)) {
			target_addr_t endAddress = state.address;
			if (endAddress > statementAddress) {
				// add the statement
				status_t error = sourceCode->AddSourceLocation(
					SourceLocation(statementLine, statementColumn));
				if (error != B_OK)
					return error;
 
				TRACE_LINES2("  -> statement: %#" B_PRIx64 " - %#" B_PRIx64
					", source location: (%" B_PRId32 ", %" B_PRId32 ")\n",
					statementAddress, endAddress, statementLine,
				 	statementColumn);
			}
 
			statementAddress = 0;
		}
 
		// skip statements of other files
		if (!isOurFile)
			continue;
 
		if (state.isStatement) {
			statementAddress = state.address;
			statementLine = state.line - 1;
			statementColumn = std::max(state.column - 1, (int32)0);
		}
	}
 
	return B_OK;
}
 
 
int32
DwarfImageDebugInfo::_GetSourceFileIndex(CompilationUnit* unit,
	LocatableFile* sourceFile) const
{
	// get the index of the source file in the compilation unit for cheaper
	// comparison below
	const char* directory;
	for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) {
		LocatableFile* file = fFileManager->GetSourceFile(directory, fileName);
		if (file != NULL) {
			BReference<LocatableFile> fileReference(file, true);
			if (file == sourceFile) {
				return i + 1;
					// indices are one-based
			}
		}
	}
 
	return -1;
}
 
 
status_t
DwarfImageDebugInfo::_CreateLocalVariables(CompilationUnit* unit,
	StackFrame* frame, FunctionID* functionID,
	DwarfStackFrameDebugInfo& factory, target_addr_t instructionPointer,
	target_addr_t lowPC, const EntryListWrapper& variableEntries,
	const EntryListWrapper& blockEntries)
{
	TRACE_LOCALS("DwarfImageDebugInfo::_CreateLocalVariables(): ip: %#" B_PRIx64
		", low PC: %#" B_PRIx64 "\n", instructionPointer, lowPC);
 
	// iterate through the variables and add the ones in scope
	for (DebugInfoEntryList::ConstIterator it
			= variableEntries.list.GetIterator();
		DIEVariable* variableEntry = dynamic_cast<DIEVariable*>(it.Next());) {
 
		TRACE_LOCALS("  variableEntry %p, scope start: %" B_PRIu64 "\n",
			variableEntry, variableEntry->StartScope());
 
		// check the variable's scope
		if (instructionPointer < lowPC + variableEntry->StartScope())
			continue;
 
		// add the variable
		Variable* variable;
		if (factory.CreateLocalVariable(functionID, variableEntry, variable)
				!= B_OK) {
			continue;
		}
		BReference<Variable> variableReference(variable, true);
 
		if (!frame->AddLocalVariable(variable))
			return B_NO_MEMORY;
	}
 
	// iterate through the blocks and find the one we're currently in (if any)
	for (DebugInfoEntryList::ConstIterator it = blockEntries.list.GetIterator();
		DIELexicalBlock* block = dynamic_cast<DIELexicalBlock*>(it.Next());) {
 
		TRACE_LOCALS("  lexical block: %p\n", block);
 
		// check whether the block has low/high PC attributes
		if (block->LowPC() != 0) {
			TRACE_LOCALS("    has lowPC\n");
 
			// yep, compare with the instruction pointer
			if (instructionPointer < block->LowPC()
				|| instructionPointer >= block->HighPC()) {
				continue;
			}
		} else {
			TRACE_LOCALS("    no lowPC\n");
 
			// check the address ranges instead
			TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit,
				block->AddressRangesOffset());
			if (rangeList == NULL) {
				TRACE_LOCALS("    failed to get ranges\n");
				continue;
			}
			BReference<TargetAddressRangeList> rangeListReference(rangeList,
				true);
 
			if (!rangeList->Contains(instructionPointer)) {
				TRACE_LOCALS("    ranges don't contain IP\n");
				continue;
			}
		}
 
		// found a block -- recurse
		return _CreateLocalVariables(unit, frame, functionID, factory,
			instructionPointer, lowPC, block->Variables(), block->Blocks());
	}
 
	return B_OK;
}
 
 
status_t
DwarfImageDebugInfo::_CreateReturnValues(ReturnValueInfoList* returnValueInfos,
	Image* image, StackFrame* frame, DwarfStackFrameDebugInfo& factory)
{
	for (int32 i = 0; i < returnValueInfos->CountItems(); i++) {
		Image* targetImage = image;
		ReturnValueInfo* valueInfo = returnValueInfos->ItemAt(i);
		target_addr_t subroutineAddress = valueInfo->SubroutineAddress();
		CpuState* subroutineState = valueInfo->State();
		if (!targetImage->ContainsAddress(subroutineAddress)) {
			// our current image doesn't contain the target function,
			// locate the one which does.
			targetImage = image->GetTeam()->ImageByAddress(subroutineAddress);
			if (targetImage == NULL) {
				// nothing we can do, try the next entry (if any)
				continue;
			}
		}
 
		status_t result = B_OK;
		ImageDebugInfo* imageInfo = targetImage->GetImageDebugInfo();
		if (imageInfo == NULL) {
			// the subroutine may have resolved to a different image
			// that doesn't have debug information available.
			continue;
		}
 
		FunctionInstance* targetFunction;
		if (imageInfo->GetAddressSectionType(subroutineAddress)
				== ADDRESS_SECTION_TYPE_PLT) {
			result = fArchitecture->ResolvePICFunctionAddress(
				subroutineAddress, subroutineState, subroutineAddress);
			if (result != B_OK)
				continue;
			if (!targetImage->ContainsAddress(subroutineAddress)) {
				// the PLT entry doesn't necessarily point to a function
				// in the same image; as such we may need to try to
				// resolve the target address again.
				targetImage = image->GetTeam()->ImageByAddress(
					subroutineAddress);
				if (targetImage == NULL)
					continue;
				imageInfo = targetImage->GetImageDebugInfo();
				if (imageInfo == NULL) {
					// As above, since the indirection here may have
					// landed us in an entirely different image, there is
					// no guarantee that debug info is available,
					// depending on which image it was.
					continue;
				}
 
			}
		}
 
		targetFunction = imageInfo->FunctionAtAddress(subroutineAddress);
		if (targetFunction != NULL) {
			DwarfFunctionDebugInfo* targetInfo =
				dynamic_cast<DwarfFunctionDebugInfo*>(
					targetFunction->GetFunctionDebugInfo());
			if (targetInfo != NULL) {
				DIESubprogram* subProgram = targetInfo->SubprogramEntry();
				DIEType* returnType = subProgram->ReturnType();
				if (returnType == NULL) {
					// check if we have a specification, and if so, if that has
					// a return type
					subProgram = dynamic_cast<DIESubprogram*>(
						subProgram->Specification());
					if (subProgram != NULL)
						returnType = subProgram->ReturnType();
 
					// function doesn't return a value, we're done.
					if (returnType == NULL)
						return B_OK;
				}
 
				uint32 byteSize = 0;
				if (returnType->ByteSize() == NULL) {
					if (dynamic_cast<DIEAddressingType*>(returnType) != NULL)
						byteSize = fArchitecture->AddressSize();
				} else
					byteSize = returnType->ByteSize()->constant;
 
				// if we were unable to determine a size for the type,
				// simply default to the architecture's register width.
				if (byteSize == 0)
					byteSize = fArchitecture->AddressSize();
 
				ValueLocation* location;
				result = fArchitecture->GetReturnAddressLocation(frame,
					byteSize, location);
				if (result != B_OK)
					return result;
 
				BReference<ValueLocation> locationReference(location, true);
				Variable* variable = NULL;
				BReference<FunctionID> idReference(
					targetFunction->GetFunctionID(), true);
				result = factory.CreateReturnValue(idReference, returnType,
					location, subroutineState, variable);
				if (result != B_OK)
					return result;
 
				BReference<Variable> variableReference(variable, true);
				if (!frame->AddLocalVariable(variable))
					return B_NO_MEMORY;
			}
		}
	}
 
	return B_OK;
}
 
 
bool
DwarfImageDebugInfo::_EvaluateBaseTypeConstraints(DIEType* type,
	const TypeLookupConstraints& constraints) const
{
	if (constraints.HasBaseTypeName()) {
		BString baseEntryName;
		DIEType* baseTypeOwnerEntry = NULL;
 
		switch (constraints.TypeKind()) {
			case TYPE_ADDRESS:
			{
				DIEAddressingType* addressType =
					dynamic_cast<DIEAddressingType*>(type);
				if (addressType != NULL) {
					baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate(
						addressType, HasTypePredicate<DIEAddressingType>());
				}
				break;
			}
			case TYPE_ARRAY:
			{
				DIEArrayType* arrayType =
					dynamic_cast<DIEArrayType*>(type);
				if (arrayType != NULL) {
					baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate(
						arrayType, HasTypePredicate<DIEArrayType>());
				}
				break;
			}
			default:
				break;
		}
 
		if (baseTypeOwnerEntry != NULL) {
			DwarfUtils::GetFullyQualifiedDIEName(baseTypeOwnerEntry,
				baseEntryName);
 
			if (baseEntryName != constraints.BaseTypeName())
				return false;
		}
	}
 
	return true;
}
 
 
status_t
DwarfImageDebugInfo::_RecursiveTraverseNamespaceForFunctions(
	DIENamespace* nsEntry, CompilationUnit* unit,
	BObjectList<FunctionDebugInfo>& functions)
{
	status_t error = B_OK;
	for (DebugInfoEntryList::ConstIterator it
				= nsEntry->Children().GetIterator();
			DebugInfoEntry* entry = it.Next();) {
		if (entry->Tag() == DW_TAG_subprogram) {
			DIESubprogram* subprogramEntry
				= static_cast<DIESubprogram*>(entry);
			error = _AddFunction(subprogramEntry, unit, functions);
			if (error != B_OK)
				return error;
		}
 
		DIENamespace* nsEntry = dynamic_cast<DIENamespace*>(entry);
		if (nsEntry != NULL) {
			error = _RecursiveTraverseNamespaceForFunctions(nsEntry, unit,
				functions);
			if (error != B_OK)
				return error;
			continue;
		}
 
		DIEClassBaseType* classEntry = dynamic_cast<DIEClassBaseType*>(entry);
		if (classEntry != NULL) {
			for (DebugInfoEntryList::ConstIterator it
						= classEntry->MemberFunctions().GetIterator();
					DebugInfoEntry* memberEntry = it.Next();) {
				error = _AddFunction(static_cast<DIESubprogram*>(memberEntry),
					unit, functions);
				if (error != B_OK)
					return error;
			}
		}
	}
 
	return B_OK;
}
 
 
status_t
DwarfImageDebugInfo::_AddFunction(DIESubprogram* subprogramEntry,
	CompilationUnit* unit, BObjectList<FunctionDebugInfo>& functions)
{
	// ignore declarations and inlined functions
	if (subprogramEntry->IsDeclaration()
		|| subprogramEntry->Inline() == DW_INL_inlined
		|| subprogramEntry->Inline() == DW_INL_declared_inlined) {
		return B_OK;
	}
 
	// get the name
	BString name;
	DwarfUtils::GetFullyQualifiedDIEName(subprogramEntry, name);
	if (name.Length() == 0)
		return B_OK;
 
	// get the address ranges
	TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit,
		subprogramEntry->AddressRangesOffset());
	if (rangeList == NULL) {
		target_addr_t lowPC = subprogramEntry->LowPC();
		target_addr_t highPC = subprogramEntry->HighPC();
		if (highPC <= lowPC)
			return B_OK;
 
		rangeList = new(std::nothrow) TargetAddressRangeList(
			TargetAddressRange(lowPC, highPC - lowPC));
		if (rangeList == NULL)
			return B_NO_MEMORY;
				// TODO: Clean up already added functions!
	}
	BReference<TargetAddressRangeList> rangeListReference(rangeList,
		true);
 
	// get the source location
	const char* directoryPath = NULL;
	const char* fileName = NULL;
	int32 line = -1;
	int32 column = -1;
	DwarfUtils::GetDeclarationLocation(fFile, subprogramEntry,
		directoryPath, fileName, line, column);
 
	LocatableFile* file = NULL;
	if (fileName != NULL) {
		file = fFileManager->GetSourceFile(directoryPath,
			fileName);
	}
	BReference<LocatableFile> fileReference(file, true);
 
	// create and add the functions
	DwarfFunctionDebugInfo* function
		= new(std::nothrow) DwarfFunctionDebugInfo(this, unit,
			subprogramEntry, rangeList, name, file,
			SourceLocation(line, std::max(column, (int32)0)));
	if (function == NULL || !functions.AddItem(function)) {
		delete function;
		return B_NO_MEMORY;
			// TODO: Clean up already added functions!
	}
 
	return B_OK;
}
 
 
status_t
DwarfImageDebugInfo::_BuildTypeNameTable()
{
	fTypeNameTable = new(std::nothrow) TypeNameTable;
	if (fTypeNameTable == NULL)
		return B_NO_MEMORY;
 
	status_t error = fTypeNameTable->Init();
	if (error != B_OK)
		return error;
 
	// iterate through all compilation units
	for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i);
		i++) {
		// iterate through all types of the compilation unit
		for (DebugInfoEntryList::ConstIterator it
				= unit->UnitEntry()->Types().GetIterator();
			DIEType* typeEntry = dynamic_cast<DIEType*>(it.Next());) {
 
			if (_RecursiveAddTypeNames(typeEntry, unit) != B_OK)
				return B_NO_MEMORY;
		}
 
		for (DebugInfoEntryList::ConstIterator it
			= unit->UnitEntry()->OtherChildren().GetIterator();
			DebugInfoEntry* child = it.Next();) {
			DIENamespace* namespaceEntry = dynamic_cast<DIENamespace*>(child);
			if (namespaceEntry == NULL)
				continue;
 
			if (_RecursiveTraverseNamespaceForTypes(namespaceEntry, unit)
					!= B_OK) {
				return B_NO_MEMORY;
			}
		}
	}
 
	return B_OK;
}
 
 
status_t
DwarfImageDebugInfo::_RecursiveAddTypeNames(DIEType* type, CompilationUnit* unit)
{
	if (type->IsDeclaration())
		return B_OK;
 
	BString typeEntryName;
	DwarfUtils::GetFullyQualifiedDIEName(type, typeEntryName);
 
	status_t error = B_OK;
	TypeNameEntry* entry = fTypeNameTable->Lookup(typeEntryName);
	if (entry == NULL) {
		entry = new(std::nothrow) TypeNameEntry(typeEntryName);
		if (entry == NULL)
			return B_NO_MEMORY;
 
		error = fTypeNameTable->Insert(entry);
		if (error != B_OK)
			return error;
	}
 
	TypeEntryInfo* info = new(std::nothrow) TypeEntryInfo(type,	unit);
	if (info == NULL)
		return B_NO_MEMORY;
 
	if (!entry->types.AddItem(info)) {
		delete info;
		return B_NO_MEMORY;
	}
 
	DIEClassBaseType* classType = dynamic_cast<DIEClassBaseType*>(type);
	if (classType == NULL)
		return B_OK;
 
	for (DebugInfoEntryList::ConstIterator it
			= classType->InnerTypes().GetIterator();
		DIEType* innerType = dynamic_cast<DIEType*>(it.Next());) {
		error = _RecursiveAddTypeNames(innerType, unit);
		if (error != B_OK)
			return error;
	}
 
	return B_OK;
}
 
 
status_t
DwarfImageDebugInfo::_RecursiveTraverseNamespaceForTypes(DIENamespace* nsEntry,
	CompilationUnit* unit)
{
	for (DebugInfoEntryList::ConstIterator it
				= nsEntry->Children().GetIterator();
			DebugInfoEntry* child = it.Next();) {
 
		if (child->IsType()) {
			DIEType* type = dynamic_cast<DIEType*>(child);
			if (_RecursiveAddTypeNames(type, unit) != B_OK)
				return B_NO_MEMORY;
		} else {
			DIENamespace* nameSpace = dynamic_cast<DIENamespace*>(child);
			if (nameSpace == NULL)
				continue;
 
			status_t error = _RecursiveTraverseNamespaceForTypes(nameSpace,
				unit);
			if (error != B_OK)
				return error;
			continue;
		}
	}
 
	return B_OK;
}

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: next.