#include "xed-dot-prep.h"
#include <string.h>
#include <assert.h>
#include <stdlib.h>
xed_dot_graph_supp_t* xed_dot_graph_supp_create(
xed_syntax_enum_t arg_syntax)
{
xed_dot_graph_supp_t* gs = 0;
gs = (xed_dot_graph_supp_t*)malloc(sizeof(xed_dot_graph_supp_t));
assert( gs != 0 );
gs->g = xed_dot_graph();
gs->syntax = arg_syntax;
memset(gs->xed_reg_to_node,
0,
sizeof(xed_dot_node_t*)*XED_REG_LAST);
gs->start = xed_dot_node(gs->g, "start");
return gs;
}
void xed_dot_graph_supp_deallocate(xed_dot_graph_supp_t* gg)
{
if (!gg)
return;
xed_dot_graph_deallocate(gg->g);
}
static xed_bool_t add_edge(xed_dot_graph_supp_t* gg,
xed_dot_node_t* n,
xed_reg_enum_t r,
xed_dot_edge_style_t s)
{
xed_reg_enum_t r_enclosing;
xed_bool_t found = 0;
xed_dot_node_t* src = 0;
r_enclosing = xed_get_largest_enclosing_register(r);
src = gg->xed_reg_to_node[r_enclosing];
if (src) {
xed_dot_edge(gg->g,src,n,s);
found = 1;
}
return found;
}
static void add_read_operands(xed_dot_graph_supp_t* gg,
xed_decoded_inst_t* xedd,
xed_dot_node_t* n)
{
xed_uint_t i, noperands;
xed_reg_enum_t r;
const xed_inst_t* xi = 0;
xed_bool_t found = 0;
xi = xed_decoded_inst_inst(xedd);
noperands = xed_inst_noperands(xi);
for( i=0; i < noperands ; i++) {
const unsigned int no_memop = 99;
unsigned int memop = no_memop;
const xed_operand_t* op = xed_inst_operand(xi,i);
xed_operand_enum_t opname = xed_operand_name(op);
if (xed_operand_is_register(opname) ||
xed_operand_is_memory_addressing_register(opname)) {
if (xed_operand_read(op)) {
r = xed_decoded_inst_get_reg(xedd, opname);
found |= add_edge(gg, n, r, XED_DOT_EDGE_SOLID);
}
continue;
}
if (opname == XED_OPERAND_MEM0)
memop = 0;
else if (opname == XED_OPERAND_MEM1 )
memop = 1;
if (memop != no_memop) {
xed_reg_enum_t base, indx;
base = xed_decoded_inst_get_base_reg(xedd,memop);
indx = xed_decoded_inst_get_index_reg(xedd,memop);
if (base != XED_REG_INVALID)
found |= add_edge(gg, n, base, XED_DOT_EDGE_SOLID);
indx = xed_decoded_inst_get_index_reg(xedd,memop);
if (indx != XED_REG_INVALID)
found |= add_edge(gg, n, indx, XED_DOT_EDGE_SOLID);
}
}
if (!found) {
xed_dot_edge(gg->g, gg->start, n, XED_DOT_EDGE_SOLID);
}
}
static void add_write_operands(xed_dot_graph_supp_t* gg,
xed_decoded_inst_t* xedd,
xed_dot_node_t* n)
{
xed_uint_t i, noperands;
xed_reg_enum_t r, r_enclosing;
const xed_inst_t* xi = 0;
xi = xed_decoded_inst_inst(xedd);
noperands = xed_inst_noperands(xi);
for( i=0; i < noperands ; i++) {
const xed_operand_t* op = xed_inst_operand(xi,i);
xed_operand_enum_t opname = xed_operand_name(op);
if (xed_operand_is_register(opname) ||
xed_operand_is_memory_addressing_register(opname)) {
if (xed_operand_written(op)) {
r = xed_decoded_inst_get_reg(xedd, opname);
(void) add_edge(gg,n,r,XED_DOT_EDGE_DASHED);
r_enclosing = xed_get_largest_enclosing_register(r);
gg->xed_reg_to_node[r_enclosing] = n;
}
}
}
}
#define XED_DOT_TMP_BUF_LEN (1024U)
void xed_dot_graph_add_instruction(
xed_dot_graph_supp_t* gg,
xed_decoded_inst_t* xedd,
xed_uint64_t runtime_instr_addr,
void* caller_data,
xed_disassembly_callback_fn_t disas_symbol_cb)
{
char disasm_str[XED_DOT_TMP_BUF_LEN];
char* p = 0;
size_t alen = 0;
int ok;
xed_bool_t ok2;
xed_dot_node_t* n = 0;
xed_uint32_t remaining_buffer_bytes = XED_DOT_TMP_BUF_LEN;
#if defined(XED_WINDOWS) && !defined(PIN_CRT)
ok = sprintf_s(disasm_str,
XED_DOT_TMP_BUF_LEN,
XED_FMT_LX "\\n",
runtime_instr_addr);
#else
ok = sprintf(disasm_str,
XED_FMT_LX "\\n",
runtime_instr_addr);
#endif
assert(ok > 0);
alen = strlen(disasm_str);
p = disasm_str + alen;
remaining_buffer_bytes -= XED_CAST(xed_uint32_t, alen);
ok2 = xed_format_context(gg->syntax,
xedd,
p,
(int)remaining_buffer_bytes,
runtime_instr_addr,
caller_data,
disas_symbol_cb);
if (!ok2) {
(void)xed_strncpy(disasm_str,"???", XED_DOT_TMP_BUF_LEN);
}
n = xed_dot_node(gg->g, disasm_str);
add_read_operands(gg,xedd,n);
add_write_operands(gg,xedd,n);
}
void xed_dot_graph_dump(
FILE* f,
xed_dot_graph_supp_t* gg)
{
xed_dot_dump(f, gg->g);
}