diff --git a/librz/core/cbin.c b/librz/core/cbin.c index 3eed3afc9a..864074572b 100644 --- a/librz/core/cbin.c +++ b/librz/core/cbin.c @@ -4109,6 +4109,95 @@ RZ_API bool rz_core_bin_class_methods_print(RZ_NONNULL RzCore *core, RZ_NONNULL return true; } +RZ_API RzCmdStatus rz_core_bin_class_apply_print(RZ_NONNULL RzCore *core, RZ_NONNULL const char *classname, ut64 addr) { + rz_return_val_if_fail(core && classname, RZ_CMD_STATUS_ERROR); + + RzBinObject *o = rz_bin_cur_object(core->bin); + const RzPVector *classes = rz_bin_object_get_classes(o); + if (!classes) { + return RZ_CMD_STATUS_ERROR; + } + + RzBinClass *klass = NULL; + void **iter; + rz_pvector_foreach (classes, iter) { + RzBinClass *c = *iter; + if (c && c->name && !strcmp(c->name, classname)) { + klass = c; + break; + } + } + + if (!klass) { + RZ_LOG_ERROR("Class \"%s\" not found\n", classname); + return RZ_CMD_STATUS_ERROR; + } + + RzListIter *it; + RzBinSymbol *sym; + ut64 min_vaddr = UT64_MAX; + rz_list_foreach (klass->methods, it, sym) { + if (sym->vaddr && sym->vaddr < min_vaddr) { + min_vaddr = sym->vaddr; + } + } + if (min_vaddr == UT64_MAX) { + min_vaddr = klass->addr; + } + + rz_flag_space_push(core->flags, RZ_FLAGS_FS_CLASSES); + rz_list_foreach (klass->methods, it, sym) { + char *fn = rz_core_bin_method_build_flag_name(klass, sym); + if (fn) { + rz_flag_set(core->flags, fn, addr + (sym->vaddr - min_vaddr), sym->size); + free(fn); + } + } + rz_flag_space_pop(core->flags); + return RZ_CMD_STATUS_OK; +} + +RZ_API bool rz_core_bin_classes_to_struct(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf) { + rz_return_val_if_fail(core && bf && bf->o, false); + const RzPVector *classes = rz_bin_object_get_classes(bf->o); + if (!classes) { + return false; + } + void **iter; + RzBinClass *c; + rz_pvector_foreach (classes, iter) { + c = *iter; + if (!c || !c->name || !c->name[0]) { + continue; + } + RzListIter *it; + RzBinClassField *f; + bool has_fields = false; + RzStrBuf *sb = rz_strbuf_new(NULL); + if (!sb) { + return false; + } + rz_strbuf_appendf(sb, "struct %s {", c->name); + rz_list_foreach (c->fields, it, f) { + if (!f->name) { + continue; + } + char *type = objc_type_toc(f->type); + char *name = objc_name_toc(f->name); + rz_strbuf_appendf(sb, " %s %s;", type, name); + free(type); + free(name); + has_fields = true; + } + if (has_fields) { + rz_strbuf_append(sb, " }"); + rz_types_define(core, rz_strbuf_get(sb)); + } + rz_strbuf_free(sb); + } + return true; +} + RZ_API bool rz_core_bin_classes_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, RZ_NONNULL RzCmdStateOutput *state) { rz_return_val_if_fail(core && bf && bf->o && state, false); diff --git a/librz/core/cmd/cmd_info.c b/librz/core/cmd/cmd_info.c index 1e842631bd..b89cf89993 100644 --- a/librz/core/cmd/cmd_info.c +++ b/librz/core/cmd/cmd_info.c @@ -378,6 +378,19 @@ RZ_IPI RzCmdStatus rz_cmd_info_classes_handler(RzCore *core, int argc, const cha return bool2status(rz_core_bin_classes_print(core, bf, state)); } +RZ_IPI RzCmdStatus rz_cmd_info_class_apply_handler(RzCore *core, int argc, const char **argv) { + ut64 addr = argc > 2 ? rz_num_math(core->num, argv[2]) : core->offset; + return rz_core_bin_class_apply_print(core, argv[1], addr); +} + +RZ_IPI RzCmdStatus rz_cmd_info_classes_to_struct_handler(RzCore *core, int argc, const char **argv) { + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return RZ_CMD_STATUS_ERROR; + } + return bool2status(rz_core_bin_classes_to_struct(core, bf)); +} + RZ_IPI RzCmdStatus rz_cmd_info_class_as_source_handler(RzCore *core, int argc, const char **argv) { GET_CHECK_CUR_BINFILE(core); return bool2status(rz_core_bin_class_as_source_print(core, bf, argv[1])); diff --git a/librz/core/cmd/cmd_print.c b/librz/core/cmd/cmd_print.c index 07e51b814a..b57f8fb916 100644 --- a/librz/core/cmd/cmd_print.c +++ b/librz/core/cmd/cmd_print.c @@ -6298,6 +6298,29 @@ RZ_IPI RzCmdStatus rz_cmd_print_format_delete_all_handler(RzCore *core, int argc return RZ_CMD_STATUS_OK; } +RZ_IPI RzCmdStatus rz_cmd_print_format_apply_handler(RzCore *core, int argc, const char **argv) { + if (argc < 2) { + return RZ_CMD_STATUS_WRONG_ARGS; + } + + const char *typename = argv[1]; + ut64 addr = argc > 2 ? rz_num_math(core->num, argv[2]) : core->offset; + + const char *fmt = rz_type_db_format_get(core->analysis->typedb, typename); + if (RZ_STR_ISEMPTY(fmt)) { + RZ_LOG_ERROR("Format with \"%s\" name not found\n", typename); + return RZ_CMD_STATUS_ERROR; + } + + ut64 old_offset = core->offset; + rz_core_seek(core, addr, true); + + RzCmdStatus status = print_format(core, fmt, RZ_PRINT_MUSTSEE, NULL); + + rz_core_seek(core, old_offset, true); + return status; +} + RZ_IPI RzCmdStatus rz_cmd_print_format_named_dot_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) { int mode = RZ_PRINT_MUSTSEE; return print_format(core, argv[1], mode, state); diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index c214d411df..6229aec7aa 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -613,6 +613,7 @@ static const RzCmdDescArg egg_type_args[2]; static const RzCmdDescArg egg_padding_args[2]; static const RzCmdDescArg egg_encoder_args[3]; static const RzCmdDescArg history_list_or_exec_args[2]; +static const RzCmdDescArg cmd_info_class_apply_args[2]; static const RzCmdDescArg cmd_info_class_as_source_args[2]; static const RzCmdDescArg cmd_info_class_fields_args[2]; static const RzCmdDescArg cmd_info_class_methods_args[2]; @@ -718,6 +719,7 @@ static const RzCmdDescArg cmd_disassemble_ropchain_args[2]; static const RzCmdDescArg cmd_disassemble_summarize_n_bytes_args[2]; static const RzCmdDescArg cmd_print_format_args[2]; static const RzCmdDescArg cmd_print_format_delete_args[2]; +static const RzCmdDescArg cmd_print_format_apply_args[2]; static const RzCmdDescArg cmd_print_format_c_args[2]; static const RzCmdDescArg cmd_print_format_dot_args[2]; static const RzCmdDescArg cmd_print_format_named_dot_args[2]; @@ -13197,6 +13199,20 @@ static const RzCmdDescHelp cmd_info_classes_help = { .args = cmd_info_classes_args, }; +static const RzCmdDescArg cmd_info_class_apply_args[] = { + { + .name = "class name", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_info_class_apply_help = { + .summary = "Apply class flags at given address", + .args = cmd_info_class_apply_args, +}; + static const RzCmdDescArg cmd_info_class_as_source_args[] = { { .name = "class name", @@ -13242,6 +13258,14 @@ static const RzCmdDescHelp cmd_info_class_methods_help = { .args = cmd_info_class_methods_args, }; +static const RzCmdDescArg cmd_info_classes_to_struct_args[] = { + { 0 }, +}; +static const RzCmdDescHelp cmd_info_classes_to_struct_help = { + .summary = "Generate type definitions from classes", + .args = cmd_info_classes_to_struct_args, +}; + static const RzCmdDescArg cmd_info_signature_args[] = { { 0 }, }; @@ -15681,6 +15705,20 @@ static const RzCmdDescHelp cmd_print_format_delete_all_help = { .args = cmd_print_format_delete_all_args, }; +static const RzCmdDescArg cmd_print_format_apply_args[] = { + { + .name = "format", + .type = RZ_CMD_ARG_TYPE_STRING, + .flags = RZ_CMD_ARG_FLAG_LAST, + + }, + { 0 }, +}; +static const RzCmdDescHelp cmd_print_format_apply_help = { + .summary = "Apply format string at given address and define flags for each field", + .args = cmd_print_format_apply_args, +}; + static const RzCmdDescArg cmd_print_format_c_args[] = { { .name = "format", @@ -23895,6 +23933,9 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *ic_cd = rz_cmd_desc_group_state_new(core->rcmd, i_cd, "ic", RZ_OUTPUT_MODE_TABLE | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_QUIETEST, rz_cmd_info_classes_handler, &cmd_info_classes_help, &ic_help); rz_warn_if_fail(ic_cd); rz_cmd_desc_set_default_mode(ic_cd, RZ_OUTPUT_MODE_TABLE); + RzCmdDesc *cmd_info_class_apply_cd = rz_cmd_desc_argv_new(core->rcmd, ic_cd, "ica", rz_cmd_info_class_apply_handler, &cmd_info_class_apply_help); + rz_warn_if_fail(cmd_info_class_apply_cd); + RzCmdDesc *cmd_info_class_as_source_cd = rz_cmd_desc_argv_new(core->rcmd, ic_cd, "icc", rz_cmd_info_class_as_source_handler, &cmd_info_class_as_source_help); rz_warn_if_fail(cmd_info_class_as_source_cd); @@ -23906,6 +23947,9 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { rz_warn_if_fail(cmd_info_class_methods_cd); rz_cmd_desc_set_default_mode(cmd_info_class_methods_cd, RZ_OUTPUT_MODE_TABLE); + RzCmdDesc *cmd_info_classes_to_struct_cd = rz_cmd_desc_argv_new(core->rcmd, ic_cd, "ics", rz_cmd_info_classes_to_struct_handler, &cmd_info_classes_to_struct_help); + rz_warn_if_fail(cmd_info_classes_to_struct_cd); + RzCmdDesc *cmd_info_signature_cd = rz_cmd_desc_argv_state_new(core->rcmd, i_cd, "iC", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_info_signature_handler, &cmd_info_signature_help); rz_warn_if_fail(cmd_info_signature_cd); @@ -24440,6 +24484,9 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) { RzCmdDesc *cmd_print_format_delete_all_cd = rz_cmd_desc_argv_new(core->rcmd, pf_cd, "pf-*", rz_cmd_print_format_delete_all_handler, &cmd_print_format_delete_all_help); rz_warn_if_fail(cmd_print_format_delete_all_cd); + RzCmdDesc *cmd_print_format_apply_cd = rz_cmd_desc_argv_new(core->rcmd, pf_cd, "pfa", rz_cmd_print_format_apply_handler, &cmd_print_format_apply_help); + rz_warn_if_fail(cmd_print_format_apply_cd); + RzCmdDesc *cmd_print_format_c_cd = rz_cmd_desc_argv_new(core->rcmd, pf_cd, "pfc", rz_cmd_print_format_c_handler, &cmd_print_format_c_help); rz_warn_if_fail(cmd_print_format_c_cd); diff --git a/librz/core/cmd_descs/cmd_descs.h b/librz/core/cmd_descs/cmd_descs.h index 98d4543903..1c2ed498f4 100644 --- a/librz/core/cmd_descs/cmd_descs.h +++ b/librz/core/cmd_descs/cmd_descs.h @@ -1686,12 +1686,16 @@ RZ_IPI RzCmdStatus rz_cmd_info_all_handler(RzCore *core, int argc, const char ** RZ_IPI RzCmdStatus rz_cmd_info_archs_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "ic" RZ_IPI RzCmdStatus rz_cmd_info_classes_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "ica" +RZ_IPI RzCmdStatus rz_cmd_info_class_apply_handler(RzCore *core, int argc, const char **argv); // "icc" RZ_IPI RzCmdStatus rz_cmd_info_class_as_source_handler(RzCore *core, int argc, const char **argv); // "icf" RZ_IPI RzCmdStatus rz_cmd_info_class_fields_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "icm" RZ_IPI RzCmdStatus rz_cmd_info_class_methods_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); +// "ics" +RZ_IPI RzCmdStatus rz_cmd_info_classes_to_struct_handler(RzCore *core, int argc, const char **argv); // "iC" RZ_IPI RzCmdStatus rz_cmd_info_signature_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state); // "id" @@ -2047,6 +2051,8 @@ RZ_IPI RzCmdStatus rz_cmd_print_format_handler(RzCore *core, int argc, const cha RZ_IPI RzCmdStatus rz_cmd_print_format_delete_handler(RzCore *core, int argc, const char **argv); // "pf-*" RZ_IPI RzCmdStatus rz_cmd_print_format_delete_all_handler(RzCore *core, int argc, const char **argv); +// "pfa" +RZ_IPI RzCmdStatus rz_cmd_print_format_apply_handler(RzCore *core, int argc, const char **argv); // "pfc" RZ_IPI RzCmdStatus rz_cmd_print_format_c_handler(RzCore *core, int argc, const char **argv); // "pfd" diff --git a/librz/core/cmd_descs/cmd_info.yaml b/librz/core/cmd_descs/cmd_info.yaml index 5e46cc5573..bea5a51675 100644 --- a/librz/core/cmd_descs/cmd_info.yaml +++ b/librz/core/cmd_descs/cmd_info.yaml @@ -46,6 +46,12 @@ commands: - RZ_OUTPUT_MODE_QUIET - RZ_OUTPUT_MODE_QUIETEST args: [] + - name: ica + summary: Apply class flags at given address + cname: cmd_info_class_apply + args: + - name: class name + type: RZ_CMD_ARG_TYPE_STRING - name: icc summary: Prints class, fields and methods as source code cname: cmd_info_class_as_source @@ -81,6 +87,10 @@ commands: - name: class name type: RZ_CMD_ARG_TYPE_STRING optional: true + - name: ics + summary: Generate type definitions from classes + cname: cmd_info_classes_to_struct + args: [] - name: iC cname: cmd_info_signature summary: Show signature info (entitlements, ...) diff --git a/librz/core/cmd_descs/cmd_print.yaml b/librz/core/cmd_descs/cmd_print.yaml index bafd2b7f00..18b6d84011 100644 --- a/librz/core/cmd_descs/cmd_print.yaml +++ b/librz/core/cmd_descs/cmd_print.yaml @@ -484,6 +484,12 @@ commands: summary: Remove all named formats cname: cmd_print_format_delete_all args: [] + - name: pfa + summary: Apply format string at given address and define flags for each field + cname: cmd_print_format_apply + args: + - name: format + type: RZ_CMD_ARG_TYPE_STRING - name: pfc summary: Show data using given format string with C syntax cname: cmd_print_format_c diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 0c75bcdf7a..19a7f5f6d1 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -1108,6 +1108,8 @@ RZ_API bool rz_core_bin_classes_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinF RZ_API bool rz_core_bin_class_as_source_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, const char *class_name); RZ_API bool rz_core_bin_class_fields_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, RZ_NONNULL RzCmdStateOutput *state, const char *class_name); RZ_API bool rz_core_bin_class_methods_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, RZ_NONNULL RzCmdStateOutput *state, const char *class_name); +RZ_API RzCmdStatus rz_core_bin_class_apply_print(RZ_NONNULL RzCore *core, RZ_NONNULL const char *classname, ut64 addr); +RZ_API bool rz_core_bin_classes_to_struct(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf); RZ_API bool rz_core_bin_signatures_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, RZ_NONNULL RzCmdStateOutput *state); RZ_API bool rz_core_bin_fields_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, RZ_NONNULL RzCmdStateOutput *state); RZ_API bool rz_core_bin_structured_data_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, RzOutputMode mode); diff --git a/test/db/cmd/cmd_i b/test/db/cmd/cmd_i index 7fa3f72467..81441a0504 100644 --- a/test/db/cmd/cmd_i +++ b/test/db/cmd/cmd_i @@ -616,6 +616,30 @@ class std::type_info { EOF RUN +NAME=ica +FILE=bins/mach0/objc-employee +CMDS=<