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

View File

@ -30,14 +30,22 @@ namespace Types
struct TypeBase struct TypeBase
{ {
virtual ~TypeBase() = default;
virtual const char* prefix() const = 0;
std::string owner; //Type owner (header file name). std::string owner; //Type owner (header file name).
std::string name; //Type identifier. std::string name; //Type identifier.
uint32_t typeId = 0; // id from typeIdMap 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 std::string alias; //Typedef and Pointer primitives have this set to the type they point to
Primitive primitive; //Primitive type. Primitive primitive; //Primitive type.
int sizeBits = 0; //Size in bits. int sizeBits = 0; //Size in bits.
@ -55,8 +63,13 @@ namespace Types
bool isBitfield = false; //Is this a bitfield? 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 std::vector<Member> members; //StructUnion members
bool isUnion = false; //Is this a union? bool isUnion = false; //Is this a union?
int sizeBits = -1; //Structure size in bits int sizeBits = -1; //Structure size in bits
@ -70,16 +83,26 @@ namespace Types
Delphi, Delphi,
}; };
struct Function : TypeBase struct Function final : TypeBase
{ {
const char* prefix() const override
{
return "";
}
std::string returnType; //Function return type std::string returnType; //Function return type
CallingConvention callconv = Cdecl; //Function calling convention CallingConvention callconv = Cdecl; //Function calling convention
bool noreturn = false; //Function does not return (ExitProcess, _exit) bool noreturn = false; //Function does not return (ExitProcess, _exit)
std::vector<Member> args; //Function arguments 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; std::vector<std::pair<uint64_t, std::string>> members;
uint8_t sizeBits; //Enum size in bits uint8_t sizeBits; //Enum size in bits
bool isFlags; //Enum members are bit flags 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 AddArg(const std::string & function, const std::string & type, const std::string & name);
bool AppendArg(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* LookupTypeById(uint32_t typeId);
Types::TypeBase* LookupTypeByName(const char* typeName); Types::TypeBase* LookupTypeByName(const std::string & typeName);
int SizeofType(const std::string & type); int SizeofType(const std::string & type);
bool VisitType(const std::string & type, const std::string & name, Types::TypeManager::Visitor & visitor); bool VisitType(const std::string & type, const std::string & name, Types::TypeManager::Visitor & visitor);
void ClearTypes(const std::string & owner = ""); 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; 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) bool NodeVisitor::visitType(const Member & member, const Typedef & type, const std::string & prettyType)
{ {
if(!mParents.empty() && parent().type == Parent::Union) if(!mParents.empty() && parent().type == Parent::Union)
@ -302,31 +313,42 @@ bool NodeVisitor::visitType(const Member & member, const Typedef & type, const s
} }
String tname; String tname;
auto ptype = mParents.empty() ? Parent::Struct : parent().type; auto isArrayMember = !mParents.empty() && parent().type == Parent::Type::Array;
if(ptype == Parent::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.primitive == Pointer && !type.alias.empty())
if(!type.alias.empty())
{ {
auto ptrname = StructUnionPtrType(type.alias); auto ptrPrefix = LookupTypePrefix(type.alias);
if(!ptrname.empty()) if(*ptrPrefix)
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; std::string path;
for(size_t i = 0; i < mPath.size(); i++) for(size_t i = 0; i < mPath.size(); i++)
{ {
if(ptype == Parent::Array && i + 1 == mPath.size()) if(isArrayMember && i + 1 == mPath.size())
break; break;
path.append(mPath[i]); path.append(mPath[i]);
} }
@ -335,7 +357,7 @@ bool NodeVisitor::visitType(const Member & member, const Typedef & type, const s
auto ptr = mAddr + mOffset; auto ptr = mAddr + mOffset;
if(mCreateLabels && MemIsValidReadPtr(ptr)) 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); LabelSet(ptr, path.c_str(), false, true);
} }
@ -378,20 +400,29 @@ bool NodeVisitor::visitStructUnion(const Member & member, const StructUnion & ty
mBitOffset = 0; mBitOffset = 0;
} }
std::string targetType; std::string tname;
if(prettyType.find("__anonymous") == 0) auto isArrayMember = !mParents.empty() && parent().type == Parent::Type::Array;
targetType = ""; if(isArrayMember)
else {
targetType = prettyType; tname += '[';
tname += std::to_string(parent().arrayIndex++);
tname += ']';
tname += ' ';
}
std::string targetName; tname += type.isUnion ? "union" : "struct";
if(member.name.find("__anonymous") == 0)
targetName = "";
else
targetName = member.name;
// TODO: the targetType is empty when displaying array members if(prettyType.find("__anonymous") != 0)
String tname = StringUtils::sprintf("%s %s %s", type.isUnion ? "union" : "struct", targetType.c_str(), targetName.c_str()); {
tname += ' ';
tname += prettyType;
}
if(!isArrayMember && member.name.find("__anonymous") != 0)
{
tname += ' ';
tname += member.name;
}
TYPEDESCRIPTOR td = { }; TYPEDESCRIPTOR td = { };
td.expanded = mParents.size() < mMaxExpandDepth; td.expanded = mParents.size() < mMaxExpandDepth;
@ -423,7 +454,28 @@ bool NodeVisitor::visitEnum(const Member & member, const Enum & num, const std::
mBitOffset = 0; 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 = { }; TYPEDESCRIPTOR td = { };
td.expanded = mParents.size() < mMaxExpandDepth; 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) 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 = { }; TYPEDESCRIPTOR td = { };
auto isPadding = member.name.find("padding") == 0; 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) bool NodeVisitor::visitPtr(const Member & member, const Typedef & type, const std::string & prettyType)
{ {
// TODO: support array of pointers?
auto offset = mOffset; auto offset = mOffset;
auto res = visitType(member, type, prettyType); //print the pointer value auto res = visitType(member, type, prettyType); //print the pointer value
if(mPtrDepth >= mMaxPtrDepth) if(mPtrDepth >= mMaxPtrDepth)

View File

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

View File

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