1
0
Fork 0

Improve pretty printing in NodeVisitor

This commit is contained in:
Duncan Ogilvie 2025-06-26 20:33:16 +02:00
parent 2e3af1c9c9
commit d88a62893a
5 changed files with 133 additions and 40 deletions

View File

@ -631,7 +631,7 @@ bool TypeManager::visitMember(const Member & root, Visitor & visitor, const std:
am.arraySize = -1;
for(auto i = 0; i < child.arraySize; i++)
if(!visitMember(am, visitor, ""))
if(!visitMember(am, visitor, am.type))
return false;
if(!visitor.visitBack(child))
@ -735,7 +735,7 @@ TypeBase* LookupTypeById(uint32_t typeId)
return typeManager.LookupTypeById(typeId);
}
TypeBase* LookupTypeByName(const char* name)
TypeBase* LookupTypeByName(const std::string & name)
{
SHARED_ACQUIRE(LockTypeManager);
return typeManager.LookupTypeByName(name);

View File

@ -30,14 +30,22 @@ namespace Types
struct TypeBase
{
virtual ~TypeBase() = default;
virtual const char* prefix() const = 0;
std::string owner; //Type owner (header file name).
std::string name; //Type identifier.
uint32_t typeId = 0; // id from typeIdMap
};
struct Typedef : TypeBase
struct Typedef final : TypeBase
{
const char* prefix() const override
{
return "";
}
std::string alias; //Typedef and Pointer primitives have this set to the type they point to
Primitive primitive; //Primitive type.
int sizeBits = 0; //Size in bits.
@ -55,8 +63,13 @@ namespace Types
bool isBitfield = false; //Is this a bitfield?
};
struct StructUnion : TypeBase
struct StructUnion final : TypeBase
{
const char* prefix() const override
{
return isUnion ? "union" : "struct";
}
std::vector<Member> members; //StructUnion members
bool isUnion = false; //Is this a union?
int sizeBits = -1; //Structure size in bits
@ -70,16 +83,26 @@ namespace Types
Delphi,
};
struct Function : TypeBase
struct Function final : TypeBase
{
const char* prefix() const override
{
return "";
}
std::string returnType; //Function return type
CallingConvention callconv = Cdecl; //Function calling convention
bool noreturn = false; //Function does not return (ExitProcess, _exit)
std::vector<Member> args; //Function arguments
};
struct Enum : TypeBase
struct Enum final : TypeBase
{
const char* prefix() const override
{
return "enum";
}
std::vector<std::pair<uint64_t, std::string>> members;
uint8_t sizeBits; //Enum size in bits
bool isFlags; //Enum members are bit flags
@ -198,7 +221,7 @@ bool AddFunction(const std::string & owner, const std::string & name, const std:
bool AddArg(const std::string & function, const std::string & type, const std::string & name);
bool AppendArg(const std::string & type, const std::string & name);
Types::TypeBase* LookupTypeById(uint32_t typeId);
Types::TypeBase* LookupTypeByName(const char* typeName);
Types::TypeBase* LookupTypeByName(const std::string & typeName);
int SizeofType(const std::string & type);
bool VisitType(const std::string & type, const std::string & name, Types::TypeManager::Visitor & visitor);
void ClearTypes(const std::string & owner = "");

View File

@ -293,6 +293,17 @@ static bool cbPrintEnum(const TYPEDESCRIPTOR* type, char* dest, size_t* destCoun
return true;
}
static const char* LookupTypePrefix(const std::string & typeName)
{
auto type = LookupTypeByName(typeName);
auto td = dynamic_cast<Typedef*>(type);
if(td != nullptr && td->primitive == Alias)
{
return LookupTypePrefix(td->alias);
}
return type->prefix();
}
bool NodeVisitor::visitType(const Member & member, const Typedef & type, const std::string & prettyType)
{
if(!mParents.empty() && parent().type == Parent::Union)
@ -302,31 +313,42 @@ bool NodeVisitor::visitType(const Member & member, const Typedef & type, const s
}
String tname;
auto ptype = mParents.empty() ? Parent::Struct : parent().type;
if(ptype == Parent::Array)
auto isArrayMember = !mParents.empty() && parent().type == Parent::Type::Array;
if(isArrayMember)
{
tname = StringUtils::sprintf("%s[%u]", member.name.c_str(), parent().index++);
tname += '[';
tname += std::to_string(parent().arrayIndex++);
tname += ']';
tname += ' ';
}
else
{
if(member.isBitfield)
tname = StringUtils::sprintf("%s %s : %d", prettyType.c_str(), member.name.c_str(), member.sizeBits);
else
tname = StringUtils::sprintf("%s %s", prettyType.c_str(), member.name.c_str());
// Prepend struct/union to pointer types
if(!type.alias.empty())
if(type.primitive == Pointer && !type.alias.empty())
{
auto ptrPrefix = LookupTypePrefix(type.alias);
if(*ptrPrefix)
{
auto ptrname = StructUnionPtrType(type.alias);
if(!ptrname.empty())
tname = ptrname + " " + tname;
tname += ptrPrefix;
tname += ' ';
}
}
if(!isArrayMember)
{
tname += prettyType;
tname += ' ';
tname += member.name;
if(member.isBitfield)
{
tname += " : ";
tname += std::to_string(member.sizeBits);
}
}
std::string path;
for(size_t i = 0; i < mPath.size(); i++)
{
if(ptype == Parent::Array && i + 1 == mPath.size())
if(isArrayMember && i + 1 == mPath.size())
break;
path.append(mPath[i]);
}
@ -335,7 +357,7 @@ bool NodeVisitor::visitType(const Member & member, const Typedef & type, const s
auto ptr = mAddr + mOffset;
if(mCreateLabels && MemIsValidReadPtr(ptr))
{
if(!LabelGet(ptr, nullptr) && (!mParents.empty() && (parent().index == 1 || ptype != Parent::Array)))
if(!LabelGet(ptr, nullptr) && (!mParents.empty() && (parent().arrayIndex == 1 || !isArrayMember)))
LabelSet(ptr, path.c_str(), false, true);
}
@ -378,20 +400,29 @@ bool NodeVisitor::visitStructUnion(const Member & member, const StructUnion & ty
mBitOffset = 0;
}
std::string targetType;
if(prettyType.find("__anonymous") == 0)
targetType = "";
else
targetType = prettyType;
std::string tname;
auto isArrayMember = !mParents.empty() && parent().type == Parent::Type::Array;
if(isArrayMember)
{
tname += '[';
tname += std::to_string(parent().arrayIndex++);
tname += ']';
tname += ' ';
}
std::string targetName;
if(member.name.find("__anonymous") == 0)
targetName = "";
else
targetName = member.name;
tname += type.isUnion ? "union" : "struct";
// TODO: the targetType is empty when displaying array members
String tname = StringUtils::sprintf("%s %s %s", type.isUnion ? "union" : "struct", targetType.c_str(), targetName.c_str());
if(prettyType.find("__anonymous") != 0)
{
tname += ' ';
tname += prettyType;
}
if(!isArrayMember && member.name.find("__anonymous") != 0)
{
tname += ' ';
tname += member.name;
}
TYPEDESCRIPTOR td = { };
td.expanded = mParents.size() < mMaxExpandDepth;
@ -423,7 +454,28 @@ bool NodeVisitor::visitEnum(const Member & member, const Enum & num, const std::
mBitOffset = 0;
}
String tname = StringUtils::sprintf("enum %s %s", prettyType.c_str(), member.name.c_str());
std::string tname;
auto isArrayMember = !mParents.empty() && parent().type == Parent::Type::Array;
if(isArrayMember)
{
tname += '[';
tname += std::to_string(parent().arrayIndex++);
tname += ']';
tname += ' ';
}
tname += "enum";
if(prettyType.find("__anonymous") != 0)
{
tname += ' ';
tname += prettyType;
}
if(!isArrayMember && member.name.find("__anonymous") != 0)
{
tname += ' ';
tname += member.name;
}
TYPEDESCRIPTOR td = { };
td.expanded = mParents.size() < mMaxExpandDepth;
@ -446,7 +498,19 @@ bool NodeVisitor::visitEnum(const Member & member, const Enum & num, const std::
bool NodeVisitor::visitArray(const Member & member, const std::string & prettyType)
{
String tname = StringUtils::sprintf("%s %s[%d]", prettyType.c_str(), member.name.c_str(), member.arraySize);
// TODO: support array of arrays?
std::string tname = LookupTypePrefix(member.type);
if(!tname.empty())
{
tname += ' ';
}
tname += prettyType;
tname += ' ';
tname += member.name;
tname += '[';
tname += std::to_string(member.arraySize);
tname += ']';
TYPEDESCRIPTOR td = { };
auto isPadding = member.name.find("padding") == 0;
@ -472,6 +536,8 @@ bool NodeVisitor::visitArray(const Member & member, const std::string & prettyTy
bool NodeVisitor::visitPtr(const Member & member, const Typedef & type, const std::string & prettyType)
{
// TODO: support array of pointers?
auto offset = mOffset;
auto res = visitType(member, type, prettyType); //print the pointer value
if(mPtrDepth >= mMaxPtrDepth)

View File

@ -45,7 +45,7 @@ private:
};
Type type;
unsigned int index = 0;
unsigned int arrayIndex = 0;
duint addr = 0;
duint offset = 0;
void* node = nullptr;

View File

@ -238,6 +238,10 @@ void TypeWidget::updateValuesSlot()
QString TypeWidget::highlightTypeName(QString name) const
{
// Pass through names that already have HTML tags
if(name.contains('<'))
return name;
// TODO: this can be improved with colors
static auto re = []
{
@ -295,8 +299,8 @@ QString TypeWidget::highlightTypeName(QString name) const
name.replace(re, "<b>\\1</b>");
static QRegExp sre("^(struct|union|class|enum) ([a-zA-Z0-9_:$]+)");
name.replace(sre, "<u>\\1</u> <b>\\2</b>");
static QRegExp sre("^(\\[\\d+\\] )?(struct|union|class|enum)( [a-zA-Z0-9_:$]+)?");
name.replace(sre, "\\1<u>\\2</u><b>\\3</b>");
return name;
}