rizin/librz/core/cannotated_code.c
2020-12-07 23:18:29 -06:00

286 lines
8.1 KiB
C

#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 *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 (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_new0 ();
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);
}