rizin/librz/core/cmd/cmd_cmp.c
Florian Märkl c542bfcb4a Make cb use cfg.bigendian instead of host one
Fixes the remaining test in test/db/cmd/cmd_c on big endian hosts,
tested on OpenBSD/sparc64.
The mask calculation was removed because it was unnecessary (only
comparing selected bytes anyway) and wrong by a factor of 8 (bits vs.
bytes confusion).
2022-08-19 16:10:54 +02:00

376 lines
12 KiB
C

// SPDX-FileCopyrightText: 2009-2019 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_cmp.h>
#include "../core_private.h"
static void rizin_compare_words(RzCore *core, ut64 of, ut64 od, int len, int ws) {
rz_return_if_fail(core && (ws == 1 || ws == 2 || ws == 4 || ws == 8));
int i;
bool useColor = rz_config_get_i(core->config, "scr.color") != 0;
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
ut64 v[2];
RzConsPrintablePalette *pal = &rz_cons_singleton()->context->pal;
for (i = 0; i < len; i += ws) {
for (size_t j = 0; j < 2; j++) {
ut8 tmp[8] = { 0 };
rz_io_nread_at(core->io, (j ? od : of) + i, tmp, ws);
v[j] = rz_read_ble(tmp, big_endian, ws * 8);
}
char ch = (v[0] == v[1]) ? '=' : '!';
const char *color = useColor ? ch == '=' ? "" : pal->graph_false : "";
const char *colorEnd = useColor ? Color_RESET : "";
if (useColor) {
rz_cons_printf("%s0x%08" PFMT64x " " Color_RESET, pal->offset, of + i);
} else {
rz_cons_printf("0x%08" PFMT64x " ", of + i);
}
switch (ws) {
case 1:
rz_cons_printf("%s0x%02x %c 0x%02x%s\n", color,
(ut32)(v[0] & 0xff), ch, (ut32)(v[1] & 0xff), colorEnd);
break;
case 2:
rz_cons_printf("%s0x%04hx %c 0x%04hx%s\n", color,
(ut16)v[0], ch, (ut16)v[1], colorEnd);
break;
case 4:
rz_cons_printf("%s0x%08" PFMT32x " %c 0x%08" PFMT32x "%s\n", color,
(ut32)v[0], ch, (ut32)v[1], colorEnd);
break;
case 8:
rz_cons_printf("%s0x%016" PFMT64x " %c 0x%016" PFMT64x "%s\n",
color, v[0], ch, v[1], colorEnd);
break;
}
}
}
static bool rizin_compare_unified(RzCore *core, RzCompareData *cmp) {
int i, min = 1, inc = 16;
int headers = B_IS_SET(core->print->flags, RZ_PRINT_FLAGS_HEADER);
if (headers) {
B_UNSET(core->print->flags, RZ_PRINT_FLAGS_HEADER);
}
for (i = 0; i < cmp->len; i += inc) {
min = RZ_MIN(16, (cmp->len - i));
if (!memcmp(cmp->data1 + i, cmp->data2 + i, min)) {
rz_cons_printf(" ");
rz_core_print_hexdiff(core, cmp->addr1 + i, cmp->data1 + i, cmp->addr1 + i, cmp->data1 + i, min, 0);
} else {
rz_cons_printf("- ");
rz_core_print_hexdiff(core, cmp->addr1 + i, cmp->data1 + i, cmp->addr2 + i, cmp->data2 + i, min, 0);
rz_cons_printf("+ ");
rz_core_print_hexdiff(core, cmp->addr2 + i, cmp->data2 + i, cmp->addr1 + i, cmp->data1 + i, min, 0);
}
}
if (headers) {
B_SET(core->print->flags, RZ_PRINT_FLAGS_HEADER);
}
return true;
}
static bool core_cmp_bits(RzCore *core, RzCompareData *cmp) {
const bool scr_color = rz_config_get_i(core->config, "scr.color");
int i;
RzConsPrintablePalette *pal = &rz_cons_singleton()->context->pal;
const char *color = scr_color ? pal->offset : "";
const char *color_end = scr_color ? Color_RESET : "";
if (rz_config_get_i(core->config, "hex.header")) {
char *n = rz_str_newf("0x%08" PFMT64x, cmp->addr1);
const char *extra = rz_str_pad(' ', strlen(n) - 10);
free(n);
rz_cons_printf("%s- offset -%s 7 6 5 4 3 2 1 0%s\n", color, extra, color_end);
}
color = scr_color ? pal->graph_false : "";
color_end = scr_color ? Color_RESET : "";
rz_cons_printf("%s0x%08" PFMT64x "%s ", color, cmp->addr1, color_end);
for (i = 7; i >= 0; i--) {
bool b0 = (cmp->data1[0] & 1 << i) ? 1 : 0;
bool b1 = (cmp->data2[0] & 1 << i) ? 1 : 0;
color = scr_color ? (b0 == b1) ? "" : b0 ? pal->graph_true
: pal->graph_false
: "";
color_end = scr_color ? Color_RESET : "";
rz_cons_printf("%s%d%s ", color, b0, color_end);
}
color = scr_color ? pal->graph_true : "";
color_end = scr_color ? Color_RESET : "";
rz_cons_printf("\n%s0x%08" PFMT64x "%s ", color, cmp->addr2, color_end);
for (i = 7; i >= 0; i--) {
bool b0 = (cmp->data1[0] & 1 << i) ? 1 : 0;
bool b1 = (cmp->data2[0] & 1 << i) ? 1 : 0;
color = scr_color ? (b0 == b1) ? "" : b1 ? pal->graph_true
: pal->graph_false
: "";
color_end = scr_color ? Color_RESET : "";
rz_cons_printf("%s%d%s ", color, b1, color_end);
}
rz_cons_newline();
return true;
}
// c
RZ_IPI RzCmdStatus rz_cmd_cmp_string_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzCmdStatus ret = RZ_CMD_STATUS_ERROR;
char *unescaped = strdup(argv[1]);
int len = rz_str_unescape(unescaped);
RzCompareData *cmp = rz_core_cmp_mem_data(core, core->offset, (ut8 *)unescaped, len);
if (!cmp) {
goto end;
}
int val = rz_core_cmp_print(core, cmp, state);
ret = val != -1 ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
end:
rz_core_cmp_free(cmp);
free(unescaped);
return ret;
}
// c1
RZ_IPI RzCmdStatus rz_cmd_cmp_bits_handler(RzCore *core, int argc, const char **argv) {
RzCompareData *cmp = rz_core_cmp_mem_mem(core, core->offset, rz_num_math(core->num, argv[1]), 1);
if (!cmp) {
return RZ_CMD_STATUS_ERROR;
}
bool val = core_cmp_bits(core, cmp);
rz_core_cmp_free(cmp);
return val ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
// ca
RZ_IPI RzCmdStatus rz_cmd_cmp_addr_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzCompareData *cmp = rz_core_cmp_mem_mem(core, core->offset, rz_num_math(core->num, argv[1]), rz_num_math(core->num, argv[2]));
if (!cmp) {
return RZ_CMD_STATUS_ERROR;
}
int val = rz_core_cmp_print(core, cmp, state);
rz_core_cmp_free(cmp);
return val != -1 ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
// cb
RZ_IPI RzCmdStatus rz_cmd_cmp_bytes_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
RzCmdStatus ret = RZ_CMD_STATUS_ERROR;
ut64 sz = rz_num_math(core->num, argv[2]);
if (sz > 8) {
RZ_LOG_ERROR("Cannot compare more than 8 bytes. Use the c command instead.\n");
return ret;
}
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
ut64 num = rz_num_math(core->num, argv[1]);
ut8 tmp[8] = { 0 };
rz_write_ble64(tmp, num, big_endian);
RzCompareData *cmp = rz_core_cmp_mem_data(core, core->offset, big_endian && sz ? tmp + (8 - sz) : tmp, sz);
if (!cmp) {
goto end;
}
int val = rz_core_cmp_print(core, cmp, state);
ret = val != -1 ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
end:
rz_core_cmp_free(cmp);
return ret;
}
// cc
RZ_IPI RzCmdStatus rz_cmd_cmp_hex_block_handler(RzCore *core, int argc, const char **argv) {
ut64 addr = rz_num_math(core->num, argv[1]);
bool col = core->cons->columns > 123;
ut8 *b = malloc(core->blocksize);
if (b) {
memset(b, 0xff, core->blocksize);
rz_io_nread_at(core->io, addr, b, core->blocksize);
rz_core_print_hexdiff(core, core->offset, core->block, addr, b, core->blocksize, col);
}
free(b);
return RZ_CMD_STATUS_OK;
}
// ccc
RZ_IPI RzCmdStatus rz_cmd_cmp_hex_diff_lines_handler(RzCore *core, int argc, const char **argv) {
ut32 oflags = core->print->flags;
core->print->flags |= RZ_PRINT_FLAGS_DIFFOUT;
ut64 addr = rz_num_math(core->num, argv[1]);
bool col = core->cons->columns > 123;
ut8 *b = malloc(core->blocksize);
if (b) {
memset(b, 0xff, core->blocksize);
rz_io_nread_at(core->io, addr, b, core->blocksize);
rz_core_print_hexdiff(core, core->offset, core->block, addr, b, core->blocksize, col);
}
free(b);
core->print->flags = oflags;
return RZ_CMD_STATUS_OK;
}
// ccd
RZ_IPI RzCmdStatus rz_cmd_cmp_disasm_handler(RzCore *core, int argc, const char **argv) {
RzList *cmp = rz_core_cmp_disasm(core, core->offset, rz_num_math(core->num, argv[1]), core->blocksize);
bool ret = rz_core_cmp_disasm_print(core, cmp, false);
rz_list_free(cmp);
return ret ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
// cf
RZ_IPI RzCmdStatus rz_cmd_cmp_file_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
FILE *fd = rz_sys_fopen(argv[1], "rb");
if (!fd) {
RZ_LOG_ERROR("Cannot open file: %s\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
}
RzCmdStatus stat = RZ_CMD_STATUS_ERROR;
ut8 *buf = (ut8 *)malloc(core->blocksize);
if (!buf) {
goto return_goto;
}
if (fread(buf, 1, core->blocksize, fd) < 1) {
RZ_LOG_ERROR("Cannot read file: %s\n", argv[1]);
goto return_goto;
}
RzCompareData *cmp = rz_core_cmp_mem_data(core, core->offset, buf, core->blocksize);
if (!cmp) {
goto return_goto;
}
int val = rz_core_cmp_print(core, cmp, state);
rz_core_cmp_free(cmp);
stat = val != -1 ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
return_goto:
free(buf);
fclose(fd);
return stat;
}
// cu
RZ_IPI RzCmdStatus rz_cmd_cmp_unified_handler(RzCore *core, int argc, const char **argv) {
RzCompareData *cmp = rz_core_cmp_mem_mem(core, core->offset, rz_num_math(core->num, argv[1]), core->blocksize);
bool ret = rizin_compare_unified(core, cmp);
rz_core_cmp_free(cmp);
return ret ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
// cu1
RZ_IPI RzCmdStatus rz_cmd_cmp_unified1_handler(RzCore *core, int argc, const char **argv) {
rizin_compare_words(core, core->offset, rz_num_math(core->num, argv[1]), core->blocksize, 1);
return RZ_CMD_STATUS_OK;
}
// cu2
RZ_IPI RzCmdStatus rz_cmd_cmp_unified2_handler(RzCore *core, int argc, const char **argv) {
rizin_compare_words(core, core->offset, rz_num_math(core->num, argv[1]), core->blocksize, 2);
return RZ_CMD_STATUS_OK;
}
// cu4
RZ_IPI RzCmdStatus rz_cmd_cmp_unified4_handler(RzCore *core, int argc, const char **argv) {
rizin_compare_words(core, core->offset, rz_num_math(core->num, argv[1]), core->blocksize, 4);
return RZ_CMD_STATUS_OK;
}
// cu8
RZ_IPI RzCmdStatus rz_cmd_cmp_unified8_handler(RzCore *core, int argc, const char **argv) {
rizin_compare_words(core, core->offset, rz_num_math(core->num, argv[1]), core->blocksize, 8);
return RZ_CMD_STATUS_OK;
}
// cud
RZ_IPI RzCmdStatus rz_cmd_cmp_unified_disasm_handler(RzCore *core, int argc, const char **argv) {
RzList *cmp = rz_core_cmp_disasm(core, core->offset, rz_num_math(core->num, argv[1]), core->blocksize);
bool ret = rz_core_cmp_disasm_print(core, cmp, true);
rz_list_free(cmp);
return ret ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
// cw
RZ_IPI RzCmdStatus rz_cmd_cmp_add_memory_watcher_handler(RzCore *core, int argc, const char **argv) {
return rz_core_cmpwatch_add(core, core->offset, atoi(argv[1]), argv[2]) ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
// cwl
RZ_IPI RzCmdStatus rz_cmd_cmp_list_compare_watchers_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
rz_core_cmpwatch_show(core, UT64_MAX, mode);
return RZ_CMD_STATUS_OK;
}
// cwr
RZ_IPI RzCmdStatus rz_cmd_cmp_reset_watcher_handler(RzCore *core, int argc, const char **argv) {
return rz_core_cmpwatch_revert(core, core->offset) ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
// cwu
RZ_IPI RzCmdStatus rz_cmd_cmp_update_watcher_handler(RzCore *core, int argc, const char **argv) {
return rz_core_cmpwatch_update(core, core->offset) ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
// cwx
RZ_IPI RzCmdStatus rz_cmd_cmp_remove_watcher_handler(RzCore *core, int argc, const char **argv) {
return rz_core_cmpwatch_del(core, core->offset) ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
// cx
RZ_IPI RzCmdStatus rz_cmd_cmp_hexpair_string_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
char *input = strdup(argv[1]);
rz_str_remove_char(input, ' ');
unsigned char *buf;
int ret = false;
if (!(buf = (ut8 *)malloc(strlen(input) + 1))) {
goto return_goto;
}
ret = rz_hex_bin2str(core->block, strlen(input) / 2, (char *)buf);
for (int i = 0; i < ret * 2; i++) {
if (input[i] == '.') {
input[i] = buf[i];
}
}
ret = rz_hex_str2bin(input, buf);
if (ret < 1) {
RZ_LOG_ERROR("Cannot parse hexpair\n");
ret = false;
goto return_goto;
}
RzCompareData *cmp = rz_core_cmp_mem_data(core, core->offset, buf, strlen(input) / 2);
if (!cmp) {
goto return_goto;
}
core->num->value = cmp->same ? 0 : 1;
int val = rz_core_cmp_print(core, cmp, state);
rz_core_cmp_free(cmp);
ret = val != -1;
return_goto:
free(input);
free(buf);
return ret ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}
// cX
RZ_IPI RzCmdStatus rz_cmd_cmp_hex_block_hexdiff_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
unsigned char *buf = malloc(core->blocksize);
bool ret = false;
if (!buf) {
goto return_goto;
}
if (rz_io_nread_at(core->io, rz_num_math(core->num, argv[1]), buf, core->blocksize) == -1) {
RZ_LOG_ERROR("Cannot read hexdump at %s\n", argv[1]);
goto return_goto;
}
RzCompareData *cmp = rz_core_cmp_mem_data(core, core->offset, buf, core->blocksize);
if (!cmp) {
free(cmp);
goto return_goto;
}
int val = rz_core_cmp_print(core, cmp, state);
rz_core_cmp_free(cmp);
ret = val != -1;
return_goto:
free(buf);
return ret ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
}