@@ -187,6 +187,46 @@ std::optional<RuntimeCall> DetectRewrittenDirectObjCMethodCall(const HighLevelIL
187187 return RuntimeCall {RuntimeCall::MessageSend, constant, true };
188188}
189189
190+ bool VariableIsObjCSuperStruct (const Variable& variable, Function& function)
191+ {
192+ auto variableName = function.GetVariableName (variable);
193+ if (variableName != " super" )
194+ return false ;
195+
196+ const auto variableType = function.GetVariableType (variable);
197+ if (!variableType || !variableType->IsNamedTypeRefer ())
198+ return false ;
199+
200+ const auto namedType = function.GetView ()->GetTypeByRef (variableType->GetNamedTypeReference ());
201+ if (!namedType || namedType->GetClass () != StructureTypeClass)
202+ return false ;
203+
204+ if (namedType->GetStructureName ().GetString () != " objc_super" )
205+ return false ;
206+
207+ return true ;
208+ }
209+
210+ bool IsAssignmentToObjCSuperStructField (const HighLevelILInstruction& assignInstr, Function& function)
211+ {
212+ // Check if this is an assignment to a field of the objc_super struct
213+ // Pattern: HLIL_ASSIGN { dest = HLIL_STRUCT_FIELD { source = HLIL_VAR { super }, }, field = ... }
214+
215+ if (assignInstr.operation != HLIL_ASSIGN)
216+ return false ;
217+
218+ const auto destExpr = assignInstr.GetDestExpr ();
219+ if (destExpr.operation != HLIL_STRUCT_FIELD)
220+ return false ;
221+
222+ const auto sourceExpr = destExpr.GetSourceExpr ();
223+ if (sourceExpr.operation != HLIL_VAR)
224+ return false ;
225+
226+ auto variable = sourceExpr.GetVariable <HLIL_VAR>();
227+ return VariableIsObjCSuperStruct (variable, function);
228+ }
229+
190230} // unnamed namespace
191231
192232PseudoObjCFunction::PseudoObjCFunction (LanguageRepresentationFunctionType* type, Architecture* arch, Function* owner,
@@ -212,7 +252,8 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL
212252 {
213253 case RuntimeCall::MessageSend:
214254 case RuntimeCall::MessageSendSuper:
215- if (GetExpr_ObjCMsgSend (objCRuntimeCall->address , objCRuntimeCall->isRewritten , destExpr, tokens, settings, parameterExprs))
255+ if (GetExpr_ObjCMsgSend (objCRuntimeCall->address , objCRuntimeCall->type == RuntimeCall::MessageSendSuper,
256+ objCRuntimeCall->isRewritten , destExpr, tokens, settings, parameterExprs))
216257 {
217258 if (statement)
218259 tokens.AppendSemicolon ();
@@ -259,7 +300,7 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL
259300 return PseudoCFunction::GetExpr_CALL_OR_TAILCALL (instr, tokens, settings, precedence, statement);
260301}
261302
262- bool PseudoObjCFunction::GetExpr_ObjCMsgSend (uint64_t msgSendAddress, bool isRewritten,
303+ bool PseudoObjCFunction::GetExpr_ObjCMsgSend (uint64_t msgSendAddress, bool isSuper, bool isRewritten,
263304 const HighLevelILInstruction& instr, HighLevelILTokenEmitter& tokens, DisassemblySettings* settings,
264305 const std::vector<HighLevelILInstruction>& parameterExprs)
265306{
@@ -278,7 +319,10 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(uint64_t msgSendAddress, bool isRew
278319
279320 tokens.AppendOpenBracket ();
280321
281- GetExprText (parameterExprs[0 ], tokens, settings);
322+ if (isSuper)
323+ tokens.Append (LocalVariableToken, " super" , instr.address );
324+ else
325+ GetExprText (parameterExprs[0 ], tokens, settings);
282326
283327 for (size_t index = 2 ; index < parameterExprs.size (); index++)
284328 {
@@ -427,7 +471,7 @@ void PseudoObjCFunction::GetExpr_IMPORT(const BinaryNinja::HighLevelILInstructio
427471 BNOperatorPrecedence precedence, bool statement)
428472{
429473 const auto constant = instr.GetConstant <HLIL_IMPORT>();
430- auto symbol = GetHighLevelILFunction ()-> GetFunction ()->GetView ()->GetSymbolByAddress (constant);
474+ auto symbol = GetFunction ()->GetView ()->GetSymbolByAddress (constant);
431475 const auto symbolType = symbol->GetType ();
432476
433477 if (symbol && (symbolType == ImportedDataSymbol || symbolType == ImportAddressSymbol))
@@ -449,6 +493,28 @@ void PseudoObjCFunction::GetExpr_IMPORT(const BinaryNinja::HighLevelILInstructio
449493 PseudoCFunction::GetExpr_IMPORT (instr, tokens, settings, precedence, statement);
450494}
451495
496+ bool PseudoObjCFunction::ShouldSkipStatement (const BinaryNinja::HighLevelILInstruction& instr)
497+ {
498+ // Skip statements that are compiler-generated artifacts of Objective-C runtime calls
499+ // For now this is limited to the declaration / initialization of the `objc_super` variable
500+ // used for `objc_msgSendSuper` calls.
501+ switch (instr.operation )
502+ {
503+ case HLIL_VAR_DECLARE:
504+ if (VariableIsObjCSuperStruct (instr.GetVariable <HLIL_VAR_DECLARE>(), *GetFunction ()))
505+ return true ;
506+ break ;
507+ case HLIL_ASSIGN:
508+ if (IsAssignmentToObjCSuperStructField (instr, *GetFunction ()))
509+ return true ;
510+ break ;
511+ default :
512+ break ;
513+ }
514+
515+ return PseudoCFunction::ShouldSkipStatement (instr);
516+ }
517+
452518
453519PseudoObjCFunctionType::PseudoObjCFunctionType () : PseudoCFunctionType(" Pseudo Objective-C" ) {}
454520
0 commit comments