mirror of
https://github.com/radareorg/r2ghidra.git
synced 2026-11-07 06:25:57 -10:00
Lock noreturn inputs only for known empty prototypes
This commit is contained in:
1 parent
9e36cfd88e
commit
a59c4ecbc1
6 files changed
+90
-35
No files matched your search
+14
-17
@@ -535,42 +535,39 @@ static void processFunctionSignature(
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool protoTakesArgs(RCore *core, const char *name) {
|
||||
static bool protoHasNoArgs(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;
|
||||
char *key = r_type_func_key (tdb, name);
|
||||
// a missing args key is an unknown prototype, not an empty one
|
||||
const char *args = key? sdb_const_getf (tdb, nullptr, "func.%s.args", key): nullptr;
|
||||
free (key);
|
||||
return args && !strcmp (args, "0");
|
||||
}
|
||||
|
||||
// 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) {
|
||||
static void markNoReturn(FunctionSymbol *funcsym, bool lockNoArgs) {
|
||||
Funcdata *fd = funcsym? funcsym->getFunction (): nullptr;
|
||||
if (!fd) {
|
||||
return;
|
||||
}
|
||||
FuncProto &fp = fd->getFuncProto ();
|
||||
fp.setNoReturn (true);
|
||||
if (!takesArgs) {
|
||||
if (lockNoArgs) {
|
||||
fp.clearInput ();
|
||||
fp.setInputLock (true);
|
||||
}
|
||||
}
|
||||
|
||||
static bool noreturnTakesArgs(RCore *core, RAnalFunction *fcn, const char *fcn_name) {
|
||||
static bool noreturnHasNoArgs(RCore *core, RAnalFunction *fcn, const char *fcn_name) {
|
||||
RAnalVar **it;
|
||||
R_VEC_FOREACH (&fcn->vars, it) {
|
||||
RAnalVar *v = *it;
|
||||
// a ppc PLT stub's TOC save lands a spurious stack arg, so only a register arg counts
|
||||
if (v && v->isarg && v->kind == R_ANAL_VAR_KIND_REG) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return protoTakesArgs (core, fcn_name);
|
||||
return protoHasNoArgs (core, fcn_name);
|
||||
}
|
||||
|
||||
FunctionSymbol *R2Scope::registerFunction(RAnalFunction *fcn) const {
|
||||
@@ -729,8 +726,8 @@ FunctionSymbol *R2Scope::registerFunction(RAnalFunction *fcn) const {
|
||||
fd->getFuncProto().setPieces(sig_proto);
|
||||
}
|
||||
}
|
||||
if (fcn->is_noreturn && !noreturnTakesArgs (core, fcn, fcn_name)) {
|
||||
markNoReturn (funcsym, false);
|
||||
if (fcn->is_noreturn) {
|
||||
markNoReturn (funcsym, noreturnHasNoArgs (core, fcn, fcn_name));
|
||||
}
|
||||
return funcsym;
|
||||
}
|
||||
@@ -741,7 +738,7 @@ FunctionSymbol *R2Scope::registerFunctionFlag(RFlagItem *flag) const {
|
||||
? flag->realname : flag->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));
|
||||
markNoReturn (funcsym, protoHasNoArgs (core, name));
|
||||
}
|
||||
return funcsym;
|
||||
}
|
||||
|
||||
@@ -55,3 +55,21 @@ elf/x86_64-varargs.so: varargs.c
|
||||
x86_64-linux-gnu-gcc -shared -fPIC -O1 -U_FORTIFY_SOURCE \
|
||||
-Wl,-z,lazy,-z,norelro,-z,max-page-size=0x1000,--build-id=none \
|
||||
-o $@ varargs.c
|
||||
|
||||
elf/arm64-noreturn-etrel.o: arm64-noreturn-etrel.c
|
||||
aarch64-linux-gnu-gcc -O2 -c \
|
||||
-fstack-protector-all \
|
||||
-fno-asynchronous-unwind-tables \
|
||||
-fno-unwind-tables \
|
||||
-fno-ident \
|
||||
-fcf-protection=none \
|
||||
-o $@ arm64-noreturn-etrel.c
|
||||
aarch64-linux-gnu-strip --strip-debug $@
|
||||
|
||||
elf/noreturn-prototypes-x86_64.o: noreturn-prototypes.c
|
||||
x86_64-linux-gnu-gcc -O2 -c \
|
||||
-fno-stack-protector \
|
||||
-fno-asynchronous-unwind-tables \
|
||||
-fno-unwind-tables \
|
||||
-fno-ident \
|
||||
-o $@ noreturn-prototypes.c
|
||||
@@ -0,0 +1,17 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int sum(const char *s) {
|
||||
char buf[32];
|
||||
strncpy (buf, s, sizeof (buf) - 1);
|
||||
buf[sizeof (buf) - 1] = 0;
|
||||
int r = 0;
|
||||
for (char *p = buf; *p; p++) {
|
||||
r += *p;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void quit(void) {
|
||||
exit (42);
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,15 @@
|
||||
#include <err.h>
|
||||
|
||||
extern void custom_fatal(int status) __attribute__((noreturn));
|
||||
|
||||
void call_err(void) {
|
||||
err (42, "boom");
|
||||
}
|
||||
|
||||
void call_errx(void) {
|
||||
errx (42, "boom");
|
||||
}
|
||||
|
||||
void call_custom(void) {
|
||||
custom_fatal (42);
|
||||
}
|
||||
@@ -1591,40 +1591,48 @@ EXPECT=<<EOF2
|
||||
EOF2
|
||||
RUN
|
||||
|
||||
NAME=aarch64 ET_REL decompile stops at a noreturn reloc call
|
||||
NAME=aarch64 ET_REL noreturn stops flow and preserves argument counts
|
||||
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()?
|
||||
pdg @ sym.sum~?int sym.sum(
|
||||
pdg @ sym.sum~?stack_chk_fail()
|
||||
pdg @ sym.sum~?reloc.exit,halt_baddata
|
||||
pdg @ sym.quit~?exit(0x2a
|
||||
EOF2
|
||||
EXPECT=<<EOF2
|
||||
1
|
||||
1
|
||||
0
|
||||
1
|
||||
EOF2
|
||||
RUN
|
||||
|
||||
NAME=aarch64 ET_REL noreturn reloc callee that takes an argument keeps it
|
||||
FILE=bins/elf/arm64-noreturn-etrel.o
|
||||
NAME=noreturn flags preserve known and unknown arguments
|
||||
FILE=bins/elf/noreturn-prototypes-x86_64.o
|
||||
ARGS=-e bin.relocs.apply=true
|
||||
CMDS=<<EOF2
|
||||
aaa
|
||||
pdg @ sym.quit~?exit(0x2a
|
||||
pdg @ sym.call_err~?reloc.err(0x2a
|
||||
pdg @ sym.call_errx~?reloc.errx(0x2a
|
||||
tna reloc.custom_fatal
|
||||
pdg @ sym.call_custom~?reloc.custom_fatal(0x2a)
|
||||
pdg @ sym.call_custom~?halt_baddata
|
||||
tk custom_fatal=func
|
||||
pdg @ sym.call_custom~?reloc.custom_fatal(0x2a)
|
||||
tk func.custom_fatal.args=0
|
||||
tk reloc.custom_fatal=func
|
||||
tk func.reloc.custom_fatal.args=1
|
||||
pdg @ sym.call_custom~?reloc.custom_fatal(0x2a)
|
||||
EOF2
|
||||
EXPECT=<<EOF2
|
||||
1
|
||||
1
|
||||
1
|
||||
0
|
||||
1
|
||||
1
|
||||
EOF2
|
||||
RUN
|
||||
|
||||
|
||||
Reference in new issue
Block a user