* fix: format with clang-format-20 * fix: fix clang-format linter with rewrite '^#define.*/\*.*\\$' * fix: update clang-format to version 20 in workflows and documentation * fix: add SPDX license information to .git-blame-ignore-revs
288 lines
8.1 KiB
C
288 lines
8.1 KiB
C
// SPDX-FileCopyrightText: 2020 NIRMAL MANOJ C <nimmumanoj@gmail.com>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
#include <rz_util/rz_annotated_code.h>
|
|
|
|
#include <rz_util.h>
|
|
#include <rz_core.h>
|
|
#include <rz_types.h>
|
|
#include <rz_vector.h>
|
|
|
|
RZ_API void rz_core_annotated_code_print_json(RzAnnotatedCode *code) {
|
|
PJ *pj = pj_new();
|
|
if (!pj) {
|
|
return;
|
|
}
|
|
|
|
pj_o(pj);
|
|
pj_ks(pj, "code", code->code);
|
|
|
|
pj_k(pj, "annotations");
|
|
pj_a(pj);
|
|
|
|
char *type_str;
|
|
RzCodeAnnotation *annotation;
|
|
rz_vector_foreach (&code->annotations, annotation) {
|
|
pj_o(pj);
|
|
pj_kn(pj, "start", (ut64)annotation->start);
|
|
pj_kn(pj, "end", (ut64)annotation->end);
|
|
switch (annotation->type) {
|
|
case RZ_CODE_ANNOTATION_TYPE_OFFSET:
|
|
pj_ks(pj, "type", "offset");
|
|
pj_kn(pj, "offset", annotation->offset.offset);
|
|
break;
|
|
case RZ_CODE_ANNOTATION_TYPE_FUNCTION_NAME:
|
|
pj_ks(pj, "type", "function_name");
|
|
pj_ks(pj, "name", annotation->reference.name);
|
|
pj_kn(pj, "offset", annotation->reference.offset);
|
|
break;
|
|
case RZ_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE:
|
|
pj_ks(pj, "type", "global_variable");
|
|
pj_kn(pj, "offset", annotation->reference.offset);
|
|
break;
|
|
case RZ_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE:
|
|
pj_ks(pj, "type", "constant_variable");
|
|
pj_kn(pj, "offset", annotation->reference.offset);
|
|
break;
|
|
case RZ_CODE_ANNOTATION_TYPE_LOCAL_VARIABLE:
|
|
pj_ks(pj, "type", "local_variable");
|
|
pj_ks(pj, "name", annotation->variable.name);
|
|
break;
|
|
case RZ_CODE_ANNOTATION_TYPE_FUNCTION_PARAMETER:
|
|
pj_ks(pj, "type", "function_parameter");
|
|
pj_ks(pj, "name", annotation->variable.name);
|
|
break;
|
|
case RZ_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT:
|
|
pj_ks(pj, "type", "syntax_highlight");
|
|
type_str = NULL;
|
|
switch (annotation->syntax_highlight.type) {
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_KEYWORD:
|
|
type_str = "keyword";
|
|
break;
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_COMMENT:
|
|
type_str = "comment";
|
|
break;
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_DATATYPE:
|
|
type_str = "datatype";
|
|
break;
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME:
|
|
type_str = "function_name";
|
|
break;
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_PARAMETER:
|
|
type_str = "function_parameter";
|
|
break;
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_LOCAL_VARIABLE:
|
|
type_str = "local_variable";
|
|
break;
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_CONSTANT_VARIABLE:
|
|
type_str = "constant_variable";
|
|
break;
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_GLOBAL_VARIABLE:
|
|
type_str = "global_variable";
|
|
break;
|
|
}
|
|
if (type_str) {
|
|
pj_ks(pj, "syntax_highlight", type_str);
|
|
}
|
|
break;
|
|
}
|
|
pj_end(pj);
|
|
}
|
|
pj_end(pj);
|
|
|
|
pj_end(pj);
|
|
rz_cons_printf("%s\n", pj_string(pj));
|
|
pj_free(pj);
|
|
}
|
|
|
|
#define PALETTE(x) (cons && cons->context->pal.x) ? cons->context->pal.x
|
|
#define PRINT_COLOR(x) \
|
|
do { \
|
|
if (cons->context->color_mode) { \
|
|
rz_cons_printf("%s", (x)); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @param width maximum nibbles per address
|
|
*/
|
|
static void print_offset_in_binary_line_bar(RzAnnotatedCode *code, ut64 offset, size_t width) {
|
|
static const char *fmt[9] = {
|
|
"0x%08" PFMT64x,
|
|
"0x%09" PFMT64x,
|
|
"0x%010" PFMT64x,
|
|
"0x%011" PFMT64x,
|
|
"0x%012" PFMT64x,
|
|
"0x%013" PFMT64x,
|
|
"0x%014" PFMT64x,
|
|
"0x%015" PFMT64x,
|
|
"0x%016" PFMT64x
|
|
};
|
|
if (width < 8) {
|
|
width = 8;
|
|
}
|
|
if (width > 16) {
|
|
width = 16;
|
|
}
|
|
width -= 8;
|
|
|
|
RzCons *cons = rz_cons_singleton();
|
|
rz_cons_printf(" ");
|
|
if (offset == UT64_MAX) {
|
|
rz_cons_print(" ");
|
|
while (width > 0) {
|
|
rz_cons_print(" ");
|
|
width--;
|
|
}
|
|
} else {
|
|
PRINT_COLOR(PALETTE(offset) : Color_GREEN);
|
|
rz_cons_printf(fmt[width], offset);
|
|
PRINT_COLOR(Color_RESET);
|
|
}
|
|
rz_cons_printf(" |");
|
|
}
|
|
|
|
RZ_API void rz_core_annotated_code_print(RzAnnotatedCode *code, RzVector /*<ut64>*/ *line_offsets) {
|
|
if (code->annotations.len == 0) {
|
|
rz_cons_printf("%s\n", code->code);
|
|
return;
|
|
}
|
|
|
|
size_t cur = 0;
|
|
size_t line_idx = 0;
|
|
size_t len = strlen(code->code);
|
|
|
|
size_t offset_width = 0;
|
|
if (line_offsets) {
|
|
ut64 *offset;
|
|
ut64 offset_max = 0;
|
|
rz_vector_foreach (line_offsets, offset) {
|
|
if (*offset != UT64_MAX && *offset > offset_max) {
|
|
offset_max = *offset;
|
|
}
|
|
}
|
|
while (offset_max) {
|
|
offset_width += 1;
|
|
offset_max >>= 4;
|
|
}
|
|
if (offset_width < 4) {
|
|
offset_width = 4;
|
|
}
|
|
}
|
|
|
|
RzCons *cons = rz_cons_singleton();
|
|
RzCodeAnnotation *annotation;
|
|
rz_vector_foreach (&code->annotations, annotation) {
|
|
if (annotation->type != RZ_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT) {
|
|
continue;
|
|
}
|
|
|
|
// (1/3)
|
|
// now we have a syntax highlighting annotation.
|
|
// pick a suitable color for it.
|
|
const char *color = Color_RESET;
|
|
switch (annotation->syntax_highlight.type) {
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_COMMENT:
|
|
color = PALETTE(comment)
|
|
: Color_WHITE;
|
|
break;
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_KEYWORD:
|
|
color = PALETTE(pop)
|
|
: Color_MAGENTA;
|
|
break;
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_DATATYPE:
|
|
color = PALETTE(func_var_type)
|
|
: Color_BLUE;
|
|
break;
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME:
|
|
color = PALETTE(fname)
|
|
: Color_RED;
|
|
break;
|
|
case RZ_SYNTAX_HIGHLIGHT_TYPE_CONSTANT_VARIABLE:
|
|
color = PALETTE(num)
|
|
: Color_YELLOW;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// (2/3)
|
|
// the chunk before the syntax highlighting annotation should not be colored
|
|
for (; cur < annotation->start && cur < len; cur++) {
|
|
// if we are starting a new line and we are printing with offsets
|
|
// we need to prepare the bar with offsets on the left handside before that
|
|
if (line_offsets && (cur == 0 || code->code[cur - 1] == '\n')) {
|
|
ut64 offset = 0;
|
|
if (line_idx < line_offsets->len) {
|
|
offset = *(ut64 *)rz_vector_index_ptr(line_offsets, line_idx);
|
|
}
|
|
print_offset_in_binary_line_bar(code, offset, offset_width);
|
|
line_idx++;
|
|
}
|
|
rz_cons_printf("%c", code->code[cur]);
|
|
}
|
|
|
|
// (3/3)
|
|
// everything in between the "start" and the "end" inclusive should be highlighted
|
|
PRINT_COLOR(color);
|
|
for (; cur < annotation->end && cur < len; cur++) {
|
|
// if we are starting a new line and we are printing with offsets
|
|
// we need to prepare the bar with offsets on the left handside before that
|
|
if (line_offsets && (cur == 0 || code->code[cur - 1] == '\n')) {
|
|
ut64 offset = 0;
|
|
if (line_idx < line_offsets->len) {
|
|
offset = *(ut64 *)rz_vector_index_ptr(line_offsets, line_idx);
|
|
}
|
|
PRINT_COLOR(Color_RESET);
|
|
print_offset_in_binary_line_bar(code, offset, offset_width);
|
|
PRINT_COLOR(color);
|
|
line_idx++;
|
|
}
|
|
rz_cons_printf("%c", code->code[cur]);
|
|
}
|
|
PRINT_COLOR(Color_RESET);
|
|
}
|
|
// the rest of the decompiled code should be printed
|
|
// without any highlighting since we don't have any annotations left
|
|
for (; cur < len; cur++) {
|
|
// if we are starting a new line and we are printing with offsets
|
|
// we need to prepare the bar with offsets on the left handside before that
|
|
if (line_offsets && (cur == 0 || code->code[cur - 1] == '\n')) {
|
|
ut64 offset = 0;
|
|
if (line_idx < line_offsets->len) {
|
|
offset = *(ut64 *)rz_vector_index_ptr(line_offsets, line_idx);
|
|
}
|
|
print_offset_in_binary_line_bar(code, offset, offset_width);
|
|
line_idx++;
|
|
}
|
|
rz_cons_printf("%c", code->code[cur]);
|
|
}
|
|
}
|
|
|
|
static bool foreach_offset_annotation(void *user, const ut64 offset, const void *val) {
|
|
RzAnnotatedCode *code = user;
|
|
const RzCodeAnnotation *annotation = val;
|
|
char *b64statement = rz_base64_encode_dyn((const ut8 *)(code->code + annotation->start),
|
|
annotation->end - annotation->start);
|
|
rz_cons_printf("CCu base64:%s @ 0x%" PFMT64x "\n", b64statement, annotation->offset.offset);
|
|
free(b64statement);
|
|
return true;
|
|
}
|
|
|
|
RZ_API void rz_core_annotated_code_print_comment_cmds(RzAnnotatedCode *code) {
|
|
RzCodeAnnotation *annotation;
|
|
HtUP *ht = ht_up_new(NULL, NULL);
|
|
rz_vector_foreach (&code->annotations, annotation) {
|
|
if (annotation->type != RZ_CODE_ANNOTATION_TYPE_OFFSET) {
|
|
continue;
|
|
}
|
|
// choose the "best" annotation at a single offset
|
|
RzCodeAnnotation *prev_annot = ht_up_find(ht, annotation->offset.offset, NULL);
|
|
if (prev_annot) {
|
|
if (annotation->end - annotation->start < prev_annot->end - prev_annot->start) {
|
|
continue;
|
|
}
|
|
}
|
|
ht_up_update(ht, annotation->offset.offset, annotation);
|
|
}
|
|
ht_up_foreach(ht, foreach_offset_annotation, code);
|
|
ht_up_free(ht);
|
|
}
|