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).
376 lines
12 KiB
C
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;
|
|
}
|