From 18f70cd1e622c75a14f3737411bc39d026abd736 Mon Sep 17 00:00:00 2001 From: Peter LaFosse Date: Tue, 3 Jun 2025 16:01:28 -0400 Subject: [PATCH] [PseudoC] Fix handling of struct field accesses * Accesses at offset zero were not handled. * The pointer arithmetic and casts that were generated were incorrect in some cases. Fixes #6825. --- lang/c/pseudoc.cpp | 142 +++++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 68 deletions(-) diff --git a/lang/c/pseudoc.cpp b/lang/c/pseudoc.cpp index 4d585966c..8507d09af 100644 --- a/lang/c/pseudoc.cpp +++ b/lang/c/pseudoc.cpp @@ -2569,91 +2569,97 @@ void PseudoCFunction::GetExprTextInternal(const HighLevelILInstruction& instr, H if (type && (type->GetClass() == NamedTypeReferenceClass)) type = GetFunction()->GetView()->GetTypeByRef(type->GetNamedTypeReference()); - bool derefOffset = false; + // Try to resolve as a structure member access if (type && (type->GetClass() == StructureTypeClass)) { - std::optional memberIndexHint; - if (memberIndex != BN_INVALID_EXPR) - memberIndexHint = memberIndex; + auto memberIndexHint = memberIndex != BN_INVALID_EXPR ? std::make_optional(memberIndex) : std::nullopt; bool outer = true; - if (type->GetStructure()->ResolveMemberOrBaseMember(GetFunction()->GetView(), offset, 0, - [&](NamedTypeReference*, Structure* s, size_t memberIndex, uint64_t structOffset, - uint64_t adjustedOffset, const StructureMember& member) { - BNSymbolDisplayResult symbolType; - if (srcExpr.operation == HLIL_CONST_PTR) - { - const auto constant = srcExpr.GetConstant(); - symbolType = tokens.AppendPointerTextToken( - srcExpr, constant, settings, DisplaySymbolOnly, precedence); - } - else - { - GetExprTextInternal(srcExpr, tokens, settings, MemberAndFunctionOperatorPrecedence); - symbolType = OtherSymbolResult; - } - - const auto displayDeref = symbolType != DataSymbolResult; - if (displayDeref && outer) - tokens.Append(OperationToken, "->"); - else - tokens.Append(OperationToken, "."); - outer = false; - - vector nameList {member.name}; - HighLevelILTokenEmitter::AddNamesForOuterStructureMembers( - GetFunction()->GetView(), type, srcExpr, nameList); - - tokens.Append(FieldNameToken, member.name, structOffset + member.offset, 0, 0, - BN_FULL_CONFIDENCE, nameList); - }), - memberIndexHint) + auto renderMember = [&](NamedTypeReference*, Structure* s, size_t memberIndex, + uint64_t structOffset, uint64_t adjustedOffset, const StructureMember& member) { + BNSymbolDisplayResult symbolType; + if (srcExpr.operation == HLIL_CONST_PTR) + { + const auto constant = srcExpr.GetConstant(); + symbolType = tokens.AppendPointerTextToken( + srcExpr, constant, settings, DisplaySymbolOnly, precedence); + } + else + { + GetExprTextInternal(srcExpr, tokens, settings, MemberAndFunctionOperatorPrecedence); + symbolType = OtherSymbolResult; + } + + const auto useArrow = (symbolType != DataSymbolResult) && outer; + tokens.Append(OperationToken, useArrow ? "->" : "."); + outer = false; + + vector nameList {member.name}; + HighLevelILTokenEmitter::AddNamesForOuterStructureMembers( + GetFunction()->GetView(), type, srcExpr, nameList); + + tokens.Append(FieldNameToken, member.name, structOffset + member.offset, 0, 0, + BN_FULL_CONFIDENCE, nameList); + }; + + bool memberResolved = type->GetStructure()->ResolveMemberOrBaseMember( + GetFunction()->GetView(), offset, 0, renderMember, memberIndexHint); + + if (memberResolved) return; } - else if (type && (type->GetClass() == StructureTypeClass)) - { - derefOffset = true; - } - if (derefOffset || offset != 0) - { - bool parens = precedence > UnaryOperatorPrecedence; - if (parens) - tokens.AppendOpenParen(); + // Member resolution failed or not a structure - render as pointer arithmetic + // Structure: *(type_cast)(char_cast pointer + offset) - tokens.Append(OperationToken, "*"); - if (!settings || settings->IsOptionSet(ShowTypeCasts)) - { - tokens.AppendOpenParen(); - AppendSizeToken(!derefOffset ? srcExpr.size : instr.size, true, tokens); - tokens.Append(TextToken, "*"); - tokens.AppendCloseParen(); - } + bool needsOuterParens = precedence > UnaryOperatorPrecedence; + bool showsTypeCasts = !settings || settings->IsOptionSet(ShowTypeCasts); + bool needsTypeCast = instr.size > 1 && showsTypeCasts; + bool hasOffset = offset != 0; + + if (needsOuterParens) tokens.AppendOpenParen(); - if (!settings || settings->IsOptionSet(ShowTypeCasts)) + + tokens.Append(OperationToken, "*"); + + if (needsTypeCast) + { + tokens.AppendOpenParen(); + AppendSizeToken(instr.size, true, tokens); + tokens.Append(TextToken, "*"); + tokens.AppendCloseParen(); + } + + if (hasOffset) { + tokens.AppendOpenParen(); + if (showsTypeCasts) { tokens.AppendOpenParen(); - tokens.Append(TypeNameToken, "char"); + tokens.Append(KeywordToken, "char"); tokens.Append(TextToken, "*"); tokens.AppendCloseParen(); } - - if (srcExpr.operation == HLIL_CONST_PTR) - { - const auto constant = srcExpr.GetConstant(); - tokens.AppendPointerTextToken(srcExpr, constant, settings, DisplaySymbolOnly, precedence); - } - else - { - GetExprTextInternal(srcExpr, tokens, settings, AddOperatorPrecedence); - } - + } + + if (srcExpr.operation == HLIL_CONST_PTR) + { + const auto constant = srcExpr.GetConstant(); + tokens.AppendPointerTextToken(srcExpr, constant, settings, DisplaySymbolOnly, precedence); + } + else + { + GetExprTextInternal(srcExpr, tokens, settings, AddOperatorPrecedence); + } + + if (hasOffset) + { tokens.Append(OperationToken, " + "); tokens.AppendIntegerTextToken(instr, offset, instr.size); - tokens.AppendCloseParen(); - if (parens) - tokens.AppendCloseParen(); + tokens.AppendCloseParen(); // Close (ptr + offset) } + + if (needsOuterParens) + tokens.AppendCloseParen(); if (statement) tokens.AppendSemicolon();