#include <hexrays.hpp>
#include <gdl.hpp>
hexdsp_t *hexdsp = NULL;
static bool inited = false;
static const char hotkey[] = "G";
static ushort hotcode;
#define CL_WHITE ((255)+ (255<<8)+ (255<<16)) // 0
#define CL_BLUE ((0 )+ (0 <<8)+ (255<<16)) // 1
#define CL_RED ((255)+ (0 <<8)+ (0 <<16)) // 2
#define CL_GREEN ((0 )+ (255<<8)+ (0 <<16)) // 3
#define CL_YELLOW ((255)+ (255<<8)+ (0 <<16)) // 4
#define CL_MAGENTA ((255)+ (0 <<8)+ (255<<16)) // 5
#define CL_CYAN ((0 )+ (255<<8)+ (255<<16)) // 6
#define CL_DARKGREY ((85 )+ (85 <<8)+ (85 <<16)) // 7
#define CL_DARKBLUE ((0 )+ (0 <<8)+ (128<<16)) // 8
#define CL_DARKRED ((128)+ (0 <<8)+ (0 <<16)) // 9
#define CL_DARKGREEN ((0 )+ (128<<8)+ (0 <<16)) // 10
#define CL_DARKYELLOW ((128)+ (128<<8)+ (0 <<16)) // 11
#define CL_DARKMAGENTA ((128)+ (0 <<8)+ (128<<16)) // 12
#define CL_DARKCYAN ((0 )+ (128<<8)+ (128<<16)) // 13
#define CL_GOLD ((255)+ (215<<8)+ (0 <<16)) // 14
#define CL_LIGHTGREY ((170)+ (170<<8)+ (170<<16)) // 15
#define CL_LIGHTBLUE ((128)+ (128<<8)+ (255<<16)) // 16
#define CL_LIGHTRED ((255)+ (128<<8)+ (128<<16)) // 17
#define CL_LIGHTGREEN ((128)+ (255<<8)+ (128<<16)) // 18
#define CL_LIGHTYELLOW ((255)+ (255<<8)+ (128<<16)) // 19
#define CL_LIGHTMAGENTA ((255)+ (128<<8)+ (255<<16)) // 20
#define CL_LIGHTCYAN ((128)+ (255<<8)+ (255<<16)) // 21
#define CL_LILAC ((238)+ (130<<8)+ (238<<16)) // 22
#define CL_TURQUOISE ((64 )+ (224<<8)+ (208<<16)) // 23
#define CL_AQUAMARINE ((127)+ (255<<8)+ (212<<16)) // 24
#define CL_KHAKI ((240)+ (230<<8)+ (140<<16)) // 25
#define CL_PURPLE ((160)+ (32 <<8)+ (240<<16)) // 26
#define CL_YELLOWGREEN ((154)+ (205<<8)+ (50 <<16)) // 27
#define CL_PINK ((255)+ (192<<8)+ (203<<16)) // 28
#define CL_ORANGE ((255)+ (165<<8)+ (0 <<16)) // 29
#define CL_ORCHID ((218)+ (112<<8)+ (214<<16)) // 30
#define CL_BLACK ((0 )+ (0 <<8)+ (0 <<16)) // 31
static const char *get_color_name(bgcolor_t c)
{
switch ( c )
{
case CL_WHITE : return "white";
case CL_BLUE : return "blue";
case CL_RED : return "red";
case CL_GREEN : return "green";
case CL_YELLOW : return "yellow";
case CL_MAGENTA : return "magenta";
case CL_CYAN : return "cyan";
case CL_DARKGREY : return "darkgrey";
case CL_DARKBLUE : return "darkblue";
case CL_DARKRED : return "darkred";
case CL_DARKGREEN : return "darkgreen";
case CL_DARKYELLOW : return "darkyellow";
case CL_DARKMAGENTA : return "darkmagenta";
case CL_DARKCYAN : return "darkcyan";
case CL_GOLD : return "gold";
case CL_LIGHTGREY : return "lightgrey";
case CL_LIGHTBLUE : return "lightblue";
case CL_LIGHTRED : return "lightred";
case CL_LIGHTGREEN : return "lightgreen";
case CL_LIGHTYELLOW : return "lightyellow";
case CL_LIGHTMAGENTA: return "lightmagenta";
case CL_LIGHTCYAN : return "lightcyan";
case CL_LILAC : return "lilac";
case CL_TURQUOISE : return "turquoise";
case CL_AQUAMARINE : return "aquamarine";
case CL_KHAKI : return "khaki";
case CL_PURPLE : return "purple";
case CL_YELLOWGREEN : return "yellowgreen";
case CL_PINK : return "pink";
case CL_ORANGE : return "orange";
case CL_ORCHID : return "orchid";
case CL_BLACK : return "black";
}
return "?";
}
class cfunc_graph_t : public gdl_graph_t
{
typedef qvector<const citem_t *> itemrefs_t;
itemrefs_t items;
const citem_t *highlight;
friend struct graph_builder_t;
array_of_intseq_t succs;
array_of_intseq_t preds;
int idaapi nsucc(int b) const { return size() ? succs[b].size() : 0; }
int idaapi npred(int b) const { return size() ? preds[b].size() : 0; }
int idaapi succ(int b, int i) const { return succs[b][i]; }
int idaapi pred(int b, int i) const { return preds[b][i]; }
public:
cfunc_graph_t(const citem_t *_highlight) : highlight(_highlight) {}
int idaapi size(void) const { return preds.size(); }
int add_node(void)
{
int n = size();
preds.resize(n+1);
succs.resize(n+1);
return n;
}
void add_edge(int x, int y)
{
preds[y].push_back(x);
succs[x].push_back(y);
}
char *idaapi get_node_label(int n, char *buf, int bufsize) const
{
char *ptr = buf;
char *end = buf + bufsize;
const citem_t *item = items[n];
APPEND(ptr, end, get_ctype_name(item->op));
const cexpr_t *e = (const cexpr_t *)item;
const cinsn_t *i = (const cinsn_t *)item;
switch ( item->op )
{
case cot_ptr :
case cot_memptr :
ptr += qsnprintf(ptr, end-ptr, ".%d", e->ptrsize);
if ( item->op == cot_ptr )
break;
case cot_memref :
ptr += qsnprintf(ptr, end-ptr, " (m=%d)", e->m);
break;
case cot_obj :
case cot_var :
ptr += qsnprintf(ptr, end-ptr, ".%d", e->refwidth);
case cot_num :
case cot_helper :
case cot_str :
APPCHAR(ptr, end, ' ');
e->print1(ptr, end-ptr, NULL);
tag_remove(ptr, ptr, 0);
ptr = tail(ptr);
break;
case cit_goto:
ptr += qsnprintf(ptr, end-ptr, " LABEL_%d", i->cgoto->label_num);
break;
case cit_asm:
ptr += qsnprintf(ptr, end-ptr, " %a.%d", *i->casm->begin(), i->casm->size());
break;
}
ptr += qsnprintf(ptr, end-ptr, "\nea: %a", item->ea);
if ( item->is_expr() && !e->type.empty() )
{
APPCHAR(ptr, end, '\n');
if ( print_type_to_one_line(ptr, end-ptr, idati, e->type.u_str()) != T_NORMAL )
{
APPCHAR(ptr, end, '?');
APPZERO(ptr, end);
}
}
return buf;
}
bool idaapi print_edge(FILE *fp, int i, int j) const
{
qfprintf(fp, "edge: { sourcename: \"%d\" targetname: \"%d\" ", i, j);
char *label = NULL;
const citem_t *a = items[i];
const citem_t *b = items[j];
if ( a->is_expr() )
{
cexpr_t *e = (cexpr_t *)a;
if ( e->x == b ) label = "x";
if ( e->y == b ) label = "y";
if ( e->z == b ) label = "z";
}
if ( label != NULL )
qfprintf(fp, "label: \"%s\" ", label);
qfprintf(fp, "}\n");
return true;
}
bgcolor_t idaapi get_node_color(int n) const
{
const citem_t *item = items[n];
if ( item == highlight )
return CL_GREEN;
if ( item->is_expr() )
{
char buf[MAXSTR];
const cexpr_t *e = (const cexpr_t *)item;
if ( print_type_to_one_line(buf, sizeof(buf), idati, e->type.u_str()) != T_NORMAL )
return CL_YELLOWGREEN;
}
return DEFCOLOR;
}
void idaapi print_node_attributes(FILE *fp, int n) const
{
bgcolor_t c = get_node_color(n);
if ( c != DEFCOLOR )
qfprintf(fp, " color: %s", get_color_name(c));
}
};
struct graph_builder_t : public ctree_parentee_t
{
cfunc_graph_t &cg;
std::map<citem_t *, int> reverse;
graph_builder_t(cfunc_graph_t &_cg) : cg(_cg) {}
int add_node(citem_t *i);
int process(citem_t *i);
int idaapi visit_insn(cinsn_t *i) { return process(i); }
int idaapi visit_expr(cexpr_t *e) { return process(e); }
};
int graph_builder_t::add_node(citem_t *i)
{
if ( reverse.find(i) != reverse.end() )
{
warning("bad ctree - duplicate nodes!");
return -1;
}
int n = cg.add_node();
if ( n <= cg.items.size() )
cg.items.push_back(i);
cg.items[n] = i;
reverse[i] = n;
return n;
}
int graph_builder_t::process(citem_t *item)
{
int n = add_node(item);
if ( n == -1 )
return -1;
if ( parents.size() > 1 )
{
int p = reverse[parents.back()];
cg.add_edge(p, n);
}
return 0;
}
static bool idaapi display_graph(void *ud)
{
vdui_t &vu = *(vdui_t *)ud;
vu.get_current_item(USE_KEYBOARD);
citem_t *highlight = vu.item.is_citem() ? vu.item.e : NULL;
cfunc_graph_t cg(highlight);
graph_builder_t gb(cg);
gb.apply_to(&vu.cfunc->body, NULL);
char fname[QMAXPATH];
qtmpnam(fname, sizeof(fname));
gen_gdl(&cg, fname);
display_gdl(fname);
return true;
}
static int idaapi callback(void *, hexrays_event_t event, va_list va)
{
switch ( event )
{
case hxe_right_click:
{
vdui_t &vu = *va_arg(va, vdui_t *);
add_custom_viewer_popup_item(vu.ct, "Display graph", hotkey, display_graph, &vu);
}
break;
case hxe_keyboard:
{
vdui_t &vu = *va_arg(va, vdui_t *);
int keycode = va_arg(va, int);
int shift = va_arg(va, int);
if ( keycode == hotcode && shift == 0 )
return display_graph(&vu);
}
break;
}
return 0;
}
int idaapi init(void)
{
if ( !init_hexrays_plugin() )
return PLUGIN_SKIP;
install_hexrays_callback(callback, NULL);
const char *hxver = get_hexrays_version();
msg("Hex-rays version %s has been detected, %s ready to use\n", hxver, PLUGIN.wanted_name);
inited = true;
hotcode = get_key_code(hotkey);
return PLUGIN_KEEP;
}
void idaapi term(void)
{
if ( inited )
{
remove_hexrays_callback(callback, NULL);
term_hexrays_plugin();
}
}
void idaapi run(int)
{
}
static char comment[] = "Sample plugin5 for Hex-Rays decompiler";
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_HIDE,
init,
term,
run,
comment,
"",
"Hex-Rays show C graph",
""
};