* ArrayIndexPath::SetTo(): Changed return type from bool to status_t.
* Finished support for retrieving and displaying array element values. * Added work-around for pointer types, if the base type isn't specified in the debug info (as it should per specification). * Added support for unspecified types, function types, and pointer to member types. All types relevant for C++ should be supported now. There are still quite a few TODOs, though. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33434 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -546,7 +546,8 @@ GetStackFrameValueJob::_GetValue()
|
||||
type = dynamic_cast<TypedefType*>(type)->BaseType();
|
||||
break;
|
||||
case TYPE_ADDRESS:
|
||||
TRACE_LOCALS(" TYPE_ADDRESS\n");
|
||||
case TYPE_POINTER_TO_MEMBER:
|
||||
TRACE_LOCALS(" TYPE_ADDRESS/TYPE_POINTER_TO_MEMBER\n");
|
||||
if (fArchitecture->AddressSize() == 4) {
|
||||
valueType = B_UINT32_TYPE;
|
||||
TRACE_LOCALS(" -> 32 bit\n");
|
||||
@@ -595,9 +596,16 @@ GetStackFrameValueJob::_GetValue()
|
||||
shortValueIsFine = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
TRACE_LOCALS(" default -> unsupported\n");
|
||||
case TYPE_SUBRANGE:
|
||||
TRACE_LOCALS(" TYPE_SUBRANGE -> unsupported\n");
|
||||
return B_UNSUPPORTED;
|
||||
case TYPE_UNSPECIFIED:
|
||||
// Can't get the value for an unspecified type!
|
||||
return B_BAD_VALUE;
|
||||
case TYPE_FUNCTION:
|
||||
TRACE_LOCALS(" TYPE_FUNCTION\n");
|
||||
// Can't get the value for a function type!
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -833,9 +841,15 @@ GetStackFrameValueJob::_ResolveTypeAndLocation(Type*& _type,
|
||||
switch (component.typeKind) {
|
||||
case TYPE_PRIMITIVE:
|
||||
case TYPE_ENUMERATION:
|
||||
case TYPE_SUBRANGE:
|
||||
case TYPE_UNSPECIFIED:
|
||||
case TYPE_FUNCTION:
|
||||
case TYPE_POINTER_TO_MEMBER:
|
||||
// cannot happen
|
||||
TRACE_LOCALS("GetStackFrameValueJob::_ResolveTypeAndLocation(): "
|
||||
"TYPE_PRIMITIVE/TYPE_ENUMERATION subcomponent!\n");
|
||||
"TYPE_PRIMITIVE/TYPE_ENUMERATION/TYPE_SUBRANGE/"
|
||||
"TYPE_UNSPECIFIED/TYPE_FUNCTION/TYPE_POINTER_TO_MEMBER "
|
||||
"subcomponent!\n");
|
||||
return B_BAD_VALUE;
|
||||
case TYPE_COMPOUND:
|
||||
{
|
||||
@@ -921,8 +935,9 @@ GetStackFrameValueJob::_ResolveTypeAndLocation(Type*& _type,
|
||||
fStackFrame, type, parentValue.ToUInt64(), location);
|
||||
if (error != B_OK) {
|
||||
TRACE_LOCALS("GetStackFrameValueJob::"
|
||||
"_ResolveTypeAndLocation(): TYPE_ADDRESS: "
|
||||
"ResolveObjectDataLocation() failed: %s\n",
|
||||
"_ResolveTypeAndLocation(): "
|
||||
"TYPE_ADDRESS/TYPE_POINTER_TO_MEMBER: "
|
||||
"ResolveObjectDataLocation() failed: %s\n",
|
||||
strerror(error));
|
||||
return error;
|
||||
}
|
||||
@@ -935,10 +950,44 @@ GetStackFrameValueJob::_ResolveTypeAndLocation(Type*& _type,
|
||||
return B_OK;
|
||||
}
|
||||
case TYPE_ARRAY:
|
||||
// TODO:...
|
||||
default:
|
||||
return B_UNSUPPORTED;
|
||||
{
|
||||
ArrayType* arrayType = dynamic_cast<ArrayType*>(parentType);
|
||||
|
||||
if (component.componentKind != TYPE_COMPONENT_ARRAY_ELEMENT)
|
||||
return B_UNSUPPORTED;
|
||||
|
||||
// get the index path
|
||||
ArrayIndexPath indexPath;
|
||||
error = indexPath.SetTo(component.name.String());
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
if (indexPath.CountIndices() != arrayType->CountDimensions())
|
||||
return B_UNSUPPORTED;
|
||||
|
||||
// resolve the element location
|
||||
ValueLocation* location;
|
||||
error = fStackFrame->DebugInfo()->ResolveArrayElementLocation(
|
||||
fStackFrame, arrayType, indexPath, *parentLocation, location);
|
||||
if (error != B_OK) {
|
||||
TRACE_LOCALS("GetStackFrameValueJob::"
|
||||
"_ResolveTypeAndLocation(): TYPE_ARRAY: "
|
||||
"ResolveArrayElementLocation() failed: %s\n",
|
||||
strerror(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
arrayType->BaseType()->AcquireReference();
|
||||
_type = arrayType->BaseType();
|
||||
_location = location;
|
||||
_valueResolved = false;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Can never get here.
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <Variant.h>
|
||||
|
||||
#include "ArrayIndexPath.h"
|
||||
#include "Architecture.h"
|
||||
#include "CompilationUnit.h"
|
||||
#include "DebugInfoEntries.h"
|
||||
@@ -44,6 +45,18 @@ struct HasTypePredicate {
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - HasReturnTypePredicate
|
||||
|
||||
|
||||
template<typename EntryType>
|
||||
struct HasReturnTypePredicate {
|
||||
inline bool operator()(EntryType* entry) const
|
||||
{
|
||||
return entry->ReturnType() != NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - HasEnumeratorsPredicate
|
||||
|
||||
|
||||
@@ -88,6 +101,18 @@ struct HasBaseTypesPredicate {
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - HasParametersPredicate
|
||||
|
||||
|
||||
template<typename EntryType>
|
||||
struct HasParametersPredicate {
|
||||
inline bool operator()(EntryType* entry) const
|
||||
{
|
||||
return !entry->Parameters().IsEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - HasLowerBoundPredicate
|
||||
|
||||
|
||||
@@ -121,6 +146,41 @@ struct HasCountPredicate {
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - HasBitStridePredicate
|
||||
|
||||
|
||||
template<typename EntryType>
|
||||
struct HasBitStridePredicate {
|
||||
inline bool operator()(EntryType* entry) const
|
||||
{
|
||||
return entry->BitStride()->IsValid();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - HasByteStridePredicate
|
||||
|
||||
|
||||
template<typename EntryType>
|
||||
struct HasByteStridePredicate {
|
||||
inline bool operator()(EntryType* entry) const
|
||||
{
|
||||
return entry->ByteStride()->IsValid();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - HasContainingTypePredicate
|
||||
|
||||
|
||||
struct HasContainingTypePredicate {
|
||||
inline bool operator()(DIEPointerToMemberType* entry) const
|
||||
{
|
||||
return entry->ContainingType() != NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
|
||||
@@ -390,12 +450,60 @@ public:
|
||||
return fType;
|
||||
}
|
||||
|
||||
DwarfType* GetDwarfType() const
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
|
||||
private:
|
||||
DwarfType* fType;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - DwarfFunctionParameter
|
||||
|
||||
|
||||
struct DwarfStackFrameDebugInfo::DwarfFunctionParameter : FunctionParameter {
|
||||
public:
|
||||
DwarfFunctionParameter(DIEFormalParameter* entry, const BString& name,
|
||||
DwarfType* type)
|
||||
:
|
||||
fEntry(entry),
|
||||
fName(name),
|
||||
fType(type)
|
||||
{
|
||||
fType->AcquireReference();
|
||||
}
|
||||
|
||||
~DwarfFunctionParameter()
|
||||
{
|
||||
fType->ReleaseReference();
|
||||
}
|
||||
|
||||
virtual const char* Name() const
|
||||
{
|
||||
return fName.Length() > 0 ? fName.String() : NULL;
|
||||
}
|
||||
|
||||
virtual Type* GetType() const
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
|
||||
DIEFormalParameter* Entry() const
|
||||
{
|
||||
return fEntry;
|
||||
}
|
||||
|
||||
private:
|
||||
DIEFormalParameter* fEntry;
|
||||
BString fName;
|
||||
DwarfType* fType;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - DwarfPrimitiveType
|
||||
|
||||
|
||||
@@ -814,6 +922,11 @@ struct DwarfStackFrameDebugInfo::DwarfArrayType : ArrayType, DwarfType {
|
||||
return fDimensions.ItemAt(index);
|
||||
}
|
||||
|
||||
DwarfArrayDimension* DwarfDimensionAt(int32 index) const
|
||||
{
|
||||
return fDimensions.ItemAt(index);
|
||||
}
|
||||
|
||||
virtual DIEType* GetDIEType() const
|
||||
{
|
||||
return fEntry;
|
||||
@@ -843,6 +956,177 @@ private:
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - DwarfUnspecifiedType
|
||||
|
||||
|
||||
struct DwarfStackFrameDebugInfo::DwarfUnspecifiedType : UnspecifiedType,
|
||||
DwarfType {
|
||||
public:
|
||||
// NOTE: The entry may be NULL.
|
||||
DwarfUnspecifiedType(const BString& name, DIEUnspecifiedType* entry)
|
||||
:
|
||||
DwarfType(name),
|
||||
fEntry(entry)
|
||||
{
|
||||
}
|
||||
|
||||
~DwarfUnspecifiedType()
|
||||
{
|
||||
}
|
||||
|
||||
virtual DIEType* GetDIEType() const
|
||||
{
|
||||
return fEntry;
|
||||
}
|
||||
|
||||
DIEUnspecifiedType* Entry() const
|
||||
{
|
||||
return fEntry;
|
||||
}
|
||||
|
||||
private:
|
||||
DIEUnspecifiedType* fEntry;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - DwarfFunctionType
|
||||
|
||||
|
||||
struct DwarfStackFrameDebugInfo::DwarfFunctionType : FunctionType, DwarfType {
|
||||
DwarfFunctionType(const BString& name, DIESubroutineType* entry,
|
||||
DwarfType* returnType)
|
||||
:
|
||||
DwarfType(name),
|
||||
fEntry(entry),
|
||||
fReturnType(returnType),
|
||||
fHasVariableArguments(false)
|
||||
{
|
||||
if (fReturnType != NULL)
|
||||
fReturnType->AcquireReference();
|
||||
}
|
||||
|
||||
~DwarfFunctionType()
|
||||
{
|
||||
for (int32 i = 0;
|
||||
DwarfFunctionParameter* parameter = fParameters.ItemAt(i); i++) {
|
||||
parameter->ReleaseReference();
|
||||
}
|
||||
|
||||
if (fReturnType != NULL)
|
||||
fReturnType->ReleaseReference();
|
||||
}
|
||||
|
||||
virtual Type* ReturnType() const
|
||||
{
|
||||
return fReturnType;
|
||||
}
|
||||
|
||||
virtual int32 CountParameters() const
|
||||
{
|
||||
return fParameters.CountItems();
|
||||
}
|
||||
|
||||
virtual FunctionParameter* ParameterAt(int32 index) const
|
||||
{
|
||||
return fParameters.ItemAt(index);
|
||||
}
|
||||
|
||||
DwarfFunctionParameter* DwarfParameterAt(int32 index) const
|
||||
{
|
||||
return fParameters.ItemAt(index);
|
||||
}
|
||||
|
||||
virtual bool HasVariableArguments() const
|
||||
{
|
||||
return fHasVariableArguments;
|
||||
}
|
||||
|
||||
void SetHasVariableArguments(bool hasVarArgs)
|
||||
{
|
||||
fHasVariableArguments = hasVarArgs;
|
||||
}
|
||||
|
||||
virtual DIEType* GetDIEType() const
|
||||
{
|
||||
return fEntry;
|
||||
}
|
||||
|
||||
DIESubroutineType* Entry() const
|
||||
{
|
||||
return fEntry;
|
||||
}
|
||||
|
||||
bool AddParameter(DwarfFunctionParameter* parameter)
|
||||
{
|
||||
if (!fParameters.AddItem(parameter))
|
||||
return false;
|
||||
|
||||
parameter->AcquireReference();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef BObjectList<DwarfFunctionParameter> ParameterList;
|
||||
|
||||
private:
|
||||
DIESubroutineType* fEntry;
|
||||
DwarfType* fReturnType;
|
||||
ParameterList fParameters;
|
||||
bool fHasVariableArguments;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - DwarfPointerToMemberType
|
||||
|
||||
|
||||
struct DwarfStackFrameDebugInfo::DwarfPointerToMemberType : PointerToMemberType,
|
||||
DwarfType {
|
||||
public:
|
||||
DwarfPointerToMemberType(const BString& name, DIEPointerToMemberType* entry,
|
||||
DwarfCompoundType* containingType, DwarfType* baseType)
|
||||
:
|
||||
DwarfType(name),
|
||||
fEntry(entry),
|
||||
fContainingType(containingType),
|
||||
fBaseType(baseType)
|
||||
{
|
||||
fContainingType->AcquireReference();
|
||||
fBaseType->AcquireReference();
|
||||
}
|
||||
|
||||
~DwarfPointerToMemberType()
|
||||
{
|
||||
fContainingType->ReleaseReference();
|
||||
fBaseType->ReleaseReference();
|
||||
}
|
||||
|
||||
virtual CompoundType* ContainingType() const
|
||||
{
|
||||
return fContainingType;
|
||||
}
|
||||
|
||||
virtual Type* BaseType() const
|
||||
{
|
||||
return fBaseType;
|
||||
}
|
||||
|
||||
virtual DIEType* GetDIEType() const
|
||||
{
|
||||
return fEntry;
|
||||
}
|
||||
|
||||
DIEPointerToMemberType* Entry() const
|
||||
{
|
||||
return fEntry;
|
||||
}
|
||||
|
||||
private:
|
||||
DIEPointerToMemberType* fEntry;
|
||||
DwarfCompoundType* fContainingType;
|
||||
DwarfType* fBaseType;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - DwarfTypeHashDefinition
|
||||
|
||||
|
||||
@@ -1063,6 +1347,158 @@ DwarfStackFrameDebugInfo::ResolveDataMemberLocation(StackFrame* stackFrame,
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DwarfStackFrameDebugInfo::ResolveArrayElementLocation(StackFrame* stackFrame,
|
||||
ArrayType* _type, const ArrayIndexPath& indexPath,
|
||||
const ValueLocation& parentLocation, ValueLocation*& _location)
|
||||
{
|
||||
DwarfArrayType* type = dynamic_cast<DwarfArrayType*>(_type);
|
||||
if (type == NULL || indexPath.CountIndices() != type->CountDimensions())
|
||||
return B_BAD_VALUE;
|
||||
DIEArrayType* typeEntry = type->Entry();
|
||||
|
||||
// If the array entry has a bit stride, get it. Otherwise fall back to the
|
||||
// element type size.
|
||||
int64 bitStride;
|
||||
if (DIEArrayType* bitStrideOwnerEntry = DwarfUtils::GetDIEByPredicate(
|
||||
typeEntry, HasBitStridePredicate<DIEArrayType>())) {
|
||||
BVariant value;
|
||||
status_t error = fFile->EvaluateDynamicValue(fCompilationUnit,
|
||||
fSubprogramEntry, bitStrideOwnerEntry->BitStride(),
|
||||
fTargetInterface, fInstructionPointer, fFramePointer, value);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
if (!value.IsInteger())
|
||||
return B_BAD_VALUE;
|
||||
bitStride = value.ToInt64();
|
||||
} else
|
||||
bitStride = type->BaseType()->ByteSize() * 8;
|
||||
|
||||
// Iterate backward through the dimensions and compute the total offset of
|
||||
// the element.
|
||||
int64 elementOffset = 0;
|
||||
DwarfArrayDimension* previousDimension = NULL;
|
||||
int64 previousDimensionStride = 0;
|
||||
for (int32 dimensionIndex = type->CountDimensions() - 1;
|
||||
dimensionIndex >= 0; dimensionIndex--) {
|
||||
DwarfArrayDimension* dimension = type->DwarfDimensionAt(dimensionIndex);
|
||||
int64 index = indexPath.IndexAt(dimensionIndex);
|
||||
|
||||
// If the dimension has a special bit/byte stride, get it.
|
||||
int64 dimensionStride = 0;
|
||||
DwarfType* dimensionType = dimension->GetDwarfType();
|
||||
DIEArrayIndexType* dimensionTypeEntry = dimensionType != NULL
|
||||
? dynamic_cast<DIEArrayIndexType*>(dimensionType->GetDIEType())
|
||||
: NULL;
|
||||
if (dimensionTypeEntry != NULL) {
|
||||
DIEArrayIndexType* bitStrideOwnerEntry
|
||||
= DwarfUtils::GetDIEByPredicate(dimensionTypeEntry,
|
||||
HasBitStridePredicate<DIEArrayIndexType>());
|
||||
if (bitStrideOwnerEntry != NULL) {
|
||||
BVariant value;
|
||||
status_t error = fFile->EvaluateDynamicValue(fCompilationUnit,
|
||||
fSubprogramEntry, bitStrideOwnerEntry->BitStride(),
|
||||
fTargetInterface, fInstructionPointer, fFramePointer,
|
||||
value);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
if (!value.IsInteger())
|
||||
return B_BAD_VALUE;
|
||||
dimensionStride = value.ToInt64();
|
||||
} else {
|
||||
DIEArrayIndexType* byteStrideOwnerEntry
|
||||
= DwarfUtils::GetDIEByPredicate(dimensionTypeEntry,
|
||||
HasByteStridePredicate<DIEArrayIndexType>());
|
||||
if (byteStrideOwnerEntry != NULL) {
|
||||
BVariant value;
|
||||
status_t error = fFile->EvaluateDynamicValue(
|
||||
fCompilationUnit, fSubprogramEntry,
|
||||
byteStrideOwnerEntry->ByteStride(), fTargetInterface,
|
||||
fInstructionPointer, fFramePointer, value);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
if (!value.IsInteger())
|
||||
return B_BAD_VALUE;
|
||||
dimensionStride = value.ToInt64() * 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have a stride for the dimension yet, use the stride of
|
||||
// the previous dimension multiplied by the size of the dimension.
|
||||
if (dimensionStride == 0) {
|
||||
if (previousDimension != NULL) {
|
||||
dimensionStride = previousDimensionStride
|
||||
* previousDimension->CountElements();
|
||||
} else {
|
||||
// the last dimension -- use the element bit stride
|
||||
dimensionStride = bitStride;
|
||||
}
|
||||
}
|
||||
|
||||
// If the dimension stride is still 0 (that can happen, if the dimension
|
||||
// doesn't have a stride and the previous dimension's element count is
|
||||
// not known), we can only resolve the first element.
|
||||
if (dimensionStride == 0 && index != 0) {
|
||||
WARNING("No dimension bit stride for dimension %ld and element "
|
||||
"index is not 0.\n", dimensionIndex);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
elementOffset += dimensionStride * index;
|
||||
|
||||
previousDimension = dimension;
|
||||
previousDimensionStride = dimensionStride;
|
||||
}
|
||||
|
||||
TRACE_LOCALS("total element bit offset: %lld\n", elementOffset);
|
||||
|
||||
// create the value location object for the element
|
||||
ValueLocation* location = new(std::nothrow) ValueLocation(
|
||||
parentLocation.IsBigEndian());
|
||||
if (location == NULL)
|
||||
return B_NO_MEMORY;
|
||||
Reference<ValueLocation> locationReference(location, true);
|
||||
|
||||
// If we have a single memory piece location for the array, we compute the
|
||||
// element's location by hand -- not uncommonly the array size isn't known.
|
||||
if (parentLocation.CountPieces() == 1) {
|
||||
ValuePieceLocation piece = parentLocation.PieceAt(0);
|
||||
if (piece.type == VALUE_PIECE_LOCATION_MEMORY) {
|
||||
int64 byteOffset = elementOffset >= 0
|
||||
? elementOffset / 8 : (elementOffset - 7) / 8;
|
||||
piece.SetToMemory(piece.address + byteOffset);
|
||||
piece.SetSize(type->BaseType()->ByteSize() * 8);
|
||||
// TODO: Support bit offsets correctly!
|
||||
// TODO: Support bit fields (primitive types) correctly!
|
||||
|
||||
if (!location->AddPiece(piece))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
_location = locationReference.Detach();
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// We can't deal with negative element offsets at this point. It doesn't
|
||||
// make a lot of sense anyway, if the array location consists of multiple
|
||||
// pieces or lives in a register.
|
||||
if (elementOffset < 0) {
|
||||
WARNING("Negative element offset unsupported for multiple location "
|
||||
"pieces or register pieces.\n");
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (!location->SetTo(parentLocation, elementOffset,
|
||||
type->BaseType()->ByteSize() * 8)) {
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
_location = locationReference.Detach();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DwarfStackFrameDebugInfo::CreateType(DIEType* typeEntry, Type*& _type)
|
||||
{
|
||||
@@ -1303,10 +1739,16 @@ DwarfStackFrameDebugInfo::_CreateTypeInternal(DIEType* typeEntry,
|
||||
dynamic_cast<DIESubrangeType*>(typeEntry), _type);
|
||||
|
||||
case DW_TAG_unspecified_type:
|
||||
return _CreateUnspecifiedType(name,
|
||||
dynamic_cast<DIEUnspecifiedType*>(typeEntry), _type);
|
||||
|
||||
case DW_TAG_subroutine_type:
|
||||
return _CreateFunctionType(name,
|
||||
dynamic_cast<DIESubroutineType*>(typeEntry), _type);
|
||||
|
||||
case DW_TAG_ptr_to_member_type:
|
||||
// TODO: Implement!
|
||||
return B_UNSUPPORTED;
|
||||
return _CreatePointerToMemberType(name,
|
||||
dynamic_cast<DIEPointerToMemberType*>(typeEntry), _type);
|
||||
|
||||
case DW_TAG_string_type:
|
||||
case DW_TAG_file_type:
|
||||
@@ -1523,14 +1965,24 @@ DwarfStackFrameDebugInfo::_CreateAddressType(const BString& name,
|
||||
// get the base type entry
|
||||
DIEAddressingType* baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate(
|
||||
typeEntry, HasTypePredicate<DIEAddressingType>());
|
||||
if (baseTypeOwnerEntry == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// create the base type
|
||||
DwarfType* baseType;
|
||||
status_t error = _CreateType(baseTypeOwnerEntry->GetType(), baseType);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
if (baseTypeOwnerEntry != NULL) {
|
||||
status_t error = _CreateType(baseTypeOwnerEntry->GetType(), baseType);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
} else {
|
||||
// According to the DWARF 3 specs a modified type *has* a base type.
|
||||
// GCC 4 doesn't (always?) bother to add one for "void".
|
||||
// TODO: We should probably search for a respective type by name. ATM
|
||||
// we just create a DwarfUnspecifiedType without DIE.
|
||||
TRACE_LOCALS("no base type for address type entry -- creating "
|
||||
"unspecified type\n");
|
||||
baseType = new(std::nothrow) DwarfUnspecifiedType("void", NULL);
|
||||
if (baseType == NULL)
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
Reference<Type> baseTypeReference(baseType, true);
|
||||
|
||||
DwarfAddressType* type = new(std::nothrow) DwarfAddressType(name, typeEntry,
|
||||
@@ -1867,9 +2319,9 @@ DwarfStackFrameDebugInfo::_CreateSubrangeType(const BString& name,
|
||||
}
|
||||
|
||||
if (isSigned)
|
||||
upperBound.SetTo(lowerBound.ToInt64() + count.ToInt64());
|
||||
upperBound.SetTo(lowerBound.ToInt64() + count.ToInt64() - 1);
|
||||
else
|
||||
upperBound.SetTo(lowerBound.ToUInt64() + count.ToUInt64());
|
||||
upperBound.SetTo(lowerBound.ToUInt64() + count.ToUInt64() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1902,6 +2354,144 @@ DwarfStackFrameDebugInfo::_CreateSubrangeType(const BString& name,
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DwarfStackFrameDebugInfo::_CreateUnspecifiedType(const BString& name,
|
||||
DIEUnspecifiedType* typeEntry, DwarfType*& _type)
|
||||
{
|
||||
DwarfUnspecifiedType* type = new(std::nothrow) DwarfUnspecifiedType(name,
|
||||
typeEntry);
|
||||
if (type == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
_type = type;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
DwarfStackFrameDebugInfo::_CreateFunctionType(const BString& name,
|
||||
DIESubroutineType* typeEntry, DwarfType*& _type)
|
||||
{
|
||||
// get the return type
|
||||
DIESubroutineType* returnTypeOwnerEntry = DwarfUtils::GetDIEByPredicate(
|
||||
typeEntry, HasReturnTypePredicate<DIESubroutineType>());
|
||||
|
||||
// create the base type
|
||||
DwarfType* returnType = NULL;
|
||||
if (returnTypeOwnerEntry != NULL) {
|
||||
status_t error = _CreateType(returnTypeOwnerEntry->ReturnType(),
|
||||
returnType);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
Reference<Type> returnTypeReference(returnType, true);
|
||||
|
||||
DwarfFunctionType* type = new(std::nothrow) DwarfFunctionType(name,
|
||||
typeEntry, returnType);
|
||||
if (type == NULL)
|
||||
return B_NO_MEMORY;
|
||||
Reference<DwarfType> typeReference(type, true);
|
||||
|
||||
// get the parameters
|
||||
DIESubroutineType* parameterOwnerEntry = DwarfUtils::GetDIEByPredicate(
|
||||
typeEntry, HasParametersPredicate<DIESubroutineType>());
|
||||
|
||||
if (parameterOwnerEntry != NULL) {
|
||||
for (DebugInfoEntryList::ConstIterator it
|
||||
= parameterOwnerEntry->Parameters().GetIterator();
|
||||
DebugInfoEntry* _parameterEntry = it.Next();) {
|
||||
if (_parameterEntry->Tag() == DW_TAG_unspecified_parameters) {
|
||||
type->SetHasVariableArguments(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
DIEFormalParameter* parameterEntry
|
||||
= dynamic_cast<DIEFormalParameter*>(_parameterEntry);
|
||||
|
||||
// get the type
|
||||
DIEFormalParameter* typeOwnerEntry = DwarfUtils::GetDIEByPredicate(
|
||||
parameterEntry, HasTypePredicate<DIEFormalParameter>());
|
||||
if (typeOwnerEntry == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
DwarfType* parameterType;
|
||||
status_t error = _CreateType(typeOwnerEntry->GetType(),
|
||||
parameterType);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
Reference<DwarfType> parameterTypeReference(parameterType, true);
|
||||
|
||||
// get the name
|
||||
BString parameterName;
|
||||
DwarfUtils::GetDIEName(parameterEntry, parameterName);
|
||||
|
||||
// create and add the parameter object
|
||||
DwarfFunctionParameter* parameter
|
||||
= new(std::nothrow) DwarfFunctionParameter(parameterEntry,
|
||||
parameterName, parameterType);
|
||||
Reference<DwarfFunctionParameter> parameterReference(parameter,
|
||||
true);
|
||||
if (parameter == NULL || !type->AddParameter(parameter))
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_type = typeReference.Detach();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DwarfStackFrameDebugInfo::_CreatePointerToMemberType(const BString& name,
|
||||
DIEPointerToMemberType* typeEntry, DwarfType*& _type)
|
||||
{
|
||||
// get the containing and base type entries
|
||||
DIEPointerToMemberType* containingTypeOwnerEntry
|
||||
= DwarfUtils::GetDIEByPredicate(typeEntry,
|
||||
HasContainingTypePredicate());
|
||||
DIEPointerToMemberType* baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate(
|
||||
typeEntry, HasTypePredicate<DIEPointerToMemberType>());
|
||||
|
||||
if (containingTypeOwnerEntry == NULL || baseTypeOwnerEntry == NULL) {
|
||||
WARNING("Failed to get containing or base type for pointer to member "
|
||||
"type \"%s\"\n", name.String());
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// create the containing type
|
||||
DwarfType* containingType;
|
||||
status_t error = _CreateType(containingTypeOwnerEntry->ContainingType(),
|
||||
containingType);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
Reference<Type> containingTypeReference(containingType, true);
|
||||
|
||||
DwarfCompoundType* compoundContainingType
|
||||
= dynamic_cast<DwarfCompoundType*>(containingType);
|
||||
if (compoundContainingType == NULL) {
|
||||
WARNING("Containing type for pointer to member type \"%s\" is not a "
|
||||
"compound type.\n", name.String());
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// create the base type
|
||||
DwarfType* baseType;
|
||||
error = _CreateType(baseTypeOwnerEntry->GetType(), baseType);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
Reference<Type> baseTypeReference(baseType, true);
|
||||
|
||||
// create the type object
|
||||
DwarfPointerToMemberType* type = new(std::nothrow) DwarfPointerToMemberType(
|
||||
name, typeEntry, compoundContainingType, baseType);
|
||||
if (type == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
_type = type;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DwarfStackFrameDebugInfo::_CreateVariable(ObjectID* id, const BString& name,
|
||||
DIEType* typeEntry, LocationDescription* locationDescription,
|
||||
@@ -2034,6 +2624,7 @@ DwarfStackFrameDebugInfo::_ResolveTypeByteSize(DIEType* typeEntry,
|
||||
break;
|
||||
case DW_TAG_pointer_type:
|
||||
case DW_TAG_reference_type:
|
||||
case DW_TAG_ptr_to_member_type:
|
||||
_size = fCompilationUnit->AddressSize();
|
||||
|
||||
TRACE_LOCALS(" pointer/reference type: size: %llu\n", _size);
|
||||
|
||||
@@ -22,10 +22,13 @@ class DIECompoundType;
|
||||
class DIEEnumerationType;
|
||||
class DIEFormalParameter;
|
||||
class DIEModifiedType;
|
||||
class DIEPointerToMemberType;
|
||||
class DIESubprogram;
|
||||
class DIESubrangeType;
|
||||
class DIESubroutineType;
|
||||
class DIEType;
|
||||
class DIETypedef;
|
||||
class DIEUnspecifiedType;
|
||||
class DIEVariable;
|
||||
class DwarfFile;
|
||||
class DwarfTargetInterface;
|
||||
@@ -65,6 +68,11 @@ public:
|
||||
DataMember* member,
|
||||
const ValueLocation& parentLocation,
|
||||
ValueLocation*& _location);
|
||||
virtual status_t ResolveArrayElementLocation(
|
||||
StackFrame* stackFrame, ArrayType* type,
|
||||
const ArrayIndexPath& indexPath,
|
||||
const ValueLocation& parentLocation,
|
||||
ValueLocation*& _location);
|
||||
|
||||
status_t CreateType(DIEType* typeEntry, Type*& _type);
|
||||
// returns reference
|
||||
@@ -85,6 +93,7 @@ private:
|
||||
struct DwarfDataMember;
|
||||
struct DwarfEnumerationValue;
|
||||
struct DwarfArrayDimension;
|
||||
struct DwarfFunctionParameter;
|
||||
struct DwarfPrimitiveType;
|
||||
struct DwarfCompoundType;
|
||||
struct DwarfModifiedType;
|
||||
@@ -93,6 +102,9 @@ private:
|
||||
struct DwarfEnumerationType;
|
||||
struct DwarfSubrangeType;
|
||||
struct DwarfArrayType;
|
||||
struct DwarfUnspecifiedType;
|
||||
struct DwarfFunctionType;
|
||||
struct DwarfPointerToMemberType;
|
||||
struct DwarfTypeHashDefinition;
|
||||
|
||||
typedef BOpenHashTable<DwarfTypeHashDefinition> TypeTable;
|
||||
@@ -136,6 +148,15 @@ private:
|
||||
status_t _CreateSubrangeType(const BString& name,
|
||||
DIESubrangeType* typeEntry,
|
||||
DwarfType*& _type);
|
||||
status_t _CreateUnspecifiedType(const BString& name,
|
||||
DIEUnspecifiedType* typeEntry,
|
||||
DwarfType*& _type);
|
||||
status_t _CreateFunctionType(const BString& name,
|
||||
DIESubroutineType* typeEntry,
|
||||
DwarfType*& _type);
|
||||
status_t _CreatePointerToMemberType(const BString& name,
|
||||
DIEPointerToMemberType* typeEntry,
|
||||
DwarfType*& _type);
|
||||
|
||||
status_t _CreateVariable(ObjectID* id,
|
||||
const BString& name, DIEType* typeEntry,
|
||||
|
||||
@@ -43,3 +43,12 @@ NoOpStackFrameDebugInfo::ResolveDataMemberLocation(StackFrame* stackFrame,
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
NoOpStackFrameDebugInfo::ResolveArrayElementLocation(StackFrame* stackFrame,
|
||||
ArrayType* type, const ArrayIndexPath& indexPath,
|
||||
const ValueLocation& parentLocation, ValueLocation*& _location)
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,11 @@ public:
|
||||
DataMember* member,
|
||||
const ValueLocation& parentLocation,
|
||||
ValueLocation*& _location);
|
||||
virtual status_t ResolveArrayElementLocation(
|
||||
StackFrame* stackFrame, ArrayType* type,
|
||||
const ArrayIndexPath& indexPath,
|
||||
const ValueLocation& parentLocation,
|
||||
ValueLocation*& _location);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "Types.h"
|
||||
|
||||
|
||||
class ArrayIndexPath;
|
||||
class ArrayType;
|
||||
class Architecture;
|
||||
class BaseType;
|
||||
class DataMember;
|
||||
@@ -46,6 +48,12 @@ public:
|
||||
const ValueLocation& parentLocation,
|
||||
ValueLocation*& _location) = 0;
|
||||
// returns a reference
|
||||
virtual status_t ResolveArrayElementLocation(
|
||||
StackFrame* stackFrame, ArrayType* type,
|
||||
const ArrayIndexPath& indexPath,
|
||||
const ValueLocation& parentLocation,
|
||||
ValueLocation*& _location) = 0;
|
||||
// returns a reference
|
||||
|
||||
protected:
|
||||
Architecture* fArchitecture;
|
||||
|
||||
@@ -548,7 +548,9 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
if (!baseIndexPath.SetTo(arrayComponent.name.String()))
|
||||
status_t error
|
||||
= baseIndexPath.SetTo(arrayComponent.name.String());
|
||||
if (error != B_OK)
|
||||
return;
|
||||
|
||||
baseDimension = baseIndexPath.CountIndices();
|
||||
@@ -579,10 +581,8 @@ private:
|
||||
|
||||
component.SetToArrayElement(type->Kind(), indexPath);
|
||||
TypeComponentPath* elementPath
|
||||
= new(std::nothrow) TypeComponentPath(*path);
|
||||
= path->CreateSubPath(path->CountComponents() - 1);
|
||||
if (elementPath == NULL
|
||||
|| elementPath->CountComponents()
|
||||
!= path->CountComponents()
|
||||
|| !elementPath->AddComponent(component)) {
|
||||
delete elementPath;
|
||||
return;
|
||||
@@ -604,10 +604,24 @@ private:
|
||||
case TYPE_ENUMERATION:
|
||||
TRACE_LOCALS("TYPE_ENUMERATION\n");
|
||||
done = true;
|
||||
break;
|
||||
case TYPE_SUBRANGE:
|
||||
TRACE_LOCALS("TYPE_SUBRANGE -> unsupported\n");
|
||||
// TODO: Support!
|
||||
return;
|
||||
default:
|
||||
TRACE_LOCALS("unknown\n");
|
||||
case TYPE_UNSPECIFIED:
|
||||
// Should never get here -- we don't create nodes for
|
||||
// unspecified types.
|
||||
TRACE_LOCALS("TYPE_UNSPECIFIED\n");
|
||||
return;
|
||||
case TYPE_FUNCTION:
|
||||
TRACE_LOCALS("TYPE_FUNCTION -> unsupported\n");
|
||||
// TODO: Support!
|
||||
return;
|
||||
case TYPE_POINTER_TO_MEMBER:
|
||||
TRACE_LOCALS("TYPE_POINTER_TO_MEMBER\n");
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (done) {
|
||||
@@ -627,6 +641,11 @@ private:
|
||||
TypeComponentPath* path, const BString& name, Type* type,
|
||||
bool isPresentationNode = false)
|
||||
{
|
||||
// Don't create nodes for unspecified types -- we can't get/show their
|
||||
// value anyway.
|
||||
if (type->Kind() == TYPE_UNSPECIFIED)
|
||||
return;
|
||||
|
||||
ValueNode* node = new(std::nothrow) ValueNode(parent, variable, path,
|
||||
name, type, isPresentationNode);
|
||||
if (node == NULL || !parent->AddChild(node)) {
|
||||
@@ -660,8 +679,22 @@ private:
|
||||
|
||||
for (int32 componentIndex = i;
|
||||
componentIndex < childComponentCount; componentIndex++) {
|
||||
if (childPath->ComponentAt(componentIndex)
|
||||
!= path->ComponentAt(componentIndex)) {
|
||||
TypeComponent childComponent
|
||||
= childPath->ComponentAt(componentIndex);
|
||||
TypeComponent pathComponent
|
||||
= path->ComponentAt(componentIndex);
|
||||
if (childComponent != pathComponent) {
|
||||
if (componentIndex + 1 == childComponentCount
|
||||
&& pathComponent.HasPrefix(childComponent)) {
|
||||
// The last child component is a prefix of the
|
||||
// corresponding path component. We consider this a
|
||||
// match, but need to recheck the component with the
|
||||
// next node level.
|
||||
childComponentCount--;
|
||||
break;
|
||||
}
|
||||
|
||||
// mismatch -- skip the child
|
||||
childNode = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -50,20 +50,28 @@ ArrayDimension::CountElements() const
|
||||
if (type->Kind() == TYPE_SUBRANGE) {
|
||||
SubrangeType* subrangeType = dynamic_cast<SubrangeType*>(type);
|
||||
BVariant lower = subrangeType->LowerBound();
|
||||
BVariant upper = subrangeType->LowerBound();
|
||||
BVariant upper = subrangeType->UpperBound();
|
||||
bool isSigned;
|
||||
if (!lower.IsInteger(&isSigned) || !upper.IsInteger())
|
||||
return 0;
|
||||
|
||||
return isSigned
|
||||
? upper.ToInt64() - lower.ToInt64()
|
||||
: upper.ToUInt64() - lower.ToUInt64();
|
||||
? upper.ToInt64() - lower.ToInt64() + 1
|
||||
: upper.ToUInt64() - lower.ToUInt64() + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - FunctionParameter
|
||||
|
||||
|
||||
FunctionParameter::~FunctionParameter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Type
|
||||
|
||||
|
||||
@@ -224,3 +232,48 @@ ArrayType::Kind() const
|
||||
{
|
||||
return TYPE_ARRAY;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - UnspecifiedType
|
||||
|
||||
|
||||
UnspecifiedType::~UnspecifiedType()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
type_kind
|
||||
UnspecifiedType::Kind() const
|
||||
{
|
||||
return TYPE_UNSPECIFIED;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - FunctionType
|
||||
|
||||
|
||||
FunctionType::~FunctionType()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
type_kind
|
||||
FunctionType::Kind() const
|
||||
{
|
||||
return TYPE_FUNCTION;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - PointerToMemberType
|
||||
|
||||
|
||||
PointerToMemberType::~PointerToMemberType()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
type_kind
|
||||
PointerToMemberType::Kind() const
|
||||
{
|
||||
return TYPE_POINTER_TO_MEMBER;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,10 @@ enum type_kind {
|
||||
TYPE_ADDRESS,
|
||||
TYPE_ENUMERATION,
|
||||
TYPE_SUBRANGE,
|
||||
TYPE_ARRAY
|
||||
TYPE_ARRAY,
|
||||
TYPE_UNSPECIFIED,
|
||||
TYPE_FUNCTION,
|
||||
TYPE_POINTER_TO_MEMBER
|
||||
};
|
||||
|
||||
|
||||
@@ -79,6 +82,15 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class FunctionParameter : public Referenceable {
|
||||
public:
|
||||
virtual ~FunctionParameter();
|
||||
|
||||
virtual const char* Name() const = 0;
|
||||
virtual Type* GetType() const = 0;
|
||||
};
|
||||
|
||||
|
||||
class Type : public Referenceable {
|
||||
public:
|
||||
virtual ~Type();
|
||||
@@ -190,4 +202,38 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class UnspecifiedType : public virtual Type {
|
||||
public:
|
||||
virtual ~UnspecifiedType();
|
||||
|
||||
virtual type_kind Kind() const;
|
||||
};
|
||||
|
||||
|
||||
class FunctionType : public virtual Type {
|
||||
public:
|
||||
virtual ~FunctionType();
|
||||
|
||||
virtual type_kind Kind() const;
|
||||
|
||||
virtual Type* ReturnType() const = 0;
|
||||
|
||||
virtual int32 CountParameters() const = 0;
|
||||
virtual FunctionParameter* ParameterAt(int32 index) const = 0;
|
||||
|
||||
virtual bool HasVariableArguments() const = 0;
|
||||
};
|
||||
|
||||
|
||||
class PointerToMemberType : public virtual Type {
|
||||
public:
|
||||
virtual ~PointerToMemberType();
|
||||
|
||||
virtual type_kind Kind() const;
|
||||
|
||||
virtual CompoundType* ContainingType() const = 0;
|
||||
virtual Type* BaseType() const = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // TYPE_H
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
// #pragma mark - TypeComponent
|
||||
|
||||
|
||||
bool
|
||||
TypeComponent::HasPrefix(const TypeComponent& other) const
|
||||
{
|
||||
if (*this == other)
|
||||
return true;
|
||||
|
||||
return componentKind == TYPE_COMPONENT_ARRAY_ELEMENT
|
||||
&& other.componentKind == TYPE_COMPONENT_ARRAY_ELEMENT
|
||||
&& name.Compare(other.name, other.name.Length()) == 0;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
TypeComponent::HashValue() const
|
||||
{
|
||||
@@ -52,6 +64,15 @@ TypeComponent::Dump() const
|
||||
case TYPE_ARRAY:
|
||||
printf("array");
|
||||
break;
|
||||
case TYPE_UNSPECIFIED:
|
||||
printf("unspecified");
|
||||
break;
|
||||
case TYPE_FUNCTION:
|
||||
printf("function");
|
||||
break;
|
||||
case TYPE_POINTER_TO_MEMBER:
|
||||
printf("pointer to member");
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" ");
|
||||
|
||||
@@ -85,6 +85,8 @@ struct TypeComponent {
|
||||
return indexPath.GetPathString(this->name);
|
||||
}
|
||||
|
||||
bool HasPrefix(const TypeComponent& other) const;
|
||||
|
||||
uint32 HashValue() const;
|
||||
|
||||
void Dump() const;
|
||||
|
||||
@@ -31,33 +31,33 @@ ArrayIndexPath::~ArrayIndexPath()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
status_t
|
||||
ArrayIndexPath::SetTo(const char* path)
|
||||
{
|
||||
fIndices.Clear();
|
||||
|
||||
if (path == NULL)
|
||||
return true;
|
||||
return B_OK;
|
||||
|
||||
while (*path != '\0') {
|
||||
char* numberEnd;
|
||||
int64 index = strtoll(path, &numberEnd, 0);
|
||||
if (numberEnd == path)
|
||||
return false;
|
||||
return B_BAD_VALUE;
|
||||
path = numberEnd;
|
||||
|
||||
if (!fIndices.Add(index))
|
||||
return false;
|
||||
return B_NO_MEMORY;
|
||||
|
||||
if (*path == '\0')
|
||||
break;
|
||||
|
||||
if (*path != kIndexSeparator)
|
||||
return false;
|
||||
return B_BAD_VALUE;
|
||||
path++;
|
||||
}
|
||||
|
||||
return true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
ArrayIndexPath(const ArrayIndexPath& other);
|
||||
~ArrayIndexPath();
|
||||
|
||||
bool SetTo(const char* path);
|
||||
status_t SetTo(const char* path);
|
||||
void Clear();
|
||||
|
||||
bool GetPathString(BString& path) const;
|
||||
|
||||
Reference in New Issue
Block a user