Skip to content

Commit 9ee047c

Browse files
committed
[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`
1 parent 5ecf8d5 commit 9ee047c

File tree

4 files changed

+83
-7
lines changed

4 files changed

+83
-7
lines changed

lang/c/pseudoc.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,8 +618,11 @@ void PseudoCFunction::GetExprTextInternal(const HighLevelILInstruction& instr, H
618618
needSeparator = hasBlocks;
619619

620620
// Emit the lines for the statement itself
621-
GetExprTextInternal(*i, tokens, settings, TopLevelOperatorPrecedence, true);
622-
tokens.NewLine();
621+
if (!ShouldSkipStatement(*i))
622+
{
623+
GetExprTextInternal(*i, tokens, settings, TopLevelOperatorPrecedence, true);
624+
tokens.NewLine();
625+
}
623626
}
624627
}();
625628
break;
@@ -2848,6 +2851,10 @@ string PseudoCFunction::GetAnnotationEndString() const
28482851
return " */";
28492852
}
28502853

2854+
bool PseudoCFunction::ShouldSkipStatement(const BinaryNinja::HighLevelILInstruction& instr)
2855+
{
2856+
return false;
2857+
}
28512858

28522859
PseudoCFunctionType::PseudoCFunctionType(): LanguageRepresentationFunctionType("Pseudo C")
28532860
{

lang/c/pseudoc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class PseudoCFunction: public BinaryNinja::LanguageRepresentationFunction
5252
void EndLines(
5353
const BinaryNinja::HighLevelILInstruction& instr, BinaryNinja::HighLevelILTokenEmitter& tokens) override;
5454

55+
virtual bool ShouldSkipStatement(const BinaryNinja::HighLevelILInstruction& instr);
5556
virtual void GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelILInstruction& instr,
5657
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
5758
BNOperatorPrecedence precedence, bool statement);

lang/c/pseudoobjc.cpp

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

192232
PseudoObjCFunction::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

453519
PseudoObjCFunctionType::PseudoObjCFunctionType() : PseudoCFunctionType("Pseudo Objective-C") {}
454520

lang/c/pseudoobjc.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ class PseudoObjCFunction : public PseudoCFunction
2121
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
2222
BNOperatorPrecedence precedence, bool statement) override;
2323

24+
bool ShouldSkipStatement(const BinaryNinja::HighLevelILInstruction& instr) override;
25+
2426
private:
25-
bool GetExpr_ObjCMsgSend(uint64_t msgSendAddress, bool isRewritten, const BinaryNinja::HighLevelILInstruction& expr,
27+
bool GetExpr_ObjCMsgSend(uint64_t msgSendAddress, bool isSuper, bool isRewritten, const BinaryNinja::HighLevelILInstruction& expr,
2628
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
2729
const std::vector<BinaryNinja::HighLevelILInstruction>& parameterExprs);
2830
bool GetExpr_GenericObjCRuntimeCall(uint64_t address, const BinaryNinja::HighLevelILInstruction& expr,

0 commit comments

Comments
 (0)