Migrating RAnnotatedCode to radare2 (#16939)

* Added comments for functions in RAnnotatedCode
* Modified code to follow coding style
* Added more documentation and changed the name of core_annotated_code.c
* Fixed memory leaks
This commit is contained in:
NIRMAL MANOJ C 2020-05-27 09:24:31 +05:30 committed by GitHub
parent 688c411afe
commit 305cc00766
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 868 additions and 2 deletions

View File

@ -11,6 +11,7 @@ OBJS+=fortune.o hack.o vasm.o patch.o cbin.o corelog.o rtr.o cmd_api.o
OBJS+=carg.o canal.o project.o gdiff.o casm.o disasm.o cplugin.o
OBJS+=vmenus.o vmenus_graph.o vmenus_zigns.o zdiff.o citem.o
OBJS+=task.o panels.o pseudo.o vmarks.o anal_tp.o anal_objc.o blaze.o cundo.o
OBJS+=cannotated_code.o
CFLAGS+=-I../../shlr/heap/include
CFLAGS+=-I../../shlr/tree-sitter/lib/include -I../../shlr/radare2-shell-parser/src/tree_parser

262
libr/core/cannotated_code.c Normal file
View File

@ -0,0 +1,262 @@
#include <r_util/r_annotated_code.h>
#include <r_util.h>
#include <r_core.h>
#include <r_types.h>
#include <r_vector.h>
R_API void r_core_annotated_code_print_json(RAnnotatedCode *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;
RCodeAnnotation *annotation;
r_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 R_CODE_ANNOTATION_TYPE_OFFSET:
pj_ks (pj, "type", "offset");
pj_kn (pj, "offset", annotation->offset.offset);
break;
case R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT:
pj_ks (pj, "type", "syntax_highlight");
switch (annotation->syntax_highlight.type) {
case R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD:
type_str = "keyword";
break;
case R_SYNTAX_HIGHLIGHT_TYPE_COMMENT:
type_str = "comment";
break;
case R_SYNTAX_HIGHLIGHT_TYPE_DATATYPE:
type_str = "datatype";
break;
case R_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME:
type_str = "function_name";
break;
case R_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_PARAMETER:
type_str = "function_parameter";
break;
case R_SYNTAX_HIGHLIGHT_TYPE_LOCAL_VARIABLE:
type_str = "local_variable";
break;
case R_SYNTAX_HIGHLIGHT_TYPE_CONSTANT_VARIABLE:
type_str = "constant_variable";
break;
case R_SYNTAX_HIGHLIGHT_TYPE_GLOBAL_VARIABLE:
type_str = "global_variable";
break;
}
pj_ks (pj, "syntax_highlight", type_str);
break;
}
pj_end (pj);
}
pj_end (pj);
pj_end (pj);
r_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) { \
r_cons_printf ("%s", (x)); \
} \
} while (0)
/**
* @param width maximum nibbles per address
*/
static void print_offset_in_binary_line_bar(RAnnotatedCode *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;
RCons *cons = r_cons_singleton ();
r_cons_printf (" ");
if (offset == UT64_MAX) {
r_cons_print (" ");
while (width > 0) {
r_cons_print (" ");
width--;
}
} else {
PRINT_COLOR (PALETTE (offset)
: Color_GREEN);
r_cons_printf (fmt[width], offset);
PRINT_COLOR (Color_RESET);
}
r_cons_printf (" |");
}
R_API void r_core_annotated_code_print(RAnnotatedCode *code, RVector *line_offsets) {
if (code->annotations.len == 0) {
r_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;
r_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;
}
}
RCons *cons = r_cons_singleton ();
RCodeAnnotation *annotation;
r_vector_foreach (&code->annotations, annotation) {
if (annotation->type != R_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 R_SYNTAX_HIGHLIGHT_TYPE_COMMENT:
color = PALETTE (comment)
: Color_WHITE;
break;
case R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD:
color = PALETTE (pop)
: Color_MAGENTA;
break;
case R_SYNTAX_HIGHLIGHT_TYPE_DATATYPE:
color = PALETTE (func_var_type)
: Color_BLUE;
break;
case R_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME:
color = PALETTE (fname)
: Color_RED;
break;
case R_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 *)r_vector_index_ptr (line_offsets, line_idx);
}
print_offset_in_binary_line_bar (code, offset, offset_width);
line_idx++;
}
r_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 *)r_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++;
}
r_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 *)r_vector_index_ptr (line_offsets, line_idx);
}
print_offset_in_binary_line_bar (code, offset, offset_width);
line_idx++;
}
r_cons_printf ("%c", code->code[cur]);
}
}
static bool foreach_offset_annotation(void *user, const ut64 offset, const void *val) {
RAnnotatedCode *code = user;
const RCodeAnnotation *annotation = val;
char *b64statement = r_base64_encode_dyn (code->code + annotation->start, annotation->end - annotation->start);
r_cons_printf ("CCu base64:%s @ 0x%" PFMT64x "\n", b64statement, annotation->offset.offset);
free (b64statement);
return true;
}
R_API void r_core_annotated_code_print_comment_cmds(RAnnotatedCode *code) {
RCodeAnnotation *annotation;
HtUP *ht = ht_up_new0 ();
r_vector_foreach (&code->annotations, annotation) {
if (annotation->type != R_CODE_ANNOTATION_TYPE_OFFSET) {
continue;
}
// choose the "best" annotation at a single offset
RCodeAnnotation *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);
}

View File

@ -65,6 +65,7 @@ r_core_sources = [
'yank.c',
'p/core_a2f.c',
'p/core_java.c',
'cannotated_code.c'
]
r_core_inc = []

View File

@ -30,6 +30,7 @@
#include "r_util/r_print.h"
#include "r_crypto.h"
#include "r_bind.h"
#include "r_util/r_annotated_code.h"
#ifdef __cplusplus
extern "C" {
@ -924,6 +925,43 @@ R_API void r_core_anal_propagate_noreturn(RCore *core, ut64 addr);
extern RCorePlugin r_core_plugin_java;
extern RCorePlugin r_core_plugin_a2f;
/* DECOMPILER PRINTING FUNCTIONS */
/**
* r_core_annotated_code_print_json() - Prints the data contained in RAnnotatedCode *code in JSON format.
* @code: Pointer to a RAnnotatedCode
*
* Prints the data contained in RAnnotatedCode represented by the pointer 'code' in JSON format.
* The function will print the output in console using the function r_cons_printf();
*
* Return: Nothing
*/
R_API void r_core_annotated_code_print_json(RAnnotatedCode *code);
/**
* r_core_annotated_code_print() - Prints the decompiled code in the passed argument 'code'.
* @code: Pointer to a RAnnotatedCode
* @line_offsets: Pointer to a RVector that containes offsets for the decompiled code
*
* This function is used for printing the output of commands pdg and pdgo.
* It can print the decompiled code with or without offsets. If line_offsets is a null pointer,
* the output will be printed without offsets (pdg), otherwise, the output will be
* printed with offsets.
* This function will print the output in console using the function r_cons_printf();
*
* Return: Nothing
*/
R_API void r_core_annotated_code_print(RAnnotatedCode *code, RVector *line_offsets);
/**
* r_core_annotated_code_print_comment_cmds() - Prints the decompiled code as comments
* @code: Pointer to a RAnnotatedCode
*
* This functions prints the decompiled code as comment.
* This function is used for the output of command pdg*
* Output will be printed in console using the function r_cons_printf();
*
* Return: Nothing
*/
R_API void r_core_annotated_code_print_comment_cmds(RAnnotatedCode *code);
#endif
#ifdef __cplusplus

View File

@ -0,0 +1,133 @@
#ifndef R_ANNOTATEDCODE_H
#define R_ANNOTATEDCODE_H
// #include <r_core.h>
#include <r_types.h>
#include <r_vector.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum r_syntax_highlight_type_t {
R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD,
R_SYNTAX_HIGHLIGHT_TYPE_COMMENT,
R_SYNTAX_HIGHLIGHT_TYPE_DATATYPE,
R_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME,
R_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_PARAMETER,
R_SYNTAX_HIGHLIGHT_TYPE_LOCAL_VARIABLE,
R_SYNTAX_HIGHLIGHT_TYPE_CONSTANT_VARIABLE,
R_SYNTAX_HIGHLIGHT_TYPE_GLOBAL_VARIABLE,
} RSyntaxHighlightType;
/**
* enum r_code_annotation_type_t - typedefed as RCodeAnnotationType and this gives types of annotation
*
* There are two kinds of RCodeAnnotation. One for offset, which of the type
* R_CODE_ANNOTATION_TYPE_OFFSET and other one is for syntax highlight, which is
* of the type R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT.
* R_CODE_ANNOTATION_TYPE_OFFSET is for representing annotations that gives an offset for
* a range while R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT is for representing the
* kind of data the range represents. Here, range refers to the range of annotation.
*/
typedef enum r_code_annotation_type_t {
R_CODE_ANNOTATION_TYPE_OFFSET,
R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT,
// ...
} RCodeAnnotationType;
typedef struct r_code_annotation_t {
size_t start;
size_t end;
RCodeAnnotationType type;
union {
struct {
ut64 offset;
} offset;
struct {
RSyntaxHighlightType type;
} syntax_highlight;
};
} RCodeAnnotation;
typedef struct r_annotated_code_t {
char *code; // owned
RVector /*<RCodeAnnotation>*/ annotations;
} RAnnotatedCode;
/**
* r_annotated_code_new() - Creates a new RAnnotatedCode structure and returns its pointer.
* @code: Literal code for which the RAnnotatedCode structure will be created .
*
* This functions creates a new RAnnotatedCode structure.
* RAnnotatedCode.code will be initialized as the character array passed.
* Here, code must be a string that can deallocated.
* This will initialize RVector<RCodeAnnotation> annotations as well.
*
* Return: Pointer to the new RAnnotatedCode structure created.
*/
R_API RAnnotatedCode *r_annotated_code_new(char *code);
/**
* r_annotated_code_free() - Deallocates *code.
* @code: Pointer to a RAnnotatedCode.
*
* This functions deallocates memory allocated for *code.
*
* Return: Nothing.
*/
R_API void r_annotated_code_free(RAnnotatedCode *code);
/**
* r_annotated_code_add_annotation() - Inserts *annotation in *code.
* @code: Pointer to a RAnnotatedCode.
* @annotation: Pointer to a annotation.
*
* This functions inserts the annotation represented by the pointer 'annotation' to the vector
* of annotations in the RAnnotatedCode represented by 'code'. To be more precise,
* annotation will be added to code->annotations, which is a RVector<RCodeAnnotation> annotations.
*
* Return: Nothing.
*/
R_API void r_annotated_code_add_annotation(RAnnotatedCode *code, RCodeAnnotation *annotation);
/**
* r_annotated_code_annotations_in() - Returns all annotations with range that contains the given offset.
* @code: Pointer to a RAnnotatedCode.
* @offset: Offset.
*
* Creates an RPVector and inserts the pointers to all annotations in which
* annotation->start <= offset < annotation->end.
*
* Return: Pointer to the RPVecrtor created.
*/
R_API RPVector *r_annotated_code_annotations_in(RAnnotatedCode *code, size_t offset);
/**
* r_annotated_code_annotations_range() - Returns all annotations with range that overlap with the given range.
* @code: Pointer to a RAnnotatedCode.
* @start: Start of the range(inclusive).
* @end: End of the range(exclusive).
*
* Creates an RPVector and inserts the pointers to all annotations whose
* range overlap with range [start, end-1] (both inclusive).
*
* Return: Pointer to the RPVecrtor created.
*/
R_API RPVector *r_annotated_code_annotations_range(RAnnotatedCode *code, size_t start, size_t end);
/**
* r_annotated_code_line_offsets() - Returns the offset for every line of decompiled code in RAnnotatedCode *code.
* @code: Pointer to a RAnnotatedCode.
*
* Creates an RVector and inserts the offsets for every seperate line of decompiled code in
* code->code (code->code is a character array).
* If a line of decompiled code doesn't have a unique offset, UT64_MAX is inserted as its offset.
*
* Return: Pointer to the RVector created.
*/
R_API RVector *r_annotated_code_line_offsets(RAnnotatedCode *code);
#ifdef __cplusplus
}
#endif
#endif //R_ANNOTATEDCODE_H

View File

@ -431,7 +431,8 @@ r_util_files = [
'include/r_util/r_utf16.h',
'include/r_util/r_utf32.h',
'include/r_util/r_utf8.h',
'include/r_util/r_x509.h'
'include/r_util/r_x509.h',
'include/r_util/r_annotated_code.h'
]
install_headers(r_util_files, subdir: 'libr/r_util')

View File

@ -23,6 +23,7 @@ OBJS+=udiff.o bdiff.o stack.o queue.o tree.o idpool.o assert.o
OBJS+=punycode.o pkcs7.o x509.o asn1.o astr.o json_indent.o skiplist.o pj.o
OBJS+=rbtree.o intervaltree.o qrcode.o vector.o str_constpool.o str_trim.o
OBJS+=ascii_table.o protobuf.o
OBJS+=annotated_code.o
ifeq (${HAVE_LIB_GMP},1)
OBJS+=big-gmp.o

View File

@ -0,0 +1,84 @@
#include <r_util/r_annotated_code.h>
#include <r_core.h>
#include <r_util.h>
R_API RAnnotatedCode *r_annotated_code_new(char *code) {
RAnnotatedCode *r = R_NEW0 (RAnnotatedCode);
if (!r) {
return NULL;
}
r->code = code;
r_vector_init (&r->annotations, sizeof (RCodeAnnotation), NULL, NULL);
return r;
}
R_API void r_annotated_code_free(RAnnotatedCode *code) {
if (!code) {
return;
}
r_vector_clear (&code->annotations);
r_free (code->code);
r_free (code);
}
R_API void r_annotated_code_add_annotation(RAnnotatedCode *code, RCodeAnnotation *annotation) {
r_vector_push (&code->annotations, annotation);
}
R_API RPVector *r_annotated_code_annotations_in(RAnnotatedCode *code, size_t offset) {
RPVector *r = r_pvector_new (NULL);
if (!r) {
return NULL;
}
RCodeAnnotation *annotation;
r_vector_foreach (&code->annotations, annotation) {
if (offset >= annotation->start && offset < annotation->end) {
r_pvector_push (r, annotation);
}
}
return r;
}
R_API RPVector *r_annotated_code_annotations_range(RAnnotatedCode *code, size_t start, size_t end) {
RPVector *r = r_pvector_new (NULL);
if (!r) {
return NULL;
}
RCodeAnnotation *annotation;
r_vector_foreach (&code->annotations, annotation) {
if (start >= annotation->end || end < annotation->start) {
continue;
}
r_pvector_push (r, annotation);
}
return r;
}
R_API RVector *r_annotated_code_line_offsets(RAnnotatedCode *code) {
RVector *r = r_vector_new (sizeof (ut64), NULL, NULL);
if (!r) {
return NULL;
}
size_t cur = 0;
size_t len = strlen (code->code);
do {
char *next = strchr (code->code + cur, '\n');
size_t next_i = next? (next - code->code) + 1: len;
RPVector *annotations = r_annotated_code_annotations_range (code, cur, next_i);
ut64 offset = UT64_MAX;
void **it;
r_pvector_foreach (annotations, it) {
RCodeAnnotation *annotation = *it;
if (annotation->type != R_CODE_ANNOTATION_TYPE_OFFSET) {
continue;
}
offset = annotation->offset.offset;
break;
}
r_vector_push (r, &offset);
cur = next_i;
r_pvector_free (annotations);
} while (cur < len);
return r;
}

View File

@ -81,7 +81,8 @@ r_util_sources = [
'protobuf.c',
'regex/regcomp.c',
'regex/regexec.c',
'regex/regerror.c'
'regex/regerror.c',
'annotated_code.c'
]
r_util_deps = [ldl, mth, pth, utl, sdb_dep, zlib_dep, platform_deps]

View File

@ -9,6 +9,7 @@ if get_option('enable_tests')
'anal_meta',
'anal_var',
'anal_xrefs',
'annotated_code',
'base64',
'bin',
'bitmap',

View File

@ -0,0 +1,343 @@
#include <r_util.h>
#include <r_vector.h>
#include <r_core.h>
#include <r_cons.h>
#include <r_util/r_annotated_code.h>
#include "minunit.h"
static RCodeAnnotation make_code_annotation(int st, int en, RCodeAnnotationType typec,
ut64 offset, RSyntaxHighlightType types) {
RCodeAnnotation annotation = {};
annotation.start = st;
annotation.end = en;
annotation.type = typec;
if (annotation.type == R_CODE_ANNOTATION_TYPE_OFFSET) {
annotation.offset.offset = offset;
}
if (annotation.type == R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT) {
annotation.syntax_highlight.type = types;
}
return annotation;
}
static RVector *get_some_code_annotation_for_add() {
RVector *test_annotations = r_vector_new (sizeof (RCodeAnnotation), NULL, NULL);
RCodeAnnotation annotation;
r_vector_init (test_annotations, sizeof (RCodeAnnotation), NULL, NULL);
annotation = make_code_annotation (1, 2, R_CODE_ANNOTATION_TYPE_OFFSET, 123, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation);
annotation = make_code_annotation (1, 5, R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT, 123, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation);
return test_annotations;
}
static RVector *get_some_annotations_for_in() {
RVector *test_annotations = r_vector_new (sizeof (RCodeAnnotation), NULL, NULL);
RCodeAnnotation annotation;
annotation = make_code_annotation (1, 2, R_CODE_ANNOTATION_TYPE_OFFSET, 123, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation);
annotation = make_code_annotation (1, 7, R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT, 123, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation);
annotation = make_code_annotation (9, 11, R_CODE_ANNOTATION_TYPE_OFFSET, 123, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation);
// For offset = 11, indices expected = 3, 4, 5
annotation = make_code_annotation (7, 13, R_CODE_ANNOTATION_TYPE_OFFSET, 123, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation);
annotation = make_code_annotation (11, 15, R_CODE_ANNOTATION_TYPE_OFFSET, 123, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation);
annotation = make_code_annotation (10, 16, R_CODE_ANNOTATION_TYPE_OFFSET, 123, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation);
annotation = make_code_annotation (17, 20, R_CODE_ANNOTATION_TYPE_OFFSET, 32, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation);
return test_annotations;
}
static RVector *get_annotations_for_hello_world() {
RVector *test_annotations = r_vector_new (sizeof (RCodeAnnotation), NULL, NULL);
RCodeAnnotation annotation;
// r_vector_init (&test_annotations, sizeof (RCodeAnnotation), NULL, NULL);
//Code Annotations for a hello world program
annotation = make_code_annotation (1, 5, R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT, 123, R_SYNTAX_HIGHLIGHT_TYPE_DATATYPE);
r_vector_push (test_annotations, &annotation); //1
annotation = make_code_annotation (6, 10, R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT, 123, R_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME);
r_vector_push (test_annotations, &annotation); //2
annotation = make_code_annotation (11, 15, R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT, 123, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation); //3
annotation = make_code_annotation (23, 35, R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT, 123, R_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME);
r_vector_push (test_annotations, &annotation); //4
annotation = make_code_annotation (36, 51, R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT, 123, R_SYNTAX_HIGHLIGHT_TYPE_CONSTANT_VARIABLE);
r_vector_push (test_annotations, &annotation); //5
annotation = make_code_annotation (23, 52, R_CODE_ANNOTATION_TYPE_OFFSET, 4440, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation); //6
annotation = make_code_annotation (58, 64, R_CODE_ANNOTATION_TYPE_OFFSET, 4447, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation); //7
annotation = make_code_annotation (58, 64, R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT, 123, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation); //8
annotation = make_code_annotation (58, 64, R_CODE_ANNOTATION_TYPE_OFFSET, 4447, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (test_annotations, &annotation); //9
return test_annotations;
}
static RAnnotatedCode *get_hello_world() {
char *test_string = strdup ("\nvoid main(void)\n{\n sym.imp.puts(\"Hello, World!\");\n return;\n}\n");
RAnnotatedCode *code = r_annotated_code_new (test_string);
RVector /*<RCodeAnnotation>*/ *test_annotations;
test_annotations = get_annotations_for_hello_world ();
RCodeAnnotation *annotation;
r_vector_foreach (test_annotations, annotation) {
r_annotated_code_add_annotation (code, annotation);
}
r_vector_free (test_annotations);
return code;
}
static bool test_r_annotated_code_new() {
//Testing RAnnoatedCode->code
char *test_string = strdup ("How are you?");
RAnnotatedCode *code = r_annotated_code_new (test_string);
mu_assert_streq (code->code, test_string, "Code in RAnnotatedCode is not set as expected");
// Testing RAnnoatedCode->annotations
mu_assert_eq (code->annotations.elem_size, sizeof (RCodeAnnotation), "Code Annotations are initialized is not properly");
r_annotated_code_free (code);
mu_end;
}
static bool test_r_annotated_code_free() {
char *test_string = strdup ("How are you?");
RAnnotatedCode *code = r_annotated_code_new (test_string);
RCodeAnnotation test_annotation1, test_annotation2;
test_annotation1 = make_code_annotation (1, 2, R_CODE_ANNOTATION_TYPE_OFFSET, 123, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (&code->annotations, &test_annotation1);
test_annotation2 = make_code_annotation (1, 5, R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT, 123, R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD);
r_vector_push (&code->annotations, &test_annotation2);
// This test is only for run errors
r_annotated_code_free (code);
mu_end;
}
static bool test_equal(RCodeAnnotation *first, RCodeAnnotation *second) { // First - Got, Second - Expected
mu_assert_eq (first->start, second->start, "start of annotations doesn't match");
mu_assert_eq (first->end, second->end, "end of annotations doesn't match");
mu_assert_eq (first->type, second->type, "type of annotation doesn't match");
if (first->type == R_CODE_ANNOTATION_TYPE_OFFSET) {
mu_assert_eq (first->offset.offset, second->offset.offset, "offset of annotations doesn't match");
return true;
}
if (first->type == R_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT) {
mu_assert_eq (first->syntax_highlight.type, second->syntax_highlight.type, "syntax highlight type of offset doesn't match");
return true;
}
return false;
}
static bool test_r_annotated_code_add_annotation() {
char *test_string = strdup ("abcdefghijklmnopqrtstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ");
RAnnotatedCode *code = r_annotated_code_new (test_string);
RVector /*<RCodeAnnotation>*/ *test_annotations;
test_annotations = get_some_code_annotation_for_add ();
RCodeAnnotation *annotation;
r_vector_foreach (test_annotations, annotation) {
r_annotated_code_add_annotation (code, annotation);
}
//Comparing
if (!test_equal (r_vector_index_ptr (&code->annotations, 0), r_vector_index_ptr (test_annotations, 0))) {
return false;
}
if (!test_equal (r_vector_index_ptr (&code->annotations, 1), r_vector_index_ptr (test_annotations, 1))) {
return false;
}
r_vector_free (test_annotations);
r_annotated_code_free (code);
mu_end;
}
static bool test_r_annotated_code_annotations_in() {
char *test_string = strdup ("abcdefghijklmnopqrtstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ");
RAnnotatedCode *code = r_annotated_code_new (test_string);
RVector /*<RCodeAnnotation>*/ *test_annotations;
test_annotations = get_some_annotations_for_in ();
RCodeAnnotation *annotation;
r_vector_foreach (test_annotations, annotation) {
r_annotated_code_add_annotation (code, annotation);
}
RPVector *out = r_annotated_code_annotations_in (code, 11);
//Expecting indices = 3, 4, 5
mu_assert_eq (out->v.len, 3, "Additional annotations found. Bad output.");
if (!test_equal (*r_pvector_index_ptr (out, 0), r_vector_index_ptr (test_annotations, 3))) {
return false;
}
if (!test_equal (*r_pvector_index_ptr (out, 1), r_vector_index_ptr (test_annotations, 4))) {
return false;
}
if (!test_equal (*r_pvector_index_ptr (out, 2), r_vector_index_ptr (test_annotations, 5))) {
return false;
}
r_vector_free (test_annotations);
r_pvector_free (out);
r_annotated_code_free (code);
mu_end;
}
static bool test_r_annotated_code_annotations_range() {
char *test_string = strdup ("abcdefghijklmnopqrtstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ");
RAnnotatedCode *code = r_annotated_code_new (test_string);
RVector /*<RCodeAnnotation>*/ *test_annotations;
test_annotations = get_some_annotations_for_in ();
RCodeAnnotation *annotation;
r_vector_foreach (test_annotations, annotation) {
r_annotated_code_add_annotation (code, annotation);
}
RPVector *out = r_annotated_code_annotations_range (code, 7, 16);
// Expecting indices = 2, 3, 4, 5
mu_assert_eq (out->v.len, 4, "Additional annotations found. Bad output.");
if (!test_equal (*r_pvector_index_ptr (out, 0), r_vector_index_ptr (test_annotations, 2))) {
return false;
}
if (!test_equal (*r_pvector_index_ptr (out, 1), r_vector_index_ptr (test_annotations, 3))) {
return false;
}
if (!test_equal (*r_pvector_index_ptr (out, 2), r_vector_index_ptr (test_annotations, 4))) {
return false;
}
if (!test_equal (*r_pvector_index_ptr (out, 3), r_vector_index_ptr (test_annotations, 5))) {
return false;
}
r_vector_free (test_annotations);
r_pvector_free (out);
r_annotated_code_free (code);
mu_end;
}
static bool test_r_annotated_code_line_offsets() {
RAnnotatedCode *code = get_hello_world ();
RVector *offsets = r_annotated_code_line_offsets (code);
mu_assert_eq (offsets->len, 6, "Number of offsets not expected");
ut64 *off = r_vector_index_ptr (offsets, 0);
mu_assert_eq_fmt (*off, UT64_MAX, "Unexpected offset", "%llu");
off = r_vector_index_ptr (offsets, 1);
mu_assert_eq_fmt (*off, UT64_MAX, "Unexpected offset", "%llu");
off = r_vector_index_ptr (offsets, 2);
mu_assert_eq_fmt (*off, UT64_MAX, "Unexpected offset", "%llu");
off = r_vector_index_ptr (offsets, 3);
mu_assert_eq_fmt (*off, (ut64)4440, "Unexpected offset", "%llu");
off = r_vector_index_ptr (offsets, 4);
mu_assert_eq_fmt (*off, (ut64)4447, "Unexpected offset", "%llu");
off = r_vector_index_ptr (offsets, 5);
mu_assert_eq_fmt (*off, UT64_MAX, "Unexpected offset", "%llu");
r_vector_free (offsets);
r_annotated_code_free (code);
mu_end;
}
static bool test_r_core_annotated_code_print_json() {
RAnnotatedCode *code = get_hello_world ();
char *actual;
char *expected = "{\"code\":\"\\nvoid main(void)\\n{\\n sym.imp.puts(\\\"Hello, World!\\\");\\n return;\\n}\\n\",\"annotations\":[{\"start\":1,\"end\":5,\"type\":\"syntax_highlight\",\"syntax_highlight\":\"datatype\"},{\"start\":6,\"end\":10,\"type\":\"syntax_highlight\",\"syntax_highlight\":\"function_name\"},{\"start\":11,\"end\":15,\"type\":\"syntax_highlight\",\"syntax_highlight\":\"keyword\"},{\"start\":23,\"end\":35,\"type\":\"syntax_highlight\",\"syntax_highlight\":\"function_name\"},{\"start\":36,\"end\":51,\"type\":\"syntax_highlight\",\"syntax_highlight\":\"constant_variable\"},{\"start\":23,\"end\":52,\"type\":\"offset\",\"offset\":4440},{\"start\":58,\"end\":64,\"type\":\"offset\",\"offset\":4447},{\"start\":58,\"end\":64,\"type\":\"syntax_highlight\",\"syntax_highlight\":\"keyword\"},{\"start\":58,\"end\":64,\"type\":\"offset\",\"offset\":4447}]}\n";
r_cons_new ();
r_cons_push ();
r_core_annotated_code_print_json (code);
actual = strdup (r_cons_get_buffer ());
r_cons_pop ();
mu_assert_streq (actual, expected, "pdgj OUTPUT DOES NOT MATCH");
r_cons_free ();
free (actual);
r_annotated_code_free (code);
mu_end;
}
static bool test_r_core_annotated_code_print() {
RAnnotatedCode *code = get_hello_world ();
char *actual;
//Checking without line offset
char *expected_first = "\n"
"void main(void)\n"
"{\n"
" sym.imp.puts(\"Hello, World!\");\n"
" return;\n"
"}\n";
r_cons_new ();
r_cons_push ();
r_core_annotated_code_print (code, NULL);
actual = strdup (r_cons_get_buffer ());
r_cons_pop ();
mu_assert_streq (actual, expected_first, "pdg OUTPUT DOES NOT MATCH");
r_cons_pop ();
//Checking with offset - pdgo
RVector *offsets = r_annotated_code_line_offsets (code);
char *expected_second = " |\n"
" |void main(void)\n"
" |{\n"
" 0x00001158 | sym.imp.puts(\"Hello, World!\");\n"
" 0x0000115f | return;\n"
" |}\n";
r_core_annotated_code_print (code, offsets);
free (actual);
actual = strdup (r_cons_get_buffer ());
r_cons_pop ();
mu_assert_streq (actual, expected_second, "pdgo OUTPUT DOES NOT MATCH");
r_cons_pop ();
r_cons_free ();
free (actual);
r_vector_free (offsets);
r_annotated_code_free (code);
mu_end;
}
static bool test_r_core_annotated_code_print_comment_cmds() {
RAnnotatedCode *code = get_hello_world ();
char *actual;
char *expected = "CCu base64:c3ltLmltcC5wdXRzKCJIZWxsbywgV29ybGQhIik= @ 0x1158\n"
"CCu base64:cmV0dXJu @ 0x115f\n";
r_cons_new ();
r_cons_push ();
r_core_annotated_code_print_comment_cmds (code);
actual = strdup (r_cons_get_buffer ());
r_cons_pop ();
mu_assert_streq (actual, expected, "pdg* OUTPUT DOES NOT MATCH");
r_cons_free ();
free (actual);
r_annotated_code_free (code);
mu_end;
}
static int all_tests() {
mu_run_test (test_r_annotated_code_new);
mu_run_test (test_r_annotated_code_free);
mu_run_test (test_r_annotated_code_add_annotation);
mu_run_test (test_r_annotated_code_annotations_in);
mu_run_test (test_r_annotated_code_annotations_range);
mu_run_test (test_r_annotated_code_line_offsets);
mu_run_test (test_r_core_annotated_code_print_json);
mu_run_test (test_r_core_annotated_code_print);
mu_run_test (test_r_core_annotated_code_print_comment_cmds);
return tests_passed != tests_run;
}
int main (int argc, char **argv) {
return all_tests ();
}