* ValueLocation:
- Changed the bit{Offset,Size} semantics. It's now more or less
aligned with the semantics of the respective DWARF DIE attributes.
DwarfStackFrameDebugInfo does now correctly translate the ValueLocations
returned by the DWARF layer (the bit piece location expression semantics is
different for some reason).
- ValueLocation is now aware of the target's endianess. The SetTo() method
needs that information to correctly meddle with the pieces.
- Support normalizing the pieces.
* Fixed retrieving the values of bit fields in various places. We still don't
handle the bit offset/size attributes of types correctly, but I haven't seen
those in actual debug info yet.
* Added support for enumerations. The variable view shows the enumerator names,
when available.
* Added partial support for subrange types. C++ doesn't have those -- we only
need them for array dimensions.
* Started adding support for array types. Still work in progress.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33314 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+83
-38
@@ -519,10 +519,13 @@ GetStackFrameValueJob::_GetValue()
|
||||
|
||||
// find out the type of the data we want to read
|
||||
type_code valueType = 0;
|
||||
bool shortValueIsFine = false;
|
||||
while (valueType == 0) {
|
||||
switch (type->Kind()) {
|
||||
case TYPE_PRIMITIVE:
|
||||
valueType = dynamic_cast<PrimitiveType*>(type)->TypeConstant();
|
||||
shortValueIsFine = BVariant::TypeIsInteger(valueType)
|
||||
|| valueType == B_BOOL_TYPE;
|
||||
|
||||
TRACE_LOCALS(" TYPE_PRIMITIVE: '%c%c%c%c'\n",
|
||||
int(valueType >> 24), int(valueType >> 16),
|
||||
@@ -560,6 +563,38 @@ GetStackFrameValueJob::_GetValue()
|
||||
// recursion work smoothly, we have to set the type and
|
||||
// location at least.
|
||||
return _SetValue(BVariant(), actualType, location);
|
||||
case TYPE_ENUMERATION:
|
||||
{
|
||||
TRACE_LOCALS(" TYPE_ENUMERATION\n");
|
||||
// If a base type is known, use that.
|
||||
EnumerationType* enumType
|
||||
= dynamic_cast<EnumerationType*>(type);
|
||||
if (enumType->BaseType() != NULL) {
|
||||
type = enumType->BaseType();
|
||||
break;
|
||||
}
|
||||
|
||||
// get the value type constant
|
||||
// TODO: This is C source language specific!
|
||||
switch (enumType->ByteSize()) {
|
||||
case 1:
|
||||
valueType = B_INT8_TYPE;
|
||||
break;
|
||||
case 2:
|
||||
valueType = B_INT16_TYPE;
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
valueType = B_INT32_TYPE;
|
||||
break;
|
||||
case 8:
|
||||
valueType = B_INT64_TYPE;
|
||||
break;
|
||||
}
|
||||
|
||||
shortValueIsFine = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
TRACE_LOCALS(" default -> unsupported\n");
|
||||
return B_UNSUPPORTED;
|
||||
@@ -578,7 +613,7 @@ GetStackFrameValueJob::_GetValue()
|
||||
// check whether we know the complete location
|
||||
int32 count = location->CountPieces();
|
||||
|
||||
TRACE_LOCALS(" location: %p, %ld pieces\n", location, count);
|
||||
TRACE_LOCALS_ONLY(location->Dump();)
|
||||
|
||||
if (count == 0) {
|
||||
TRACE_LOCALS(" -> no location\n");
|
||||
@@ -592,7 +627,7 @@ GetStackFrameValueJob::_GetValue()
|
||||
if (piece.type == VALUE_PIECE_LOCATION_MEMORY) {
|
||||
ValueLocation* dataLocation;
|
||||
error = fStackFrame->DebugInfo()->ResolveObjectDataLocation(
|
||||
fStackFrame, type, piece.address, dataLocation);
|
||||
fStackFrame, type, *location, dataLocation);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
@@ -601,7 +636,7 @@ GetStackFrameValueJob::_GetValue()
|
||||
}
|
||||
}
|
||||
|
||||
target_size_t totalSize = 0;
|
||||
static const size_t kMaxPieceSize = 16;
|
||||
uint64 totalBitSize = 0;
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
ValuePieceLocation piece = location->PieceAt(i);
|
||||
@@ -614,48 +649,51 @@ GetStackFrameValueJob::_GetValue()
|
||||
break;
|
||||
}
|
||||
|
||||
totalSize += piece.size;
|
||||
if (piece.size > kMaxPieceSize) {
|
||||
TRACE_LOCALS(" -> overly long piece size (%llu bytes)\n",
|
||||
piece.size);
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
totalBitSize += piece.bitSize;
|
||||
}
|
||||
|
||||
TRACE_LOCALS(" -> totalSize: %llu, totalBitSize: %llu\n", totalSize,
|
||||
totalBitSize);
|
||||
TRACE_LOCALS(" -> totalBitSize: %llu\n", totalBitSize);
|
||||
|
||||
if (totalSize == 0 && totalBitSize == 0) {
|
||||
if (totalBitSize == 0) {
|
||||
TRACE_LOCALS(" -> no size\n");
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (totalSize > 8 || totalSize + (totalBitSize + 7) / 8 > 8) {
|
||||
TRACE_LOCALS(" -> longer than 8 bytes: unsupported\n");
|
||||
if (totalBitSize > 64) {
|
||||
TRACE_LOCALS(" -> longer than 64 bits: unsupported\n");
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (totalSize + (totalBitSize + 7) / 8 < BVariant::SizeOfType(valueType)) {
|
||||
TRACE_LOCALS(" -> too short for value type (%llu vs. %lu)\n",
|
||||
totalSize + (totalBitSize + 7) / 8,
|
||||
BVariant::SizeOfType(valueType));
|
||||
uint64 valueBitSize = BVariant::SizeOfType(valueType) * 8;
|
||||
if (!shortValueIsFine && totalBitSize < valueBitSize) {
|
||||
TRACE_LOCALS(" -> too short for value type (%llu vs. %llu bits)\n",
|
||||
totalBitSize, valueBitSize);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// load the data
|
||||
// Load the data. Since the BitBuffer class we're using only supports big
|
||||
// endian bit semantics, we convert all data to big endian before pushing
|
||||
// them to the buffer. For later conversion to BVariant we need to make sure
|
||||
// the final buffer has the size of the value type, so we pad the most
|
||||
// significant bits with zeros.
|
||||
BitBuffer valueBuffer;
|
||||
if (totalBitSize < valueBitSize)
|
||||
valueBuffer.AddZeroBits(valueBitSize - totalBitSize);
|
||||
|
||||
// If the total bit size is not byte aligned, push the respective number of
|
||||
// 0 bits on a big endian architecture to get an immediately usable value.
|
||||
// On a little endian architecture we'll play with the last read byte
|
||||
// instead.
|
||||
if (fArchitecture->IsBigEndian() && totalBitSize % 8 != 0) {
|
||||
const uint8 zero = 0;
|
||||
valueBuffer.AddBits(&zero, 8 - totalBitSize % 8, 0);
|
||||
}
|
||||
|
||||
bool bigEndian = fArchitecture->IsBigEndian();
|
||||
const Register* registers = fArchitecture->Registers();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
ValuePieceLocation piece = location->PieceAt(i);
|
||||
ValuePieceLocation piece = location->PieceAt(
|
||||
bigEndian ? i : count - i - 1);
|
||||
uint32 bytesToRead = piece.size;
|
||||
uint32 bitSize = piece.bitSize;
|
||||
uint8 bitOffset = piece.bitOffset;
|
||||
uint32 bitSize = piece.size * 8 + piece.bitSize;
|
||||
uint32 bytesToRead = (bitSize + 7) / 8;
|
||||
|
||||
switch (piece.type) {
|
||||
case VALUE_PIECE_LOCATION_INVALID:
|
||||
@@ -663,13 +701,12 @@ GetStackFrameValueJob::_GetValue()
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
case VALUE_PIECE_LOCATION_MEMORY:
|
||||
{
|
||||
target_addr_t address = piece.address + bitOffset / 8;
|
||||
target_addr_t address = piece.address;
|
||||
|
||||
TRACE_LOCALS(" piece %ld: memory address: %#llx, bits: %lu\n",
|
||||
i, address, bitSize);
|
||||
|
||||
bitOffset %= 8;
|
||||
uint8 pieceBuffer[8];
|
||||
uint8 pieceBuffer[kMaxPieceSize];
|
||||
ssize_t bytesRead = fDebuggerInterface->ReadMemory(address,
|
||||
pieceBuffer, bytesToRead);
|
||||
if (bytesRead < 0)
|
||||
@@ -684,6 +721,14 @@ GetStackFrameValueJob::_GetValue()
|
||||
TRACE_LOCALS("\n");
|
||||
)
|
||||
|
||||
// convert to big endian
|
||||
if (!bigEndian) {
|
||||
for (int32 k = bytesRead / 2 - 1; k >= 0; k--) {
|
||||
std::swap(pieceBuffer[k],
|
||||
pieceBuffer[bytesRead - k - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
valueBuffer.AddBits(pieceBuffer, bitSize, bitOffset);
|
||||
break;
|
||||
}
|
||||
@@ -700,7 +745,7 @@ GetStackFrameValueJob::_GetValue()
|
||||
if (registerValue.Size() < bytesToRead)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
if (!fArchitecture->IsHostEndian())
|
||||
if (!bigEndian)
|
||||
registerValue.SwapEndianess();
|
||||
valueBuffer.AddBits(registerValue.Bytes(), bitSize, bitOffset);
|
||||
break;
|
||||
@@ -708,12 +753,9 @@ GetStackFrameValueJob::_GetValue()
|
||||
}
|
||||
}
|
||||
|
||||
// If the total bit size is not byte aligned, shift the last byte by the
|
||||
// respective number of bits on a little endian architecture to get a usable
|
||||
// value.
|
||||
if (!fArchitecture->IsBigEndian() && totalBitSize % 8 != 0)
|
||||
valueBuffer.Bytes()[totalBitSize / 8] >>= 8 - totalBitSize % 8;
|
||||
// TODO: Verify that this is the way to handle it!
|
||||
// If we don't have enough bits in the buffer apparently adding some failed.
|
||||
if (valueBuffer.BitSize() < valueBitSize)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// convert the bits into something we can work with
|
||||
BVariant value;
|
||||
@@ -723,8 +765,10 @@ GetStackFrameValueJob::_GetValue()
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!fArchitecture->IsHostEndian())
|
||||
// convert to host endianess
|
||||
#if B_HOST_IS_LENDIAN
|
||||
value.SwapEndianess();
|
||||
#endif
|
||||
|
||||
return _SetValue(value, actualType, location);
|
||||
}
|
||||
@@ -788,9 +832,10 @@ GetStackFrameValueJob::_ResolveTypeAndLocation(Type*& _type,
|
||||
TypeComponent component = fPath->ComponentAt(componentCount - 1);
|
||||
switch (component.typeKind) {
|
||||
case TYPE_PRIMITIVE:
|
||||
case TYPE_ENUMERATION:
|
||||
// cannot happen
|
||||
TRACE_LOCALS("GetStackFrameValueJob::_ResolveTypeAndLocation(): "
|
||||
"TYPE_PRIMITIVE subcomponent!\n");
|
||||
"TYPE_PRIMITIVE/TYPE_ENUMERATION subcomponent!\n");
|
||||
return B_BAD_VALUE;
|
||||
case TYPE_COMPOUND:
|
||||
{
|
||||
|
||||
@@ -322,7 +322,7 @@ ArchitectureX86::CreateStackFrame(Image* image, FunctionDebugInfo* function,
|
||||
|
||||
// create the stack frame
|
||||
StackFrameDebugInfo* stackFrameDebugInfo
|
||||
= new(std::nothrow) NoOpStackFrameDebugInfo;
|
||||
= new(std::nothrow) NoOpStackFrameDebugInfo(this);
|
||||
if (stackFrameDebugInfo == NULL)
|
||||
return B_NO_MEMORY;
|
||||
Reference<StackFrameDebugInfo> stackFrameDebugInfoReference(
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
#include "TeamMemory.h"
|
||||
#include "Tracing.h"
|
||||
#include "UnsupportedLanguage.h"
|
||||
#include "ValueLocation.h"
|
||||
#include "Variable.h"
|
||||
|
||||
|
||||
@@ -397,7 +396,7 @@ DwarfImageDebugInfo::CreateFrame(Image* image,
|
||||
// create the stack frame debug info
|
||||
DIESubprogram* subprogramEntry = function->SubprogramEntry();
|
||||
DwarfStackFrameDebugInfo* stackFrameDebugInfo
|
||||
= new(std::nothrow) DwarfStackFrameDebugInfo(fFile, unit,
|
||||
= new(std::nothrow) DwarfStackFrameDebugInfo(fArchitecture, fFile, unit,
|
||||
subprogramEntry, instructionPointer, framePointer, inputInterface,
|
||||
fromDwarfMap);
|
||||
if (stackFrameDebugInfo == NULL)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,9 +19,11 @@ class DIEAddressingType;
|
||||
class DIEArrayType;
|
||||
class DIEBaseType;
|
||||
class DIECompoundType;
|
||||
class DIEEnumerationType;
|
||||
class DIEFormalParameter;
|
||||
class DIEModifiedType;
|
||||
class DIESubprogram;
|
||||
class DIESubrangeType;
|
||||
class DIEType;
|
||||
class DIETypedef;
|
||||
class DIEVariable;
|
||||
@@ -37,7 +39,8 @@ class Variable;
|
||||
|
||||
class DwarfStackFrameDebugInfo : public StackFrameDebugInfo {
|
||||
public:
|
||||
DwarfStackFrameDebugInfo(DwarfFile* file,
|
||||
DwarfStackFrameDebugInfo(
|
||||
Architecture* architecture, DwarfFile* file,
|
||||
CompilationUnit* compilationUnit,
|
||||
DIESubprogram* subprogramEntry,
|
||||
target_addr_t instructionPointer,
|
||||
@@ -50,7 +53,7 @@ public:
|
||||
|
||||
virtual status_t ResolveObjectDataLocation(
|
||||
StackFrame* stackFrame, Type* type,
|
||||
target_addr_t objectAddress,
|
||||
const ValueLocation& objectLocation,
|
||||
ValueLocation*& _location);
|
||||
virtual status_t ResolveBaseTypeLocation(
|
||||
StackFrame* stackFrame, Type* type,
|
||||
@@ -80,11 +83,15 @@ private:
|
||||
struct DwarfType;
|
||||
struct DwarfInheritance;
|
||||
struct DwarfDataMember;
|
||||
struct DwarfEnumerationValue;
|
||||
struct DwarfArrayDimension;
|
||||
struct DwarfPrimitiveType;
|
||||
struct DwarfCompoundType;
|
||||
struct DwarfModifiedType;
|
||||
struct DwarfTypedefType;
|
||||
struct DwarfAddressType;
|
||||
struct DwarfEnumerationType;
|
||||
struct DwarfSubrangeType;
|
||||
struct DwarfArrayType;
|
||||
struct DwarfTypeHashDefinition;
|
||||
|
||||
@@ -123,6 +130,12 @@ private:
|
||||
status_t _CreateArrayType(const BString& name,
|
||||
DIEArrayType* typeEntry,
|
||||
DwarfType*& _type);
|
||||
status_t _CreateEnumerationType(const BString& name,
|
||||
DIEEnumerationType* typeEntry,
|
||||
DwarfType*& _type);
|
||||
status_t _CreateSubrangeType(const BString& name,
|
||||
DIESubrangeType* typeEntry,
|
||||
DwarfType*& _type);
|
||||
|
||||
status_t _CreateVariable(ObjectID* id,
|
||||
const BString& name, DIEType* typeEntry,
|
||||
@@ -134,8 +147,10 @@ private:
|
||||
status_t _ResolveTypeByteSize(DIEType* typeEntry,
|
||||
uint64& _size);
|
||||
|
||||
void _FixLocation(ValueLocation* location,
|
||||
DwarfType* type);
|
||||
status_t _ResolveLocation(
|
||||
const LocationDescription* description,
|
||||
target_addr_t objectAddress, Type* type,
|
||||
ValueLocation& _location);
|
||||
|
||||
template<typename EntryType>
|
||||
static DIEType* _GetDIEType(EntryType* entry);
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
#include "NoOpStackFrameDebugInfo.h"
|
||||
|
||||
|
||||
NoOpStackFrameDebugInfo::NoOpStackFrameDebugInfo()
|
||||
NoOpStackFrameDebugInfo::NoOpStackFrameDebugInfo(Architecture* architecture)
|
||||
:
|
||||
StackFrameDebugInfo(architecture)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -19,7 +21,7 @@ NoOpStackFrameDebugInfo::~NoOpStackFrameDebugInfo()
|
||||
|
||||
status_t
|
||||
NoOpStackFrameDebugInfo::ResolveObjectDataLocation(StackFrame* stackFrame,
|
||||
Type* type, target_addr_t objectAddress, ValueLocation*& _location)
|
||||
Type* type, const ValueLocation& objectLocation, ValueLocation*& _location)
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
|
||||
class NoOpStackFrameDebugInfo : public StackFrameDebugInfo {
|
||||
public:
|
||||
NoOpStackFrameDebugInfo();
|
||||
NoOpStackFrameDebugInfo(
|
||||
Architecture* architecture);
|
||||
virtual ~NoOpStackFrameDebugInfo();
|
||||
|
||||
virtual status_t ResolveObjectDataLocation(
|
||||
StackFrame* stackFrame, Type* type,
|
||||
target_addr_t objectAddress,
|
||||
const ValueLocation& objectLocation,
|
||||
ValueLocation*& _location);
|
||||
virtual status_t ResolveBaseTypeLocation(
|
||||
StackFrame* stackFrame, Type* type,
|
||||
|
||||
@@ -6,12 +6,39 @@
|
||||
|
||||
#include "StackFrameDebugInfo.h"
|
||||
|
||||
#include "Architecture.h"
|
||||
#include "ValueLocation.h"
|
||||
|
||||
StackFrameDebugInfo::StackFrameDebugInfo()
|
||||
|
||||
StackFrameDebugInfo::StackFrameDebugInfo(Architecture* architecture)
|
||||
:
|
||||
fArchitecture(architecture)
|
||||
{
|
||||
fArchitecture->AcquireReference();
|
||||
}
|
||||
|
||||
|
||||
StackFrameDebugInfo::~StackFrameDebugInfo()
|
||||
{
|
||||
fArchitecture->ReleaseReference();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
StackFrameDebugInfo::ResolveObjectDataLocation(StackFrame* stackFrame,
|
||||
Type* type, target_addr_t objectAddress, ValueLocation*& _location)
|
||||
{
|
||||
ValuePieceLocation piece;
|
||||
piece.SetToMemory(objectAddress);
|
||||
piece.SetSize(0);
|
||||
// We set the piece size to 0 as an indicator that the size has to be
|
||||
// set.
|
||||
// TODO: We could set the byte size from type, but that may not be
|
||||
// accurate. We may want to add bit offset and size to Type.
|
||||
|
||||
ValueLocation location(fArchitecture->IsBigEndian());
|
||||
if (!location.AddPiece(piece))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
return ResolveObjectDataLocation(stackFrame, type, location, _location);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "Types.h"
|
||||
|
||||
|
||||
class Architecture;
|
||||
class BaseType;
|
||||
class DataMember;
|
||||
class StackFrame;
|
||||
@@ -20,14 +21,19 @@ class ValueLocation;
|
||||
|
||||
class StackFrameDebugInfo : public Referenceable {
|
||||
public:
|
||||
StackFrameDebugInfo();
|
||||
StackFrameDebugInfo(Architecture* architecture);
|
||||
virtual ~StackFrameDebugInfo();
|
||||
|
||||
virtual status_t ResolveObjectDataLocation(
|
||||
StackFrame* stackFrame, Type* type,
|
||||
target_addr_t objectAddress,
|
||||
const ValueLocation& objectLocation,
|
||||
ValueLocation*& _location) = 0;
|
||||
// returns a reference
|
||||
status_t ResolveObjectDataLocation(
|
||||
StackFrame* stackFrame, Type* type,
|
||||
target_addr_t objectAddress,
|
||||
ValueLocation*& _location);
|
||||
// returns a reference
|
||||
virtual status_t ResolveBaseTypeLocation(
|
||||
StackFrame* stackFrame, Type* type,
|
||||
BaseType* baseType,
|
||||
@@ -40,6 +46,9 @@ public:
|
||||
const ValueLocation& parentLocation,
|
||||
ValueLocation*& _location) = 0;
|
||||
// returns a reference
|
||||
|
||||
protected:
|
||||
Architecture* fArchitecture;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -24,7 +24,12 @@
|
||||
#include "Variable.h"
|
||||
|
||||
|
||||
class VariablesView::ValueNode : Referenceable {
|
||||
enum {
|
||||
VALUE_NODE_TYPE = 'valn'
|
||||
};
|
||||
|
||||
|
||||
class VariablesView::ValueNode : public Referenceable {
|
||||
public:
|
||||
ValueNode(ValueNode* parent, Variable* variable, TypeComponentPath* path,
|
||||
const BString& name, Type* type)
|
||||
@@ -34,11 +39,13 @@ public:
|
||||
fPath(path),
|
||||
fName(name),
|
||||
fType(type),
|
||||
fRawType(type->ResolveRawType()),
|
||||
fChildrenAdded(false)
|
||||
{
|
||||
fVariable->AcquireReference();
|
||||
fPath->AcquireReference();
|
||||
fType->AcquireReference();
|
||||
fRawType->AcquireReference();
|
||||
}
|
||||
|
||||
~ValueNode()
|
||||
@@ -49,6 +56,7 @@ public:
|
||||
fVariable->ReleaseReference();
|
||||
fPath->ReleaseReference();
|
||||
fType->ReleaseReference();
|
||||
fRawType->ReleaseReference();
|
||||
}
|
||||
|
||||
ValueNode* Parent() const
|
||||
@@ -76,6 +84,11 @@ public:
|
||||
return fType;
|
||||
}
|
||||
|
||||
Type* RawType() const
|
||||
{
|
||||
return fRawType;
|
||||
}
|
||||
|
||||
const BVariant& Value() const
|
||||
{
|
||||
return fValue;
|
||||
@@ -129,6 +142,7 @@ private:
|
||||
TypeComponentPath* fPath;
|
||||
BString fName;
|
||||
Type* fType;
|
||||
Type* fRawType;
|
||||
BVariant fValue;
|
||||
ChildList fChildren;
|
||||
bool fChildrenAdded;
|
||||
@@ -150,16 +164,21 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual BField* PrepareField(const BVariant& value) const
|
||||
virtual BField* PrepareField(const BVariant& _value) const
|
||||
{
|
||||
BVariant value = _ResolveValue(_value);
|
||||
|
||||
char buffer[64];
|
||||
return StringTableColumn::PrepareField(
|
||||
BVariant(_ToString(value, buffer, sizeof(buffer)),
|
||||
B_VARIANT_DONT_COPY_DATA));
|
||||
}
|
||||
|
||||
virtual int CompareValues(const BVariant& a, const BVariant& b)
|
||||
virtual int CompareValues(const BVariant& _a, const BVariant& _b)
|
||||
{
|
||||
BVariant a = _ResolveValue(_a);
|
||||
BVariant b = _ResolveValue(_b);
|
||||
|
||||
// If neither value is a number, compare the strings. If only one value
|
||||
// is a number, it is considered to be greater.
|
||||
if (!a.IsNumber()) {
|
||||
@@ -190,6 +209,26 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
BVariant _ResolveValue(const BVariant& nodeValue) const
|
||||
{
|
||||
BVariant value;
|
||||
if (nodeValue.Type() != VALUE_NODE_TYPE)
|
||||
return BVariant();
|
||||
|
||||
ValueNode* node = dynamic_cast<ValueNode*>(nodeValue.ToReferenceable());
|
||||
|
||||
// replace enumerations values with their names
|
||||
if (node->RawType()->Kind() == TYPE_ENUMERATION) {
|
||||
EnumerationValue* enumValue
|
||||
= dynamic_cast<EnumerationType*>(node->RawType())
|
||||
->ValueFor(node->Value());
|
||||
if (enumValue != NULL)
|
||||
return enumValue->Name();
|
||||
}
|
||||
|
||||
return node->Value();
|
||||
}
|
||||
|
||||
const char* _ToString(const BVariant& value, char* buffer,
|
||||
size_t bufferSize) const
|
||||
{
|
||||
@@ -329,7 +368,7 @@ public:
|
||||
if (node->Value().Type() == 0)
|
||||
return false;
|
||||
|
||||
_value = node->Value();
|
||||
_value.SetTo(node, VALUE_NODE_TYPE);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -484,6 +523,10 @@ private:
|
||||
TRACE_LOCALS("TYPE_ARRAY\n");
|
||||
// TODO:...
|
||||
return;
|
||||
case TYPE_ENUMERATION:
|
||||
TRACE_LOCALS("TYPE_ENUMERATION\n");
|
||||
done = true;
|
||||
return;
|
||||
default:
|
||||
TRACE_LOCALS("unknown\n");
|
||||
return;
|
||||
|
||||
@@ -23,6 +23,47 @@ DataMember::~DataMember()
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - EnumerationValue
|
||||
|
||||
|
||||
EnumerationValue::~EnumerationValue()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - ArrayDimension
|
||||
|
||||
|
||||
ArrayDimension::~ArrayDimension()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
uint64
|
||||
ArrayDimension::CountElements() const
|
||||
{
|
||||
Type* type = GetType();
|
||||
|
||||
if (type->Kind() == TYPE_ENUMERATION)
|
||||
return dynamic_cast<EnumerationType*>(type)->CountValues();
|
||||
|
||||
if (type->Kind() == TYPE_SUBRANGE) {
|
||||
SubrangeType* subrangeType = dynamic_cast<SubrangeType*>(type);
|
||||
BVariant lower = subrangeType->LowerBound();
|
||||
BVariant upper = subrangeType->LowerBound();
|
||||
bool isSigned;
|
||||
if (!lower.IsInteger(&isSigned) || !upper.IsInteger())
|
||||
return 0;
|
||||
|
||||
return isSigned
|
||||
? upper.ToInt64() - lower.ToInt64()
|
||||
: upper.ToUInt64() - lower.ToUInt64();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Type
|
||||
|
||||
|
||||
@@ -31,6 +72,13 @@ Type::~Type()
|
||||
}
|
||||
|
||||
|
||||
Type*
|
||||
Type::ResolveRawType() const
|
||||
{
|
||||
return const_cast<Type*>(this);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - PrimitiveType
|
||||
|
||||
|
||||
@@ -76,6 +124,13 @@ ModifiedType::Kind() const
|
||||
}
|
||||
|
||||
|
||||
Type*
|
||||
ModifiedType::ResolveRawType() const
|
||||
{
|
||||
return BaseType();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - TypedefType
|
||||
|
||||
|
||||
@@ -91,6 +146,13 @@ TypedefType::Kind() const
|
||||
}
|
||||
|
||||
|
||||
Type*
|
||||
TypedefType::ResolveRawType() const
|
||||
{
|
||||
return BaseType();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - AddressType
|
||||
|
||||
|
||||
@@ -106,6 +168,49 @@ AddressType::Kind() const
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - EnumerationType
|
||||
|
||||
|
||||
EnumerationType::~EnumerationType()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
type_kind
|
||||
EnumerationType::Kind() const
|
||||
{
|
||||
return TYPE_ENUMERATION;
|
||||
}
|
||||
|
||||
|
||||
EnumerationValue*
|
||||
EnumerationType::ValueFor(const BVariant& value) const
|
||||
{
|
||||
// TODO: Optimize?
|
||||
for (int32 i = 0; EnumerationValue* enumValue = ValueAt(i); i++) {
|
||||
if (enumValue->Value() == value)
|
||||
return enumValue;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - SubrangeType
|
||||
|
||||
|
||||
SubrangeType::~SubrangeType()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
type_kind
|
||||
SubrangeType::Kind() const
|
||||
{
|
||||
return TYPE_SUBRANGE;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - ArrayType
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <Variant.h>
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
@@ -17,6 +18,8 @@ enum type_kind {
|
||||
TYPE_MODIFIED,
|
||||
TYPE_TYPEDEF,
|
||||
TYPE_ADDRESS,
|
||||
TYPE_ENUMERATION,
|
||||
TYPE_SUBRANGE,
|
||||
TYPE_ARRAY
|
||||
};
|
||||
|
||||
@@ -56,6 +59,26 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class EnumerationValue : public Referenceable {
|
||||
public:
|
||||
virtual ~EnumerationValue();
|
||||
|
||||
virtual const char* Name() const = 0;
|
||||
virtual BVariant Value() const = 0;
|
||||
};
|
||||
|
||||
|
||||
class ArrayDimension : public Referenceable {
|
||||
public:
|
||||
virtual ~ArrayDimension();
|
||||
|
||||
virtual Type* GetType() const = 0;
|
||||
// subrange or enumeration
|
||||
virtual uint64 CountElements() const;
|
||||
// returns 0, if unknown
|
||||
};
|
||||
|
||||
|
||||
class Type : public Referenceable {
|
||||
public:
|
||||
virtual ~Type();
|
||||
@@ -63,6 +86,8 @@ public:
|
||||
virtual const char* Name() const = 0;
|
||||
virtual type_kind Kind() const = 0;
|
||||
virtual target_size_t ByteSize() const = 0;
|
||||
virtual Type* ResolveRawType() const;
|
||||
// strips modifiers and typedefs
|
||||
};
|
||||
|
||||
|
||||
@@ -98,6 +123,7 @@ public:
|
||||
|
||||
virtual uint32 Modifiers() const = 0;
|
||||
virtual Type* BaseType() const = 0;
|
||||
virtual Type* ResolveRawType() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -108,6 +134,7 @@ public:
|
||||
virtual type_kind Kind() const;
|
||||
|
||||
virtual Type* BaseType() const = 0;
|
||||
virtual Type* ResolveRawType() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -122,6 +149,34 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class EnumerationType : public virtual Type {
|
||||
public:
|
||||
virtual ~EnumerationType();
|
||||
|
||||
virtual type_kind Kind() const;
|
||||
|
||||
virtual Type* BaseType() const = 0;
|
||||
// may return NULL
|
||||
|
||||
virtual int32 CountValues() const = 0;
|
||||
virtual EnumerationValue* ValueAt(int32 index) const = 0;
|
||||
virtual EnumerationValue* ValueFor(const BVariant& value) const;
|
||||
};
|
||||
|
||||
|
||||
class SubrangeType : public virtual Type {
|
||||
public:
|
||||
virtual ~SubrangeType();
|
||||
|
||||
virtual type_kind Kind() const;
|
||||
|
||||
virtual Type* BaseType() const = 0;
|
||||
|
||||
virtual BVariant LowerBound() const = 0;
|
||||
virtual BVariant UpperBound() const = 0;
|
||||
};
|
||||
|
||||
|
||||
class ArrayType : public virtual Type {
|
||||
public:
|
||||
virtual ~ArrayType();
|
||||
@@ -129,9 +184,9 @@ public:
|
||||
virtual type_kind Kind() const;
|
||||
|
||||
virtual Type* BaseType() const = 0;
|
||||
virtual target_size_t CountElements() const = 0;
|
||||
// TODO: That doesn't work. We need a list of dimensions which in turn
|
||||
// are enumeration or subrange types.
|
||||
|
||||
virtual int32 CountDimensions() const = 0;
|
||||
virtual ArrayDimension* DimensionAt(int32 index) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -43,6 +43,12 @@ TypeComponent::Dump() const
|
||||
case TYPE_ADDRESS:
|
||||
printf("address");
|
||||
break;
|
||||
case TYPE_ENUMERATION:
|
||||
printf("enum");
|
||||
break;
|
||||
case TYPE_SUBRANGE:
|
||||
printf("subrange");
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
printf("array");
|
||||
break;
|
||||
|
||||
@@ -7,12 +7,59 @@
|
||||
#include "ValueLocation.h"
|
||||
|
||||
|
||||
// #pragma mark - ValuePieceLocation
|
||||
|
||||
|
||||
ValuePieceLocation&
|
||||
ValuePieceLocation::Normalize(bool bigEndian)
|
||||
{
|
||||
uint64 excessMSBs = bitOffset / 8;
|
||||
uint64 excessLSBs = size - (bitOffset + bitSize + 7) / 8;
|
||||
|
||||
if (excessMSBs > 0 || excessLSBs > 0) {
|
||||
switch (type) {
|
||||
case VALUE_PIECE_LOCATION_MEMORY:
|
||||
if (bigEndian)
|
||||
address += excessMSBs;
|
||||
else
|
||||
address += excessLSBs;
|
||||
bitOffset -= excessMSBs * 8;
|
||||
size -= excessMSBs + excessLSBs;
|
||||
break;
|
||||
case VALUE_PIECE_LOCATION_UNKNOWN:
|
||||
bitOffset -= excessMSBs * 8;
|
||||
size -= excessMSBs + excessLSBs;
|
||||
break;
|
||||
case VALUE_PIECE_LOCATION_REGISTER:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - ValueLocation
|
||||
|
||||
|
||||
ValueLocation::ValueLocation()
|
||||
:
|
||||
fBigEndian(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ValueLocation::ValueLocation(const ValuePieceLocation& piece)
|
||||
ValueLocation::ValueLocation(bool bigEndian)
|
||||
:
|
||||
fBigEndian(bigEndian)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ValueLocation::ValueLocation(bool bigEndian, const ValuePieceLocation& piece)
|
||||
:
|
||||
fBigEndian(bigEndian)
|
||||
{
|
||||
AddPiece(piece);
|
||||
}
|
||||
@@ -20,7 +67,8 @@ ValueLocation::ValueLocation(const ValuePieceLocation& piece)
|
||||
|
||||
ValueLocation::ValueLocation(const ValueLocation& other)
|
||||
:
|
||||
fPieces(other.fPieces)
|
||||
fPieces(other.fPieces),
|
||||
fBigEndian(other.fBigEndian)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -31,60 +79,105 @@ ValueLocation::SetTo(const ValueLocation& other, uint64 bitOffset,
|
||||
{
|
||||
Clear();
|
||||
|
||||
// skip pieces before the offset
|
||||
fBigEndian = other.fBigEndian;
|
||||
|
||||
// compute the total bit size
|
||||
int32 count = other.CountPieces();
|
||||
int32 i;
|
||||
ValuePieceLocation piece;
|
||||
for (i = 0; i < count; i++) {
|
||||
piece = other.PieceAt(i);
|
||||
if (piece.size * 8 + piece.bitSize > bitOffset)
|
||||
break;
|
||||
bitOffset -= piece.size * 8 + piece.bitSize;
|
||||
uint64 totalBitSize = 0;
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
ValuePieceLocation piece = other.PieceAt(i);
|
||||
totalBitSize += piece.bitSize;
|
||||
}
|
||||
|
||||
if (i >= count)
|
||||
return true;
|
||||
// adjust requested bit offset/size to something reasonable, if necessary
|
||||
if (bitOffset + bitSize > totalBitSize) {
|
||||
if (bitOffset >= totalBitSize)
|
||||
return true;
|
||||
bitSize = totalBitSize - bitOffset;
|
||||
}
|
||||
|
||||
// handle partial piece
|
||||
if (bitOffset > 0) {
|
||||
uint64 remainingBits = piece.size * 8 + piece.bitSize - bitOffset;
|
||||
piece.size = remainingBits / 8;
|
||||
piece.bitSize = remainingBits % 8;
|
||||
if (fBigEndian) {
|
||||
// Big endian: Skip the superfluous most significant bits, copy the
|
||||
// pieces we need (cutting the first and the last one as needed) and
|
||||
// ignore the remaining pieces.
|
||||
|
||||
switch (piece.type) {
|
||||
case VALUE_PIECE_LOCATION_MEMORY:
|
||||
piece.address += (bitOffset + piece.bitOffset) / 8;
|
||||
piece.bitOffset = (bitOffset + piece.bitOffset) % 8;
|
||||
break;
|
||||
case VALUE_PIECE_LOCATION_UNKNOWN:
|
||||
piece.bitOffset = 0;
|
||||
break;
|
||||
case VALUE_PIECE_LOCATION_REGISTER:
|
||||
piece.bitOffset += bitOffset;
|
||||
break;
|
||||
default:
|
||||
// skip pieces for the most significant bits we don't need anymore
|
||||
uint64 bitsToSkip = bitOffset;
|
||||
int32 i;
|
||||
ValuePieceLocation piece;
|
||||
for (i = 0; i < count; i++) {
|
||||
piece = other.PieceAt(i);
|
||||
if (piece.bitSize > bitsToSkip)
|
||||
break;
|
||||
bitsToSkip -= piece.bitSize;
|
||||
}
|
||||
}
|
||||
|
||||
// handle remaining pieces
|
||||
while (bitSize > 0) {
|
||||
target_addr_t pieceSize = piece.size * 8 + piece.bitSize;
|
||||
if (pieceSize > bitSize) {
|
||||
// the piece is bigger than the remaining size -- cut it
|
||||
piece.size = bitSize / 8;
|
||||
piece.bitSize = bitSize % 8;
|
||||
bitSize = 0;
|
||||
} else
|
||||
bitSize -= pieceSize;
|
||||
// handle partial piece
|
||||
if (bitsToSkip > 0) {
|
||||
piece.bitOffset += bitsToSkip;
|
||||
piece.bitSize -= bitsToSkip;
|
||||
piece.Normalize(fBigEndian);
|
||||
}
|
||||
|
||||
if (!AddPiece(piece))
|
||||
return false;
|
||||
// handle remaining pieces
|
||||
while (bitSize > 0) {
|
||||
if (piece.bitSize > bitSize) {
|
||||
// the piece is bigger than the remaining size -- cut it
|
||||
piece.bitSize = bitSize;
|
||||
piece.Normalize(fBigEndian);
|
||||
bitSize = 0;
|
||||
} else
|
||||
bitSize -= piece.bitSize;
|
||||
|
||||
if (++i >= count)
|
||||
break;
|
||||
if (!AddPiece(piece))
|
||||
return false;
|
||||
|
||||
piece = other.PieceAt(i);
|
||||
if (++i >= count)
|
||||
break;
|
||||
|
||||
piece = other.PieceAt(i);
|
||||
}
|
||||
} else {
|
||||
// Little endian: Skip the superfluous least significant bits, copy the
|
||||
// pieces we need (cutting the first and the last one as needed) and
|
||||
// ignore the remaining pieces.
|
||||
|
||||
// skip pieces for the least significant bits we don't need anymore
|
||||
uint64 bitsToSkip = totalBitSize - bitOffset - bitSize;
|
||||
int32 i;
|
||||
ValuePieceLocation piece;
|
||||
for (i = 0; i < count; i++) {
|
||||
piece = other.PieceAt(i);
|
||||
if (piece.bitSize > bitsToSkip)
|
||||
break;
|
||||
bitsToSkip -= piece.bitSize;
|
||||
}
|
||||
|
||||
// handle partial piece
|
||||
if (bitsToSkip > 0) {
|
||||
piece.bitSize -= bitsToSkip;
|
||||
piece.Normalize(fBigEndian);
|
||||
}
|
||||
|
||||
// handle remaining pieces
|
||||
while (bitSize > 0) {
|
||||
if (piece.bitSize > bitSize) {
|
||||
// the piece is bigger than the remaining size -- cut it
|
||||
piece.bitOffset += piece.bitSize - bitSize;
|
||||
piece.bitSize = bitSize;
|
||||
piece.Normalize(fBigEndian);
|
||||
bitSize = 0;
|
||||
} else
|
||||
bitSize -= piece.bitSize;
|
||||
|
||||
if (!AddPiece(piece))
|
||||
return false;
|
||||
|
||||
if (++i >= count)
|
||||
break;
|
||||
|
||||
piece = other.PieceAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -101,6 +194,8 @@ ValueLocation::Clear()
|
||||
bool
|
||||
ValueLocation::AddPiece(const ValuePieceLocation& piece)
|
||||
{
|
||||
// Just add, don't normalize. This allows for using the class with different
|
||||
// semantics (e.g. in the DWARF code).
|
||||
return fPieces.Add(piece);
|
||||
}
|
||||
|
||||
@@ -136,6 +231,7 @@ ValueLocation&
|
||||
ValueLocation::operator=(const ValueLocation& other)
|
||||
{
|
||||
fPieces = other.fPieces;
|
||||
fBigEndian = other.fBigEndian;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -144,7 +240,8 @@ void
|
||||
ValueLocation::Dump() const
|
||||
{
|
||||
int32 count = fPieces.Size();
|
||||
printf("ValueLocation: %ld pieces:\n", count);
|
||||
printf("ValueLocation: %s endian, %ld pieces:\n",
|
||||
fBigEndian ? "big" : "little", count);
|
||||
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
const ValuePieceLocation& piece = fPieces[i];
|
||||
@@ -163,7 +260,7 @@ ValueLocation::Dump() const
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" size: %llu+%u, offset: %u\n", piece.size, piece.bitSize,
|
||||
piece.bitOffset);
|
||||
printf(" size: %llu (%llu bits), offset: %llu bits\n", piece.size,
|
||||
piece.bitSize, piece.bitOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,11 @@ struct ValuePieceLocation {
|
||||
target_addr_t address; // memory address
|
||||
uint32 reg; // register number
|
||||
};
|
||||
target_size_t size; // size in bytes (complete ones)
|
||||
uint8 bitSize; // totalBitSize = size * 8 + bitSize
|
||||
uint8 bitOffset; // offset in bits
|
||||
target_size_t size; // size in bytes (including
|
||||
// incomplete ones)
|
||||
uint64 bitSize; // total size in bits
|
||||
uint64 bitOffset; // bit offset (to the most
|
||||
// significant bit)
|
||||
value_piece_location_type type;
|
||||
|
||||
ValuePieceLocation()
|
||||
@@ -61,29 +63,36 @@ struct ValuePieceLocation {
|
||||
void SetSize(target_size_t size)
|
||||
{
|
||||
this->size = size;
|
||||
this->bitSize = 0;
|
||||
this->bitSize = size * 8;
|
||||
this->bitOffset = 0;
|
||||
}
|
||||
|
||||
void SetSize(uint64 bitSize, uint8 bitOffset)
|
||||
void SetSize(uint64 bitSize, uint64 bitOffset)
|
||||
{
|
||||
this->size = bitSize / 8;
|
||||
this->bitSize = bitSize % 8;
|
||||
this->size = (bitOffset + bitSize + 7) / 8;
|
||||
this->bitSize = bitSize;
|
||||
this->bitOffset = bitOffset;
|
||||
}
|
||||
|
||||
ValuePieceLocation& Normalize(bool bigEndian);
|
||||
};
|
||||
|
||||
|
||||
class ValueLocation : public Referenceable {
|
||||
public:
|
||||
ValueLocation();
|
||||
ValueLocation(const ValuePieceLocation& piece);
|
||||
ValueLocation(bool bigEndian);
|
||||
ValueLocation(bool bigEndian,
|
||||
const ValuePieceLocation& piece);
|
||||
ValueLocation(const ValueLocation& other);
|
||||
|
||||
bool SetTo(const ValueLocation& other,
|
||||
uint64 bitOffset, uint64 bitSize);
|
||||
|
||||
void Clear();
|
||||
|
||||
bool IsBigEndian() const { return fBigEndian; }
|
||||
|
||||
bool AddPiece(const ValuePieceLocation& piece);
|
||||
|
||||
int32 CountPieces() const;
|
||||
@@ -100,6 +109,7 @@ private:
|
||||
|
||||
private:
|
||||
PieceArray fPieces;
|
||||
bool fBigEndian;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user