Skip to content

Commit 90d5791

Browse files
bdash0cyn
authored andcommitted
[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 b6b98c0 commit 90d5791

File tree

4 files changed

+91
-11
lines changed

4 files changed

+91
-11
lines changed

lang/c/pseudoc.cpp

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

617617
// Emit the lines for the statement itself
618-
GetExprTextInternal(*i, tokens, settings, TopLevelOperatorPrecedence, true);
619-
tokens.NewLine();
618+
if (!ShouldSkipStatement(*i))
619+
{
620+
GetExprTextInternal(*i, tokens, settings, TopLevelOperatorPrecedence, true);
621+
tokens.NewLine();
622+
}
620623
}
621624
}();
622625
break;
@@ -2846,6 +2849,10 @@ TypePrinter* PseudoCFunction::GetTypePrinter() const
28462849
return m_typePrinter;
28472850
}
28482851

2852+
bool PseudoCFunction::ShouldSkipStatement(const BinaryNinja::HighLevelILInstruction& instr)
2853+
{
2854+
return false;
2855+
}
28492856

28502857
PseudoCFunctionType::PseudoCFunctionType(): LanguageRepresentationFunctionType("Pseudo C")
28512858
{

lang/c/pseudoc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class PseudoCFunction: public BinaryNinja::LanguageRepresentationFunction
5555

5656
BinaryNinja::TypePrinter* GetTypePrinter() const;
5757

58+
virtual bool ShouldSkipStatement(const BinaryNinja::HighLevelILInstruction& instr);
5859
virtual void GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelILInstruction& instr,
5960
BinaryNinja::HighLevelILTokenEmitter& tokens, BinaryNinja::DisassemblySettings* settings,
6061
BNOperatorPrecedence precedence, bool statement);

lang/c/pseudoobjc.cpp

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,17 @@ std::optional<std::pair<uint64_t, Ref<Symbol>>> GetCallTargetInfo(const HighLeve
9999
return std::make_pair(constant, symbol);
100100
}
101101

102+
Ref<Type> TypeResolvingNamedTypeReference(Ref<Type> type, const Function& function)
103+
{
104+
if (!type || !type->IsNamedTypeRefer())
105+
return type;
106+
107+
if (auto resolvedType = function.GetView()->GetTypeByRef(type->GetNamedTypeReference()))
108+
return resolvedType;
109+
110+
return type;
111+
}
112+
102113
struct RuntimeCall
103114
{
104115
enum Type
@@ -198,6 +209,42 @@ std::optional<RuntimeCall> DetectRewrittenDirectObjCMethodCall(const HighLevelIL
198209
return RuntimeCall {RuntimeCall::MessageSend, constant, true};
199210
}
200211

212+
bool VariableIsObjCSuperStruct(const Variable& variable, Function& function)
213+
{
214+
auto variableName = function.GetVariableName(variable);
215+
if (variableName != "super")
216+
return false;
217+
218+
const auto variableType = TypeResolvingNamedTypeReference(function.GetVariableType(variable), function);
219+
if (!variableType || variableType->GetClass() != StructureTypeClass)
220+
return false;
221+
222+
if (variableType->GetStructureName().GetString() != "objc_super")
223+
return false;
224+
225+
return true;
226+
}
227+
228+
bool IsAssignmentToObjCSuperStructField(const HighLevelILInstruction& assignInstr, Function& function)
229+
{
230+
// Check if this is an assignment to a field of the objc_super struct
231+
// Pattern: HLIL_ASSIGN { dest = HLIL_STRUCT_FIELD { source = HLIL_VAR { super }, }, field = ... }
232+
233+
if (assignInstr.operation != HLIL_ASSIGN)
234+
return false;
235+
236+
const auto destExpr = assignInstr.GetDestExpr();
237+
if (destExpr.operation != HLIL_STRUCT_FIELD)
238+
return false;
239+
240+
const auto sourceExpr = destExpr.GetSourceExpr();
241+
if (sourceExpr.operation != HLIL_VAR)
242+
return false;
243+
244+
auto variable = sourceExpr.GetVariable<HLIL_VAR>();
245+
return VariableIsObjCSuperStruct(variable, function);
246+
}
247+
201248
} // unnamed namespace
202249

203250
PseudoObjCFunction::PseudoObjCFunction(LanguageRepresentationFunctionType* type, Architecture* arch, Function* owner,
@@ -223,7 +270,8 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL
223270
{
224271
case RuntimeCall::MessageSend:
225272
case RuntimeCall::MessageSendSuper:
226-
if (GetExpr_ObjCMsgSend(objCRuntimeCall->address, objCRuntimeCall->isRewritten, destExpr, tokens, settings, parameterExprs))
273+
if (GetExpr_ObjCMsgSend(objCRuntimeCall->address, objCRuntimeCall->type == RuntimeCall::MessageSendSuper,
274+
objCRuntimeCall->isRewritten, destExpr, tokens, settings, parameterExprs))
227275
{
228276
if (statement)
229277
tokens.AppendSemicolon();
@@ -283,7 +331,7 @@ void PseudoObjCFunction::GetExpr_CALL_OR_TAILCALL(const BinaryNinja::HighLevelIL
283331
return PseudoCFunction::GetExpr_CALL_OR_TAILCALL(instr, tokens, settings, precedence, statement);
284332
}
285333

286-
bool PseudoObjCFunction::GetExpr_ObjCMsgSend(uint64_t msgSendAddress, bool isRewritten,
334+
bool PseudoObjCFunction::GetExpr_ObjCMsgSend(uint64_t msgSendAddress, bool isSuper, bool isRewritten,
287335
const HighLevelILInstruction& instr, HighLevelILTokenEmitter& tokens, DisassemblySettings* settings,
288336
const std::vector<HighLevelILInstruction>& parameterExprs)
289337
{
@@ -302,7 +350,10 @@ bool PseudoObjCFunction::GetExpr_ObjCMsgSend(uint64_t msgSendAddress, bool isRew
302350

303351
tokens.AppendOpenBracket();
304352

305-
GetExprText(parameterExprs[0], tokens, settings);
353+
if (isSuper)
354+
tokens.Append(LocalVariableToken, "super", instr.address);
355+
else
356+
GetExprText(parameterExprs[0], tokens, settings);
306357

307358
for (size_t index = 2; index < parameterExprs.size(); index++)
308359
{
@@ -402,10 +453,7 @@ void PseudoObjCFunction::GetExpr_CONST_PTR(const BinaryNinja::HighLevelILInstruc
402453
if (!hasVariable)
403454
return PseudoCFunction::GetExpr_CONST_PTR(instr, tokens, settings, precedence, statement);
404455

405-
auto type = variable.type->IsNamedTypeRefer() ?
406-
GetFunction()->GetView()->GetTypeByRef(variable.type->GetNamedTypeReference()) :
407-
variable.type.GetValue();
408-
456+
auto type = TypeResolvingNamedTypeReference(variable.type, *GetFunction());
409457
if (!type || type->GetClass() != StructureTypeClass)
410458
return PseudoCFunction::GetExpr_CONST_PTR(instr, tokens, settings, precedence, statement);
411459

@@ -489,7 +537,7 @@ void PseudoObjCFunction::GetExpr_IMPORT(const BinaryNinja::HighLevelILInstructio
489537
BNOperatorPrecedence precedence, bool statement)
490538
{
491539
const auto constant = instr.GetConstant<HLIL_IMPORT>();
492-
auto symbol = GetHighLevelILFunction()->GetFunction()->GetView()->GetSymbolByAddress(constant);
540+
auto symbol = GetFunction()->GetView()->GetSymbolByAddress(constant);
493541
const auto symbolType = symbol->GetType();
494542

495543
if (symbol && (symbolType == ImportedDataSymbol || symbolType == ImportAddressSymbol))
@@ -511,6 +559,28 @@ void PseudoObjCFunction::GetExpr_IMPORT(const BinaryNinja::HighLevelILInstructio
511559
PseudoCFunction::GetExpr_IMPORT(instr, tokens, settings, precedence, statement);
512560
}
513561

562+
bool PseudoObjCFunction::ShouldSkipStatement(const BinaryNinja::HighLevelILInstruction& instr)
563+
{
564+
// Skip statements that are compiler-generated artifacts of Objective-C runtime calls
565+
// For now this is limited to the declaration / initialization of the `objc_super` variable
566+
// used for `objc_msgSendSuper` calls.
567+
switch (instr.operation)
568+
{
569+
case HLIL_VAR_DECLARE:
570+
if (VariableIsObjCSuperStruct(instr.GetVariable<HLIL_VAR_DECLARE>(), *GetFunction()))
571+
return true;
572+
break;
573+
case HLIL_ASSIGN:
574+
if (IsAssignmentToObjCSuperStructField(instr, *GetFunction()))
575+
return true;
576+
break;
577+
default:
578+
break;
579+
}
580+
581+
return PseudoCFunction::ShouldSkipStatement(instr);
582+
}
583+
514584

515585
PseudoObjCFunctionType::PseudoObjCFunctionType() : PseudoCFunctionType("Pseudo Objective-C") {}
516586

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)