Stop pdg decompiling past noreturn calls to relocated imports

This commit is contained in:
phix33 authored and pancake committed 2026-09-16 14:20:18 +08:00
1 parent ce32d30a8f
commit 9e36cfd88e
3 files changed
+71 -18

No files matched your search

+34 -18
View File
@@ -535,6 +535,32 @@ static void processFunctionSignature(
}
#endif
static bool protoTakesArgs(RCore *core, const char *name) {
Sdb *tdb = core->anal->sdb_types;
char *fname = r_type_func_guess (tdb, r_str_skip_prefix (name, "reloc."));
if (!fname) {
return false;
}
// args_count is 0 for both unknown and zero-arg protos, so > 0 alone tells real arg-takers apart
bool has_args = r_type_func_args_count (tdb, fname) > 0;
free (fname);
return has_args;
}
// Ghidra does active param recovery unless input is locked, so a no-arg noreturn (eg __stack_chk_fail) would otherwise get a live caller reg as a phantom arg
static void markNoReturn(FunctionSymbol *funcsym, bool takesArgs) {
Funcdata *fd = funcsym? funcsym->getFunction (): nullptr;
if (!fd) {
return;
}
FuncProto &fp = fd->getFuncProto ();
fp.setNoReturn (true);
if (!takesArgs) {
fp.clearInput ();
fp.setInputLock (true);
}
}
static bool noreturnTakesArgs(RCore *core, RAnalFunction *fcn, const char *fcn_name) {
RAnalVar **it;
R_VEC_FOREACH (&fcn->vars, it) {
@@ -544,15 +570,7 @@ static bool noreturnTakesArgs(RCore *core, RAnalFunction *fcn, const char *fcn_n
return true;
}
}
Sdb *tdb = core->anal->sdb_types;
char *fname = r_type_func_guess (tdb, fcn_name);
if (!fname) {
return false;
}
// args_count is 0 for both unknown and zero-arg protos, so > 0 alone tells real arg-takers apart
bool has_args = r_type_func_args_count (tdb, fname) > 0;
free (fname);
return has_args;
return protoTakesArgs (core, fcn_name);
}
FunctionSymbol *R2Scope::registerFunction(RAnalFunction *fcn) const {
@@ -711,14 +729,8 @@ FunctionSymbol *R2Scope::registerFunction(RAnalFunction *fcn) const {
fd->getFuncProto().setPieces(sig_proto);
}
}
// Ghidra does active param recovery unless input is locked, so a no-arg noreturn (eg __stack_chk_fail) would otherwise get a live caller reg as a phantom arg
if (funcsym && fcn->is_noreturn && !noreturnTakesArgs (core, fcn, fcn_name)) {
if (Funcdata *fd = funcsym->getFunction ()) {
FuncProto &fp = fd->getFuncProto ();
fp.setNoReturn (true);
fp.clearInput ();
fp.setInputLock (true);
}
if (fcn->is_noreturn && !noreturnTakesArgs (core, fcn, fcn_name)) {
markNoReturn (funcsym, false);
}
return funcsym;
}
@@ -727,7 +739,11 @@ FunctionSymbol *R2Scope::registerFunctionFlag(RFlagItem *flag) const {
RCoreLock core (arch->getCore ());
const char *name = (core->flags->realnames && flag->realname)
? flag->realname : flag->name;
return cache->addFunction (Address (arch->getDefaultCodeSpace (), flag->addr), name);
FunctionSymbol *funcsym = cache->addFunction (Address (arch->getDefaultCodeSpace (), flag->addr), name);
if (r_anal_noreturn_at (core->anal, flag->addr)) {
markNoReturn (funcsym, protoTakesArgs (core, name));
}
return funcsym;
}
Symbol *R2Scope::registerFlag(RFlagItem *flag) const {
Binary file not shown.
+37
View File
@@ -1591,6 +1591,43 @@ EXPECT=<<EOF2
EOF2
RUN
NAME=aarch64 ET_REL decompile stops at a noreturn reloc call
FILE=bins/elf/arm64-noreturn-etrel.o
ARGS=-e bin.relocs.apply=true
CMDS=<<EOF2
aaa
pdg @ sym.sum~Subroutine does not return,strncpy,exit([0]
EOF2
EXPECT=<<EOF2
puVar2
//WARNING:
EOF2
RUN
NAME=aarch64 ET_REL noreturn reloc callee gets no phantom canary args
FILE=bins/elf/arm64-noreturn-etrel.o
ARGS=-e bin.relocs.apply=true
CMDS=<<EOF2
aaa
pdg @ sym.sum~stack_chk_fail()?
EOF2
EXPECT=<<EOF2
1
EOF2
RUN
NAME=aarch64 ET_REL noreturn reloc callee that takes an argument keeps it
FILE=bins/elf/arm64-noreturn-etrel.o
ARGS=-e bin.relocs.apply=true
CMDS=<<EOF2
aaa
pdg @ sym.quit~?exit(0x2a
EOF2
EXPECT=<<EOF2
1
EOF2
RUN
NAME=pdg survives an unparseable var type string instead of recursing
FILE=bins/dectest64
CMDS=<<EOF