diff options
| author | Mark Rowe <mrowe@bdash.net.nz> | 2025-05-30 09:22:50 -0700 |
|---|---|---|
| committer | kat <kat@vector35.com> | 2025-06-18 10:44:49 -0400 |
| commit | 90d5791ef7b211ca8f792eb64f9452f6df92d1e0 (patch) | |
| tree | 0c739461f6ad946fa917de2f94029ad03c6e1d85 /lang/c/pseudoobjc.cpp | |
| parent | b6b98c07eb8ce704da4edf5a0b16959215a2c450 (diff) | |
[ObjC] Improve how [super ...] calls are displayed
1. Skip displaying the declaration and initialization of the objc_super
struct since that's an artifact of how objc_msgSendSuper is called.
2. Display the message receiver as `super` rather than `&super`
Diffstat (limited to 'lang/c/pseudoobjc.cpp')
| -rw-r--r-- | lang/c/pseudoobjc.cpp | 86 |
1 files changed, 78 insertions, 8 deletions
diff --git a/lang/c/pseudoobjc.cpp b/lang/c/pseudoobjc.cpp index 9b6dd0c7..c832e388 100644 --- a/lang/c/pseudoobjc.cpp +++ b/lang/c/pseudoobjc.cpp @@ -99,6 +99,17 @@ std::optional<std::pair<uint64_t, Ref<Symbol>>> GetCallTargetInfo(const HighLeve return std::make_pair(constant, symbol); } +Ref<Type> TypeResolvingNamedTypeReference(Ref<Type> type, const Function& function) +{ + if (!type || !type->IsNamedTypeRefer()) + return type; + + if (auto resolvedType = function.GetView()->GetTypeByRef(type->GetNamedTypeReference())) + return resolvedType; + + return type; +} + struct RuntimeCall { enum Type @@ -198,6 +209,42 @@ std::optional<RuntimeCall> DetectRewrittenDirectObjCMethodCall(const HighLevelIL return RuntimeCall {RuntimeCall::MessageSend, constant, true}; } +bool VariableIsObjCSuperStruct(const Variable& variable, Function& function) +{ + auto variableName = function.GetVariableName(variable); + if (variableName != "super") + return false; + + const auto variableType = TypeResolvingNamedTypeReference(function.GetVariableType(variable), function); + if (!variableType || variableType->GetClass() != StructureTypeClass) + return false; + + if (variableType->GetStructureName().GetString() != "objc_super") + return false; + + return true; +} + +bool IsAssignmentToObjCSuperStructField(const HighLevelILInstruction& assignInstr, Function& function) +{ + // Check if this is an assignment to a field of the objc_super struct + // Pattern: HLIL_ASSIGN { dest = HLIL_STRUCT_FIELD { source = HLIL_VAR { super }, }, field = ... } + + if (assignInstr.operation != HLIL_ASSIGN) + return false; + + const auto destExpr = assignInstr.GetDestExpr(); + if (destExpr.operation != HLIL_STRUCT_FIELD) + return false; + + const auto sourceExpr = destExpr.GetSourceExpr(); + if (sourceExpr.operation != HLIL_VAR) + return false; + + auto variable = sourceExpr.GetVariable<HLIL_VAR>(); + return VariableIsObjCSuperStruct(variable, function); +} + } // unnamed namespace PseudoObjCFunction::PseudoObjCFunction(LanguageRepresentationFunctionType* type, Architecture* arch, Function* owner, @@ -223,7 +270,8 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL { case RuntimeCall::MessageSend: case RuntimeCall::MessageSendSuper: - if (GetExpr_ObjCMsgSend(objCRuntimeCall->address, objCRuntimeCall->isRewritten, destExpr, tokens, settings, parameterExprs)) + if (GetExpr_ObjCMsgSend(objCRuntimeCall->address, objCRuntimeCall->type == RuntimeCall::MessageSendSuper, + objCRuntimeCall->isRewritten, destExpr, tokens, settings, parameterExprs)) { if (statement) tokens.AppendSemicolon(); @@ -283,7 +331,7 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL return PseudoCFunction::GetExpr_CALL_OR_TAILCALL(instr, tokens, settings, precedence, statement); } -bool PseudoObjCFunction::GetExpr_ObjCMsgSend(uint64_t msgSendAddress, bool isRewritten, +bool PseudoObjCFunction::GetExpr_ObjCMsgSend(uint64_t msgSendAddress, bool isSuper, bool isRewritten, const HighLevelILInstruction& instr, HighLevelILTokenEmitter& tokens, DisassemblySettings* settings, const std::vector<HighLevelILInstruction>& parameterExprs) { @@ -302,7 +350,10 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(uint64_t msgSendAddress, bool isRew tokens.AppendOpenBracket(); - GetExprText(parameterExprs[0], tokens, settings); + if (isSuper) + tokens.Append(LocalVariableToken, "super", instr.address); + else + GetExprText(parameterExprs[0], tokens, settings); for (size_t index = 2; index < parameterExprs.size(); index++) { @@ -402,10 +453,7 @@ void PseudoObjCFunction::GetExpr_CONST_PTR(const BinaryNinja::HighLevelILInstruc if (!hasVariable) return PseudoCFunction::GetExpr_CONST_PTR(instr, tokens, settings, precedence, statement); - auto type = variable.type->IsNamedTypeRefer() ? - GetFunction()->GetView()->GetTypeByRef(variable.type->GetNamedTypeReference()) : - variable.type.GetValue(); - + auto type = TypeResolvingNamedTypeReference(variable.type, *GetFunction()); if (!type || type->GetClass() != StructureTypeClass) return PseudoCFunction::GetExpr_CONST_PTR(instr, tokens, settings, precedence, statement); @@ -489,7 +537,7 @@ void PseudoObjCFunction::GetExpr_IMPORT(const BinaryNinja::HighLevelILInstructio BNOperatorPrecedence precedence, bool statement) { const auto constant = instr.GetConstant<HLIL_IMPORT>(); - auto symbol = GetHighLevelILFunction()->GetFunction()->GetView()->GetSymbolByAddress(constant); + auto symbol = GetFunction()->GetView()->GetSymbolByAddress(constant); const auto symbolType = symbol->GetType(); if (symbol && (symbolType == ImportedDataSymbol || symbolType == ImportAddressSymbol)) @@ -511,6 +559,28 @@ void PseudoObjCFunction::GetExpr_IMPORT(const BinaryNinja::HighLevelILInstructio PseudoCFunction::GetExpr_IMPORT(instr, tokens, settings, precedence, statement); } +bool PseudoObjCFunction::ShouldSkipStatement(const BinaryNinja::HighLevelILInstruction& instr) +{ + // Skip statements that are compiler-generated artifacts of Objective-C runtime calls + // For now this is limited to the declaration / initialization of the `objc_super` variable + // used for `objc_msgSendSuper` calls. + switch (instr.operation) + { + case HLIL_VAR_DECLARE: + if (VariableIsObjCSuperStruct(instr.GetVariable<HLIL_VAR_DECLARE>(), *GetFunction())) + return true; + break; + case HLIL_ASSIGN: + if (IsAssignmentToObjCSuperStructField(instr, *GetFunction())) + return true; + break; + default: + break; + } + + return PseudoCFunction::ShouldSkipStatement(instr); +} + PseudoObjCFunctionType::PseudoObjCFunctionType() : PseudoCFunctionType("Pseudo Objective-C") {} |
