diff --git a/libr/anal/cc.c b/libr/anal/cc.c index 7290d6ba40..2fd8db8859 100644 --- a/libr/anal/cc.c +++ b/libr/anal/cc.c @@ -97,6 +97,10 @@ R_API void r_anal_cc_get_json(RAnal *anal, PJ *pj, const char *name) { return; } pj_ks (pj, "ret", ret); + const char *ret2 = sdb_const_get (DB, r_strf ("cc.%s.ret2", name), 0); + if (ret2) { + pj_ks (pj, "ret2", ret2); + } char *sig = r_anal_cc_get (anal, name); pj_ks (pj, "signature", sig); free (sig); @@ -121,26 +125,40 @@ R_API void r_anal_cc_get_json(RAnal *anal, PJ *pj, const char *name) { } R_API char *r_anal_cc_get(RAnal *anal, const char *name) { + Sdb *db = anal->sdb_cc; r_return_val_if_fail (anal && name, NULL); int i; // get cc by name and print the expr - if (strcmp (sdb_const_get (DB, name, 0), "cc")) { + if (strcmp (sdb_const_get (db, name, 0), "cc")) { R_LOG_ERROR ("Invalid calling convention name (%s)", name); return NULL; } r_strf_var (ccret, 128, "cc.%s.ret", name); - const char *ret = sdb_const_get (DB, ccret, 0); + const char *ret = sdb_const_get (db, ccret, 0); if (!ret) { R_LOG_ERROR ("Cannot find return type for %s", name); return NULL; } + r_strf_var (ccret2, 128, "cc.%s.ret2", name); + const char *ret2 = sdb_const_get (db, ccret2, 0); + RStrBuf *sb = r_strbuf_new (NULL); const char *self = r_anal_cc_self (anal, name); - r_strbuf_appendf (sb, "%s %s%s%s (", ret, r_str_get (self), self? ".": "", name); + if (ret2) { + r_strbuf_appendf (sb, "%s:%s %s%s%s (", ret, ret2, r_str_get (self), self? ".": "", name); + } else { + r_strbuf_appendf (sb, "%s %s%s%s (", ret, r_str_get (self), self? ".": "", name); + } bool isFirst = true; + bool revarg = false; + { + r_strf_var (k, 128, "cc.%s.revarg", name); + const char *s = sdb_const_get (db, k, 0); + revarg = r_str_is_true (s); + } for (i = 0; i < R_ANAL_CC_MAXARG; i++) { r_strf_var (k, 128, "cc.%s.arg%d", name, i); - const char *arg = sdb_const_get (DB, k, 0); + const char *arg = sdb_const_get (db, k, 0); if (!arg) { break; } @@ -148,7 +166,7 @@ R_API char *r_anal_cc_get(RAnal *anal, const char *name) { isFirst = false; } r_strf_var (rename, 128, "cc.%s.argn", name); - const char *argn = sdb_const_get (DB, rename, 0); + const char *argn = sdb_const_get (db, rename, 0); if (argn) { r_strbuf_appendf (sb, "%s%s", isFirst? "": ", ", argn); } @@ -160,27 +178,38 @@ R_API char *r_anal_cc_get(RAnal *anal, const char *name) { } r_strbuf_append (sb, ";"); + if (revarg) { + r_strbuf_append (sb, " // revarg"); + } return r_strbuf_drain (sb); } -R_API bool r_anal_cc_exist(RAnal *anal, const char *convention) { - r_return_val_if_fail (anal && convention, false); - const char *x = sdb_const_get (DB, convention, 0); - return x && *x && !strcmp (x, "cc"); +R_API bool r_anal_cc_exist(RAnal *anal, const char *cc) { + r_return_val_if_fail (anal && cc, false); + const char *x = sdb_const_get (DB, cc, 0); + return (x != NULL) && !strcmp (x, "cc"); } -R_API const char *r_anal_cc_arg(RAnal *anal, const char *convention, int n) { +R_API const char *r_anal_cc_arg(RAnal *anal, const char *cc, int n, int lastn) { r_return_val_if_fail (anal && n >= 0, NULL); - if (!convention) { + if (!cc) { return NULL; } - + Sdb *db = DB; r_strf_buffer (64); - char *query = r_strf ("cc.%s.arg%d", convention, n); - const char *ret = sdb_const_get (DB, query, 0); + if (lastn >= 0) { + char *revarg = r_strf ("cc.%s.revarg", cc); + if (r_str_is_true (revarg)) { + // check if revarg is set, this is used only for D + R_LOG_INFO ("EXPERIMENTAL: Reversing argument position"); + n = lastn - n; + } + } + char *query = r_strf ("cc.%s.arg%d", cc, n); + const char *ret = sdb_const_get (db, query, 0); if (!ret) { - query = r_strf ("cc.%s.argn", convention); - ret = sdb_const_get (DB, query, 0); + query = r_strf ("cc.%s.argn", cc); + ret = sdb_const_get (db, query, 0); } return ret? r_str_constpool_get (&anal->constpool, ret): NULL; } @@ -207,7 +236,7 @@ R_API const char *r_anal_cc_error(RAnal *anal, const char *convention) { R_CRITICAL_ENTER (anal); r_strf_var (query, 64, "cc.%s.error", convention); const char *error = sdb_const_get (DB, query, 0); - const char * res = error? r_str_constpool_get (&anal->constpool, error): NULL; + const char *res = error? r_str_constpool_get (&anal->constpool, error): NULL; R_CRITICAL_LEAVE (anal); return res; } diff --git a/libr/anal/d/README.md b/libr/anal/d/README.md index 1271ef9057..eae39c580f 100644 --- a/libr/anal/d/README.md +++ b/libr/anal/d/README.md @@ -8,3 +8,45 @@ structures and this is used for the code analysis and type propagation logic. * spec.sdb.txt = format modifiers like %p %d %s its used for type propagation * types.sdb.txt = basic C-like types * $os-$bits.sdb.txt = os-arch-bits structs and enums + +## Types: structs / enums / constants + +## Calling Conventions + +Those are defined in the `cc-${arch}-${bits}.sdb.txt` files. + +### dlang calling convention + +* narg = 1 : edi +* narg = 2 : esi, edi +* narg = 3 : edx, esi, edi +* narg = 4 : ecx, edx, esi, edi +* narg = 5 : r8d, ecx, edx, esi, edi +* narg = 6 : r9d, r8d, ecx, edx, esi, edi +* narg = 7 : push, r9d, r8d, ecx, edx, esi, edi + +```asm +mov R9D,1 +mov R8D,2 +mov ECX,3 +mov EDX,4 +mov ESI,5 +mov EDI,6 + +mov R8D,1 +mov ECX,2 +mov EDX,3 +mov ESI,4 +mov EDI,5 + +push 1 +push 2 +mov R9D,3 +mov R8D,4 +mov ECX,5 +mov EDX,6 +mov ESI,7 +mov EDI,8 +call int example.square(int, int, int, int, int, int, int, int)@PLT32 +add RSP,010h +``` diff --git a/libr/anal/d/cc-arm-64.sdb.txt b/libr/anal/d/cc-arm-64.sdb.txt index be37dfd120..1eb6644aa7 100644 --- a/libr/anal/d/cc-arm-64.sdb.txt +++ b/libr/anal/d/cc-arm-64.sdb.txt @@ -30,3 +30,17 @@ p9=cc cc.p9.arg0=x0 cc.p9.argn=stack cc.p9.ret=x0 + +dlang=cc +cc.dlang.arg0=x0 +cc.dlang.arg1=x1 +cc.dlang.arg2=x2 +cc.dlang.arg3=x3 +cc.dlang.arg4=x4 +cc.dlang.arg5=x5 +cc.dlang.arg6=x6 +cc.dlang.arg7=x7 +cc.dlang.argn=stack +cc.dlang.self=x20 +cc.dlang.error=x21 +cc.dlang.ret=x0 diff --git a/libr/anal/d/cc-x86-32.sdb.txt b/libr/anal/d/cc-x86-32.sdb.txt index 052d90e546..284693cba0 100644 --- a/libr/anal/d/cc-x86-32.sdb.txt +++ b/libr/anal/d/cc-x86-32.sdb.txt @@ -44,3 +44,16 @@ cc.watcom.argn=stack pascal=cc cc.pascal.ret=eax cc.pascal.argn=stack_rev + +# reverse argument calling convention. only for gcc and dmd, ldc2 uses normal cdecl CC +dlang=cc +cc.dlang.ret=eax +cc.dlang.ret2=edx +cc.dlang.revarg=1 +cc.dlang.arg0=edi +cc.dlang.arg1=esi +cc.dlang.arg2=edx +cc.dlang.arg3=ecx +cc.dlang.arg4=r8d +cc.dlang.arg5=r9d +cc.dlang.argn=stack_rev diff --git a/libr/anal/d/cc-x86-64.sdb.txt b/libr/anal/d/cc-x86-64.sdb.txt index 6c0789d6de..e350ba13c4 100644 --- a/libr/anal/d/cc-x86-64.sdb.txt +++ b/libr/anal/d/cc-x86-64.sdb.txt @@ -51,3 +51,14 @@ p9=cc cc.p9.arg0=rbp cc.p9.argn=stack cc.p9.ret=rax + +dlang=cc +cc.dlang.ret=rax +cc.dlang.ret2=rdx +cc.dlang.arg0=rdi +cc.dlang.arg1=rsi +cc.dlang.arg2=rdx +cc.dlang.arg3=rcx +cc.dlang.arg4=r8d +cc.dlang.arg5=r9d +cc.dlang.argn=stack diff --git a/libr/anal/var.c b/libr/anal/var.c index 7510f6357b..eef6795095 100644 --- a/libr/anal/var.c +++ b/libr/anal/var.c @@ -589,9 +589,10 @@ R_API int r_anal_var_get_argnum(RAnalVar *var) { r_unref (ri); int i; char *cc = var->fcn->cc ? strdup (var->fcn->cc): NULL; - int arg_max = cc ? r_anal_cc_max_arg (anal, cc) : 0; + const int arg_max = cc ? r_anal_cc_max_arg (anal, cc) : 0; + int total = 0; for (i = 0; i < arg_max; i++) { - const char *reg_arg = r_anal_cc_arg (anal, cc, i); + const char *reg_arg = r_anal_cc_arg (anal, cc, i, total); if (reg_arg && !strcmp (ri_name, reg_arg)) { free (cc); free (ri_name); @@ -1001,6 +1002,7 @@ static void extract_arg(RAnal *anal, RAnalFunction *fcn, RAnalOp *op, const char R_LOG_WARN ("Analysis didn't fill op->src/dst at 0x%" PFMT64x, op->addr); } + const int maxarg = 32; // TODO: use maxarg ? int rw = (op->direction == R_ANAL_OP_DIR_WRITE) ? R_ANAL_VAR_ACCESS_TYPE_WRITE : R_ANAL_VAR_ACCESS_TYPE_READ; if (*sign == '+') { const bool isarg = type == R_ANAL_VAR_KIND_SPV ? ptr >= fcn->stack : ptr >= fcn->bp_off; @@ -1021,7 +1023,7 @@ static void extract_arg(RAnal *anal, RAnalFunction *fcn, RAnalOp *op, const char } char *varname = NULL, *vartype = NULL; if (isarg) { - const char *place = fcn->cc ? r_anal_cc_arg (anal, fcn->cc, ST32_MAX) : NULL; + const char *place = fcn->cc ? r_anal_cc_arg (anal, fcn->cc, maxarg, -1) : NULL; bool stack_rev = place ? !strcmp (place, "stack_rev") : false; char *fname = r_type_func_guess (anal->sdb_types, fcn->name); if (fname) { @@ -1245,6 +1247,7 @@ R_API void r_anal_extract_rarg(RAnal *anal, RAnalOp *op, RAnalFunction *fcn, int callee_rargs_l = r_anal_var_list (anal, f, R_ANAL_VAR_KIND_REG); } int i; + const int total = callee_rargs; for (i = 0; i < callee_rargs; i++) { if (reg_set[i]) { continue; @@ -1253,7 +1256,7 @@ R_API void r_anal_extract_rarg(RAnal *anal, RAnalOp *op, RAnalFunction *fcn, int char *type = NULL; char *name = NULL; int delta = 0; - const char *regname = r_anal_cc_arg (anal, fcn->cc, i); + const char *regname = r_anal_cc_arg (anal, fcn->cc, i, total); if (regname) { RRegItem *ri = r_reg_get (anal->reg, regname, -1); if (ri) { @@ -1300,8 +1303,9 @@ R_API void r_anal_extract_rarg(RAnal *anal, RAnalOp *op, RAnalFunction *fcn, int return; } + const int total = 0; // TODO: pass argn for (i = 0; i < max_count; i++) { - const char *regname = r_anal_cc_arg (anal, fcn->cc, i); + const char *regname = r_anal_cc_arg (anal, fcn->cc, i, total); if (!regname) { // WIP break; } else { diff --git a/libr/core/anal_tp.c b/libr/core/anal_tp.c index b7af22afd1..397958724a 100644 --- a/libr/core/anal_tp.c +++ b/libr/core/anal_tp.c @@ -415,13 +415,14 @@ static void type_match(RCore *core, char *fcn_name, ut64 addr, ut64 baddr, const return; } int i, j, pos = 0, size = 0, max = r_type_func_args_count (TDB, fcn_name); - const char *place = r_anal_cc_arg (anal, cc, ST32_MAX); + int lastarg = ST32_MAX; + const char *place = r_anal_cc_arg (anal, cc, lastarg, -1); r_cons_break_push (NULL, NULL); if (place && !strcmp (place, "stack_rev")) { stack_rev = true; } - place = r_anal_cc_arg (anal, cc, 0); + place = r_anal_cc_arg (anal, cc, 0, -1); if (place && r_str_startswith (place, "stack")) { in_stack = true; } @@ -468,7 +469,7 @@ static void type_match(RCore *core, char *fcn_name, ut64 addr, ut64 baddr, const // XXX: param arg_num must be fixed to support floating point register // before this change place could be null DD eprintf ("not in stack\n"); - const char *p = r_anal_cc_arg (anal, cc, arg_num); + const char *p = r_anal_cc_arg (anal, cc, arg_num, -1); if (p && r_str_startswith (p, "stack")) { in_stack = true; place = p; diff --git a/libr/core/carg.c b/libr/core/carg.c index 73dadd1441..3509106437 100644 --- a/libr/core/carg.c +++ b/libr/core/carg.c @@ -25,7 +25,7 @@ static void set_fcn_args_info(RAnalFuncArg *arg, RAnal *anal, const char *fcn_na arg->fmt = sdb_const_get (TDB, query, 0); const char *t_query = r_strf ("type.%s.size", arg->c_type); arg->size = sdb_num_get (TDB, t_query, 0) / 8; - arg->cc_source = r_anal_cc_arg (anal, cc, arg_num); + arg->cc_source = r_anal_cc_arg (anal, cc, arg_num, -1); } R_API char *resolve_fcn_name(RAnal *anal, const char *func_name) { @@ -231,7 +231,7 @@ R_API RList *r_core_get_func_args(RCore *core, const char *fcn_name) { return NULL; } char *cc = strdup (r_anal_cc_func (core->anal, key)); - const char *src = r_anal_cc_arg (core->anal, cc, 0); // src of first argument + const char *src = r_anal_cc_arg (core->anal, cc, 0, -1); // src of first argument if (!cc) { // unsupported calling convention free (key); diff --git a/libr/core/pseudo.c b/libr/core/pseudo.c index b240995c82..71196e0b39 100644 --- a/libr/core/pseudo.c +++ b/libr/core/pseudo.c @@ -287,8 +287,8 @@ R_API int r_core_pseudo_code(RCore *core, const char *input) { pj_ka (pj, "annotations"); } const char *cc = fcn->cc ? fcn->cc: "default"; - const char *cc_a0 = r_anal_cc_arg (core->anal, cc, 0); - const char *cc_a1 = r_anal_cc_arg (core->anal, cc, 1); + const char *cc_a0 = r_anal_cc_arg (core->anal, cc, 0, -1); + const char *cc_a1 = r_anal_cc_arg (core->anal, cc, 1, -1); const char *a0 = cc_a0? cc_a0: r_reg_get_name_by_type (core->anal->reg, "A0"); const char *a1 = cc_a1? cc_a1: r_reg_get_name_by_type (core->anal->reg, "A1"); const char *r0 = r_reg_get_name_by_type (core->anal->reg, "R0"); diff --git a/libr/debug/arg.c b/libr/debug/arg.c index 7f49dccef1..da1eeb365e 100644 --- a/libr/debug/arg.c +++ b/libr/debug/arg.c @@ -27,7 +27,7 @@ R_API ut64 r_debug_arg_get(RDebug *dbg, const char *cc, int num) { return (ut64)n32; } } - const char *rn = r_anal_cc_arg (dbg->anal, cc, num); + const char *rn = r_anal_cc_arg (dbg->anal, cc, num, -1); if (rn) { return r_debug_reg_get (dbg, rn); } @@ -43,7 +43,7 @@ R_API bool r_debug_arg_set(RDebug *dbg, const char *cc, int num, ut64 val) { if (!R_STR_ISEMPTY (cc)) { cc = r_anal_syscc_default (dbg->anal); } - const char *rn = r_anal_cc_arg (dbg->anal, cc, num); + const char *rn = r_anal_cc_arg (dbg->anal, cc, num, -1); if (rn) { r_debug_reg_set (dbg, rn, val); return true; diff --git a/libr/include/r_anal.h b/libr/include/r_anal.h index 2082724296..c530df2975 100644 --- a/libr/include/r_anal.h +++ b/libr/include/r_anal.h @@ -255,7 +255,6 @@ struct r_anal_attr_t { }; /* Stores useful function metadata */ -/* TODO: Think about moving more stuff to this structure? */ typedef struct r_anal_function_meta_t { // _min and _max are calculated lazily when queried. // On changes, they will either be updated (if this can be done trivially) or invalidated. @@ -269,7 +268,7 @@ typedef struct r_anal_function_meta_t { typedef struct r_anal_function_t { char *name; - // R2_590: add realname for the mangled one + char *realname; // R2_590: add realname for the mangled one int bits; // ((> bits 0) (set-bits bits)) int type; const char *cc; // calling convention, should come from RAnal.constpool @@ -1203,7 +1202,7 @@ R_API bool r_anal_cc_set(RAnal *anal, const char *expr); R_API char *r_anal_cc_get(RAnal *anal, const char *name); R_API bool r_anal_cc_once(RAnal *anal); R_API void r_anal_cc_get_json(RAnal *anal, PJ *pj, const char *name); -R_API const char *r_anal_cc_arg(RAnal *anal, const char *convention, int n); +R_API const char *r_anal_cc_arg(RAnal *anal, const char *convention, int n, int lastn); R_API const char *r_anal_cc_self(RAnal *anal, const char *convention); R_API void r_anal_cc_set_self(RAnal *anal, const char *convention, const char *self); R_API const char *r_anal_cc_error(RAnal *anal, const char *convention); diff --git a/test/db/cmd/cmd_afcl b/test/db/cmd/cmd_afcl index 488942c0e2..e105353fb7 100644 --- a/test/db/cmd/cmd_afcl +++ b/test/db/cmd/cmd_afcl @@ -9,6 +9,7 @@ EOF EXPECT=<