⛏️ index : haiku.git

/*
 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Copyright 2011-2013, Rene Gollent, rene@gollent.com.
 * Distributed under the terms of the MIT License.
 */

#include "DwarfUtils.h"

#include <String.h>

#include "CompilationUnit.h"
#include "Dwarf.h"
#include "DwarfFile.h"


/*static*/ void
DwarfUtils::GetDIEName(const DebugInfoEntry* entry, BString& _name)
{
	// If we don't seem to have a name but an abstract origin, return the
	// origin's name.
	const char* name = entry->Name();
	if (name == NULL) {
		if (DebugInfoEntry* abstractOrigin = entry->AbstractOrigin()) {
			entry = abstractOrigin;
			name = entry->Name();
		}
	}

	// If we still don't have a name but a specification, return the
	// specification's name.
	if (name == NULL) {
		if (DebugInfoEntry* specification = entry->Specification()) {
			entry = specification;
			name = entry->Name();
		}
	}

	_name = name;
}


/*static*/ void
DwarfUtils::GetDIETypeName(const DebugInfoEntry* entry, BString& _name,
	const DebugInfoEntry* requestingEntry)
{
	const DIEType* type = dynamic_cast<const DIEType*>(entry);
	if (type == NULL)
		return;

	const DIEModifiedType* modifiedType = dynamic_cast<const DIEModifiedType*>(
		type);
	BString typeName;
	BString modifier;

	if (modifiedType != NULL) {
		const DIEType* baseType = type;
		while ((modifiedType = dynamic_cast<const DIEModifiedType*>(
			baseType)) != NULL) {
			switch (modifiedType->Tag()) {
				case DW_TAG_pointer_type:
					modifier.Prepend("*");
					break;
				case DW_TAG_reference_type:
					modifier.Prepend("&");
					break;
				case DW_TAG_const_type:
					modifier.Prepend(" const ");
					break;
				default:
					break;
			}

			baseType = modifiedType->GetType();
		}
		type = baseType;
	}

	// if the parameter has no type associated,
	// then it's the unspecified type.
	if (type == NULL)
		typeName = "void";
	else
		GetFullyQualifiedDIEName(type, typeName, requestingEntry);

	if (modifier.Length() > 0) {
		if (modifier[modifier.Length() - 1] == ' ')
			modifier.Truncate(modifier.Length() - 1);

		// if the modifier has a leading const, treat it
		// as the degenerate case and prepend it to the
		// type name since that's the more typically used
		// representation in source
		if (modifier[0] == ' ') {
			typeName.Prepend("const ");
			modifier.Remove(0, 7);
		}
		typeName += modifier;
	}

	_name = typeName;
}


/*static*/ void
DwarfUtils::GetFullDIEName(const DebugInfoEntry* entry, BString& _name)
{
	BString generatedName;
	// If we don't seem to have a name but an abstract origin, return the
	// origin's name.
	const char* name = entry->Name();
	if (name == NULL) {
		if (DebugInfoEntry* abstractOrigin = entry->AbstractOrigin()) {
			entry = abstractOrigin;
			name = entry->Name();
		}
	}

	// If we still don't have a name but a specification, return the
	// specification's name.
	if (name == NULL) {
		if (DebugInfoEntry* specification = entry->Specification()) {
			entry = specification;
			name = entry->Name();
		}
	}

	if (name == NULL) {
		if (dynamic_cast<const DIEModifiedType*>(entry) != NULL)
			GetDIETypeName(entry, _name);

		// we found no name for this entry whatsoever, abort.
		return;
	}

	generatedName = name;

	const DIESubprogram* subProgram = dynamic_cast<const DIESubprogram*>(
		entry);
	if (subProgram != NULL) {
		generatedName += "(";
		BString parameters;
		DebugInfoEntryList::ConstIterator iterator
			= subProgram->Parameters().GetIterator();

		bool firstParameter = true;
		while (iterator.HasNext()) {
			DebugInfoEntry* parameterEntry = iterator.Next();
			if (dynamic_cast<DIEUnspecifiedParameters*>(parameterEntry)
				!= NULL) {
				parameters += ", ...";
				continue;
			}

			const DIEFormalParameter* parameter
				= dynamic_cast<DIEFormalParameter*>(parameterEntry);
			if (parameter == NULL) {
				// this shouldn't happen
				return;
			}

			if (parameter->IsArtificial())
				continue;

			BString paramName;
			BString modifier;
			DIEType* type = parameter->GetType();
			GetDIETypeName(type, paramName, entry);

			if (firstParameter)
				firstParameter = false;
			else
				parameters += ", ";

			parameters += paramName;
		}

		if (parameters.Length() > 0)
			generatedName += parameters;
		else
			generatedName += "void";
		generatedName += ")";
	}
	_name = generatedName;
}


/*static*/ void
DwarfUtils::GetFullyQualifiedDIEName(const DebugInfoEntry* entry,
	BString& _name, const DebugInfoEntry* requestingEntry)
{
	// If we don't seem to have a name but an abstract origin, return the
	// origin's name.
	if (entry->Name() == NULL) {
		if (DebugInfoEntry* abstractOrigin = entry->AbstractOrigin())
			entry = abstractOrigin;
	}

	// If we don't still don't have a name but a specification, get the
	// specification's name.
	if (entry->Name() == NULL) {
		if (DebugInfoEntry* specification = entry->Specification())
			entry = specification;
	}

	_name.Truncate(0);
	BString generatedName;

	// Get the namespace, if any.
	DebugInfoEntry* parent = entry->Parent();
	while (parent != NULL) {
		if (parent == requestingEntry)
			break;
		if (parent->IsNamespace()) {
			BString parentName;
			GetFullyQualifiedDIEName(parent, parentName);
			if (parentName.Length() > 0) {
				parentName += "::";
				generatedName.Prepend(parentName);
			}
			break;
		}

		parent = parent->Parent();
	}

	BString name;
	GetFullDIEName(entry, name);
	if (name.Length() == 0)
		return;

	generatedName += name;

	_name = generatedName;
}


/*static*/ bool
DwarfUtils::GetDeclarationLocation(DwarfFile* dwarfFile,
	const DebugInfoEntry* entry, const char*& _directory, const char*& _file,
	int32& _line, int32& _column)
{
	uint32 file = 0;
	uint32 line = 0;
	uint32 column = 0;
	bool fileSet = entry->GetDeclarationFile(file);
	bool lineSet = entry->GetDeclarationLine(line);
	bool columnSet = entry->GetDeclarationColumn(column);

	// if something is not set yet, try the abstract origin (if any)
	if (!fileSet || !lineSet || !columnSet) {
		if (DebugInfoEntry* abstractOrigin = entry->AbstractOrigin()) {
			entry = abstractOrigin;
			if (!fileSet)
				fileSet = entry->GetDeclarationFile(file);
			if (!lineSet)
				lineSet = entry->GetDeclarationLine(line);
			if (!columnSet)
				columnSet = entry->GetDeclarationColumn(column);
		}
	}

	// something is not set yet, try the specification (if any)
	if (!fileSet || !lineSet || !columnSet) {
		if (DebugInfoEntry* specification = entry->Specification()) {
			entry = specification;
			if (!fileSet)
				fileSet = entry->GetDeclarationFile(file);
			if (!lineSet)
				lineSet = entry->GetDeclarationLine(line);
			if (!columnSet)
				columnSet = entry->GetDeclarationColumn(column);
		}
	}

	if (file == 0)
		return false;

	// get the compilation unit
	CompilationUnit* unit = dwarfFile->CompilationUnitForDIE(entry);
	if (unit == NULL)
		return false;

	const char* directoryName;
	const char* fileName = unit->FileAt(file - 1, &directoryName);
	if (fileName == NULL)
		return false;

	_directory = directoryName;
	_file = fileName;
	_line = (int32)line - 1;
	_column = (int32)column - 1;
	return true;
}