summaryrefslogtreecommitdiff
path: root/lang/c/pseudoobjc.cpp
diff options
context:
space:
mode:
authorMark Rowe <mrowe@bdash.net.nz>2025-05-30 09:22:50 -0700
committerkat <kat@vector35.com>2025-06-18 10:44:49 -0400
commit90d5791ef7b211ca8f792eb64f9452f6df92d1e0 (patch)
tree0c739461f6ad946fa917de2f94029ad03c6e1d85 /lang/c/pseudoobjc.cpp
parentb6b98c07eb8ce704da4edf5a0b16959215a2c450 (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.cpp86
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") {}