From fa83e96082b45a6dda3d46338070d25e6eb47459 Mon Sep 17 00:00:00 2001 From: vardyh Date: Sat, 21 Sep 2013 19:18:35 +0800 Subject: [PATCH] libudis86: introduce asmvprintf hook Introduce asmvprintf hook to implement custom assembly code printing procedure with the help of udis86 builtin syntax formatting machanism. For syn-intel/att.c code, a syntax element type (enum ud_syn_class) is passed as the second argument on each calls to asmprintf(). An example of colorized assembly code output is implemented in udcli.c Signed-off-by: vardyh --- libudis86/extern.h | 10 ++++- libudis86/syn-att.c | 100 ++++++++++++++++++++++-------------------- libudis86/syn-intel.c | 86 +++++++++++++++++++----------------- libudis86/syn.c | 24 +++++----- libudis86/syn.h | 20 ++++++--- libudis86/types.h | 21 +++++++++ libudis86/udis86.c | 21 +++++++++ udcli/udcli.c | 79 +++++++++++++++++++++++++++++++-- 8 files changed, 250 insertions(+), 111 deletions(-) diff --git a/libudis86/extern.h b/libudis86/extern.h index ae9f82f..075bb73 100644 --- a/libudis86/extern.h +++ b/libudis86/extern.h @@ -92,11 +92,17 @@ extern uint64_t ud_insn_sext_imm(const struct ud*, const struct ud_operand*); extern void ud_set_asm_buffer(struct ud *u, char *buf, size_t size); -extern void ud_set_sym_resolver(struct ud *u, - const char* (*resolver)(struct ud*, +extern void ud_set_sym_resolver(struct ud *u, + const char* (*resolver)(struct ud*, uint64_t addr, int64_t *offset)); +extern void ud_set_asmvprintf_hook(struct ud *u, + int (*asmvprintf_hook)(struct ud*, + enum ud_syn_class, + const char *, + va_list)); + /* ========================================================================== */ #ifdef __cplusplus diff --git a/libudis86/syn-att.c b/libudis86/syn-att.c index cc59838..31b729e 100644 --- a/libudis86/syn-att.c +++ b/libudis86/syn-att.c @@ -34,12 +34,12 @@ * opr_cast() - Prints an operand cast. * ----------------------------------------------------------------------------- */ -static void +static void opr_cast(struct ud* u, struct ud_operand* op) { switch(op->size) { case 16 : case 32 : - ud_asmprintf(u, "*"); break; + ud_asmprintf(u, UD_operator, "*"); break; default: break; } } @@ -48,16 +48,16 @@ opr_cast(struct ud* u, struct ud_operand* op) * gen_operand() - Generates assembly output for each operand. * ----------------------------------------------------------------------------- */ -static void +static void gen_operand(struct ud* u, struct ud_operand* op) { switch(op->type) { case UD_OP_CONST: - ud_asmprintf(u, "$0x%x", op->lval.udword); + ud_asmprintf(u, UD_immediate, "$0x%x", op->lval.udword); break; case UD_OP_REG: - ud_asmprintf(u, "%%%s", ud_reg_tab[op->base - UD_R_AL]); + ud_asmprintf(u, UD_register, "%%%s", ud_reg_tab[op->base - UD_R_AL]); break; case UD_OP_MEM: @@ -65,32 +65,35 @@ gen_operand(struct ud* u, struct ud_operand* op) opr_cast(u, op); } if (u->pfx_seg) { - ud_asmprintf(u, "%%%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]); + ud_asmprintf(u, UD_prefix, "%%%s", ud_reg_tab[u->pfx_seg - UD_R_AL]); + ud_asmprintf(u, UD_operator, ":"); } - if (op->offset != 0) { + if (op->offset != 0) { ud_syn_print_mem_disp(u, op, 0); } if (op->base) { - ud_asmprintf(u, "(%%%s", ud_reg_tab[op->base - UD_R_AL]); + ud_asmprintf(u, UD_operator, "("); + ud_asmprintf(u, UD_register, "%%%s", ud_reg_tab[op->base - UD_R_AL]); } if (op->index) { if (op->base) { - ud_asmprintf(u, ","); + ud_asmprintf(u, UD_operator, ","); } else { - ud_asmprintf(u, "("); + ud_asmprintf(u, UD_operator, "("); } - ud_asmprintf(u, "%%%s", ud_reg_tab[op->index - UD_R_AL]); + ud_asmprintf(u, UD_register, "%%%s", ud_reg_tab[op->index - UD_R_AL]); } if (op->scale) { - ud_asmprintf(u, ",%d", op->scale); + ud_asmprintf(u, UD_operator, ","); + ud_asmprintf(u, UD_immediate, "%d", op->scale); } if (op->base || op->index) { - ud_asmprintf(u, ")"); + ud_asmprintf(u, UD_operator, ")"); } break; case UD_OP_IMM: - ud_asmprintf(u, "$"); + ud_asmprintf(u, UD_immediate, "$"); ud_syn_print_imm(u, op); break; @@ -101,25 +104,27 @@ gen_operand(struct ud* u, struct ud_operand* op) case UD_OP_PTR: switch (op->size) { case 32: - ud_asmprintf(u, "$0x%x, $0x%x", op->lval.ptr.seg, - op->lval.ptr.off & 0xFFFF); + ud_asmprintf(u, UD_address, "$0x%x", op->lval.ptr.seg); + ud_asmprintf(u, UD_operator, ", "); + ud_asmprintf(u, UD_address, "$0x%x", op->lval.ptr.off & 0xFFFF); break; case 48: - ud_asmprintf(u, "$0x%x, $0x%x", op->lval.ptr.seg, - op->lval.ptr.off); + ud_asmprintf(u, UD_address, "$0x%x", op->lval.ptr.seg); + ud_asmprintf(u, UD_operator, ", "); + ud_asmprintf(u, UD_address, "$0x%x", op->lval.ptr.off); break; } break; - + default: return; } } /* ============================================================================= - * translates to AT&T syntax + * translates to AT&T syntax * ============================================================================= */ -extern void +extern void ud_translate_att(struct ud *u) { int size = 0; @@ -128,12 +133,12 @@ ud_translate_att(struct ud *u) /* check if P_OSO prefix is used */ if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) { switch (u->dis_mode) { - case 16: - ud_asmprintf(u, "o32 "); + case 16: + ud_asmprintf(u, UD_prefix, "o32 "); break; case 32: case 64: - ud_asmprintf(u, "o16 "); + ud_asmprintf(u, UD_prefix, "o16 "); break; } } @@ -141,82 +146,83 @@ ud_translate_att(struct ud *u) /* check if P_ASO prefix was used */ if (! P_ASO(u->itab_entry->prefix) && u->pfx_adr) { switch (u->dis_mode) { - case 16: - ud_asmprintf(u, "a32 "); + case 16: + ud_asmprintf(u, UD_prefix, "a32 "); break; case 32: - ud_asmprintf(u, "a16 "); + ud_asmprintf(u, UD_prefix, "a16 "); break; case 64: - ud_asmprintf(u, "a32 "); + ud_asmprintf(u, UD_prefix, "a32 "); break; } } if (u->pfx_lock) - ud_asmprintf(u, "lock "); + ud_asmprintf(u, UD_prefix, "lock "); if (u->pfx_rep) { - ud_asmprintf(u, "rep "); + ud_asmprintf(u, UD_prefix, "rep "); } else if (u->pfx_rep) { - ud_asmprintf(u, "repe "); + ud_asmprintf(u, UD_prefix, "repe "); } else if (u->pfx_repne) { - ud_asmprintf(u, "repne "); + ud_asmprintf(u, UD_prefix, "repne "); } /* special instructions */ switch (u->mnemonic) { - case UD_Iretf: - ud_asmprintf(u, "lret "); + case UD_Iretf: + ud_asmprintf(u, UD_opcode, "lret "); break; case UD_Idb: - ud_asmprintf(u, ".byte 0x%x", u->operand[0].lval.ubyte); + ud_asmprintf(u, UD_opcode, ".byte "); + ud_asmprintf(u, UD_immediate, "0x%x", u->operand[0].lval.ubyte); return; case UD_Ijmp: case UD_Icall: - if (u->br_far) ud_asmprintf(u, "l"); + if (u->br_far) ud_asmprintf(u, UD_opsize, "l"); if (u->operand[0].type == UD_OP_REG) { star = 1; } - ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic)); + ud_asmprintf(u, UD_opcode, "%s", ud_lookup_mnemonic(u->mnemonic)); break; case UD_Ibound: case UD_Ienter: if (u->operand[0].type != UD_NONE) gen_operand(u, &u->operand[0]); if (u->operand[1].type != UD_NONE) { - ud_asmprintf(u, ","); + ud_asmprintf(u, UD_operator, ","); gen_operand(u, &u->operand[1]); } return; default: - ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic)); + ud_asmprintf(u, UD_opcode, "%s", ud_lookup_mnemonic(u->mnemonic)); } if (size == 8) { - ud_asmprintf(u, "b"); + ud_asmprintf(u, UD_opsize, "b"); } else if (size == 16) { - ud_asmprintf(u, "w"); + ud_asmprintf(u, UD_opsize, "w"); } else if (size == 64) { - ud_asmprintf(u, "q"); + ud_asmprintf(u, UD_opsize, "q"); } if (star) { - ud_asmprintf(u, " *"); + ud_asmprintf(u, UD_operator, " *"); } else { - ud_asmprintf(u, " "); + ud_asmprintf(u, UD_operator, " "); } if (u->operand[3].type != UD_NONE) { gen_operand(u, &u->operand[3]); - ud_asmprintf(u, ", "); + ud_asmprintf(u, UD_operator, ", "); } if (u->operand[2].type != UD_NONE) { gen_operand(u, &u->operand[2]); - ud_asmprintf(u, ", "); + ud_asmprintf(u, UD_operator, ", "); } if (u->operand[1].type != UD_NONE) { gen_operand(u, &u->operand[1]); - ud_asmprintf(u, ", "); + ud_asmprintf(u, UD_operator, ", "); } if (u->operand[0].type != UD_NONE) { gen_operand(u, &u->operand[0]); diff --git a/libudis86/syn-intel.c b/libudis86/syn-intel.c index 0664fea..a02616b 100644 --- a/libudis86/syn-intel.c +++ b/libudis86/syn-intel.c @@ -34,20 +34,20 @@ * opr_cast() - Prints an operand cast. * ----------------------------------------------------------------------------- */ -static void +static void opr_cast(struct ud* u, struct ud_operand* op) { if (u->br_far) { - ud_asmprintf(u, "far "); + ud_asmprintf(u, UD_opsize, "far "); } switch(op->size) { - case 8: ud_asmprintf(u, "byte " ); break; - case 16: ud_asmprintf(u, "word " ); break; - case 32: ud_asmprintf(u, "dword "); break; - case 64: ud_asmprintf(u, "qword "); break; - case 80: ud_asmprintf(u, "tword "); break; - case 128: ud_asmprintf(u, "oword "); break; - case 256: ud_asmprintf(u, "yword "); break; + case 8: ud_asmprintf(u, UD_opsize, "byte " ); break; + case 16: ud_asmprintf(u, UD_opsize, "word " ); break; + case 32: ud_asmprintf(u, UD_opsize, "dword "); break; + case 64: ud_asmprintf(u, UD_opsize, "qword "); break; + case 80: ud_asmprintf(u, UD_opsize, "tword "); break; + case 128: ud_asmprintf(u, UD_opsize, "oword "); break; + case 256: ud_asmprintf(u, UD_opsize, "yword "); break; default: break; } } @@ -60,34 +60,36 @@ static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast) { switch(op->type) { case UD_OP_REG: - ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]); + ud_asmprintf(u, UD_register, "%s", ud_reg_tab[op->base - UD_R_AL]); break; case UD_OP_MEM: if (syn_cast) { opr_cast(u, op); } - ud_asmprintf(u, "["); + ud_asmprintf(u, UD_operator, "["); if (u->pfx_seg) { - ud_asmprintf(u, "%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]); + ud_asmprintf(u, UD_prefix, "%s", ud_reg_tab[u->pfx_seg - UD_R_AL]); + ud_asmprintf(u, UD_operator, ":"); } if (op->base) { - ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]); + ud_asmprintf(u, UD_register, "%s", ud_reg_tab[op->base - UD_R_AL]); } if (op->index) { - ud_asmprintf(u, "%s%s", op->base != UD_NONE? "+" : "", - ud_reg_tab[op->index - UD_R_AL]); + ud_asmprintf(u, UD_operator, "%s", op->base != UD_NONE? "+" : ""); + ud_asmprintf(u, UD_register, "%s", ud_reg_tab[op->index - UD_R_AL]); if (op->scale) { - ud_asmprintf(u, "*%d", op->scale); + ud_asmprintf(u, UD_operator, "*"); + ud_asmprintf(u, UD_immediate, "%d", op->scale); } } if (op->offset != 0) { - ud_syn_print_mem_disp(u, op, (op->base != UD_NONE || + ud_syn_print_mem_disp(u, op, (op->base != UD_NONE || op->index != UD_NONE) ? 1 : 0); } - ud_asmprintf(u, "]"); + ud_asmprintf(u, UD_operator, "]"); break; - + case UD_OP_IMM: ud_syn_print_imm(u, op); break; @@ -100,19 +102,23 @@ static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast) case UD_OP_PTR: switch (op->size) { case 32: - ud_asmprintf(u, "word 0x%x:0x%x", op->lval.ptr.seg, - op->lval.ptr.off & 0xFFFF); + ud_asmprintf(u, UD_opsize, "word "); + ud_asmprintf(u, UD_register, "0x%x", op->lval.ptr.seg); + ud_asmprintf(u, UD_operator, ":"); + ud_asmprintf(u, UD_address, "0x%x", op->lval.ptr.off & 0xFFFF); break; case 48: - ud_asmprintf(u, "dword 0x%x:0x%x", op->lval.ptr.seg, - op->lval.ptr.off); + ud_asmprintf(u, UD_opsize, "dword "); + ud_asmprintf(u, UD_register, "0x%x", op->lval.ptr.seg); + ud_asmprintf(u, UD_operator, ":"); + ud_asmprintf(u, UD_address, "0x%x", op->lval.ptr.off); break; } break; case UD_OP_CONST: if (syn_cast) opr_cast(u, op); - ud_asmprintf(u, "%d", op->lval.udword); + ud_asmprintf(u, UD_immediate, "%d", op->lval.udword); break; default: return; @@ -129,44 +135,44 @@ ud_translate_intel(struct ud* u) /* check if P_OSO prefix is used */ if (!P_OSO(u->itab_entry->prefix) && u->pfx_opr) { switch (u->dis_mode) { - case 16: ud_asmprintf(u, "o32 "); break; + case 16: ud_asmprintf(u, UD_prefix, "o32 "); break; case 32: - case 64: ud_asmprintf(u, "o16 "); break; + case 64: ud_asmprintf(u, UD_prefix, "o16 "); break; } } /* check if P_ASO prefix was used */ if (!P_ASO(u->itab_entry->prefix) && u->pfx_adr) { switch (u->dis_mode) { - case 16: ud_asmprintf(u, "a32 "); break; - case 32: ud_asmprintf(u, "a16 "); break; - case 64: ud_asmprintf(u, "a32 "); break; + case 16: ud_asmprintf(u, UD_prefix, "a32 "); break; + case 32: ud_asmprintf(u, UD_prefix, "a16 "); break; + case 64: ud_asmprintf(u, UD_prefix, "a32 "); break; } } if (u->pfx_seg && u->operand[0].type != UD_OP_MEM && u->operand[1].type != UD_OP_MEM ) { - ud_asmprintf(u, "%s ", ud_reg_tab[u->pfx_seg - UD_R_AL]); + ud_asmprintf(u, UD_prefix, "%s ", ud_reg_tab[u->pfx_seg - UD_R_AL]); } if (u->pfx_lock) { - ud_asmprintf(u, "lock "); + ud_asmprintf(u, UD_prefix, "lock "); } if (u->pfx_rep) { - ud_asmprintf(u, "rep "); + ud_asmprintf(u, UD_prefix, "rep "); } else if (u->pfx_repe) { - ud_asmprintf(u, "repe "); + ud_asmprintf(u, UD_prefix, "repe "); } else if (u->pfx_repne) { - ud_asmprintf(u, "repne "); + ud_asmprintf(u, UD_prefix, "repne "); } /* print the instruction mnemonic */ - ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic)); + ud_asmprintf(u, UD_opcode, "%s", ud_lookup_mnemonic(u->mnemonic)); if (u->operand[0].type != UD_NONE) { int cast = 0; - ud_asmprintf(u, " "); + ud_asmprintf(u, UD_operator, " "); if (u->operand[0].type == UD_OP_MEM) { if (u->operand[1].type == UD_OP_IMM || u->operand[1].type == UD_OP_CONST || @@ -194,9 +200,9 @@ ud_translate_intel(struct ud* u) if (u->operand[1].type != UD_NONE) { int cast = 0; - ud_asmprintf(u, ", "); + ud_asmprintf(u, UD_operator, ", "); if (u->operand[1].type == UD_OP_MEM && - u->operand[0].size != u->operand[1].size && + u->operand[0].size != u->operand[1].size && !ud_opr_is_sreg(&u->operand[0])) { cast = 1; } @@ -205,7 +211,7 @@ ud_translate_intel(struct ud* u) if (u->operand[2].type != UD_NONE) { int cast = 0; - ud_asmprintf(u, ", "); + ud_asmprintf(u, UD_operator, ", "); if (u->operand[2].type == UD_OP_MEM && u->operand[2].size != u->operand[1].size) { cast = 1; @@ -214,7 +220,7 @@ ud_translate_intel(struct ud* u) } if (u->operand[3].type != UD_NONE) { - ud_asmprintf(u, ", "); + ud_asmprintf(u, UD_operator, ", "); gen_operand(u, &u->operand[3], 0); } } diff --git a/libudis86/syn.c b/libudis86/syn.c index 1b9e1d4..7b2ab52 100644 --- a/libudis86/syn.c +++ b/libudis86/syn.c @@ -103,19 +103,17 @@ ud_syn_rel_target(struct ud *u, struct ud_operand *opr) /* - * asmprintf + * asmvprintf * Printf style function for printing translated assembly * output. Returns the number of characters written and * moves the buffer pointer forward. On an overflow, * returns a negative number and truncates the output. */ int -ud_asmprintf(struct ud *u, const char *fmt, ...) +ud_asmvprintf(struct ud *u, const char *fmt, va_list ap) { int ret; int avail; - va_list ap; - va_start(ap, fmt); avail = u->asm_buf_size - u->asm_buf_fill - 1 /* nullchar */; ret = vsnprintf((char*) u->asm_buf + u->asm_buf_fill, avail, fmt, ap); if (ret < 0 || ret > avail) { @@ -123,7 +121,6 @@ ud_asmprintf(struct ud *u, const char *fmt, ...) } else { u->asm_buf_fill += ret; } - va_end(ap); return ret; } @@ -137,14 +134,15 @@ ud_syn_print_addr(struct ud *u, uint64_t addr) name = u->sym_resolver(u, addr, &offset); if (name) { if (offset) { - ud_asmprintf(u, "%s%+" FMT64 "d", name, offset); + ud_asmprintf(u, UD_symbol, "%s", name); + ud_asmprintf(u, UD_immediate, "%+" FMT64 "d", offset); } else { - ud_asmprintf(u, "%s", name); + ud_asmprintf(u, UD_symbol, "%s", name); } return; } } - ud_asmprintf(u, "0x%" FMT64 "x", addr); + ud_asmprintf(u, UD_address, "0x%" FMT64 "x", addr); } @@ -171,7 +169,7 @@ ud_syn_print_imm(struct ud* u, const struct ud_operand *op) default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */ } } - ud_asmprintf(u, "0x%" FMT64 "x", v); + ud_asmprintf(u, UD_immediate, "0x%" FMT64 "x", v); } @@ -189,7 +187,7 @@ ud_syn_print_mem_disp(struct ud* u, const struct ud_operand *op, int sign) case 64: v = op->lval.uqword; break; default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */ } - ud_asmprintf(u, "0x%" FMT64 "x", v); + ud_asmprintf(u, UD_immediate, "0x%" FMT64 "x", v); } else { int64_t v; UD_ASSERT(op->offset != 64); @@ -200,9 +198,11 @@ ud_syn_print_mem_disp(struct ud* u, const struct ud_operand *op, int sign) default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */ } if (v < 0) { - ud_asmprintf(u, "-0x%" FMT64 "x", -v); + ud_asmprintf(u, UD_operator, "-"); + ud_asmprintf(u, UD_immediate, "0x%" FMT64 "x", -v); } else if (v > 0) { - ud_asmprintf(u, "%s0x%" FMT64 "x", sign? "+" : "", v); + ud_asmprintf(u, UD_operator, "%s", sign? "+" : ""); + ud_asmprintf(u, UD_immediate, "0x%" FMT64 "x", v); } } } diff --git a/libudis86/syn.h b/libudis86/syn.h index d3b1e3f..0a5dfcf 100644 --- a/libudis86/syn.h +++ b/libudis86/syn.h @@ -35,12 +35,20 @@ extern const char* ud_reg_tab[]; uint64_t ud_syn_rel_target(struct ud*, struct ud_operand*); -#ifdef __GNUC__ -int ud_asmprintf(struct ud *u, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); -#else -int ud_asmprintf(struct ud *u, const char *fmt, ...); -#endif +int ud_asmvprintf(struct ud *u, const char *fmt, va_list ap); + +static inline int ud_asmprintf(struct ud *u, enum ud_syn_class sc, const char *fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + if (u->asmvprintf_hook) + ret = (*u->asmvprintf_hook)(u, sc, fmt, ap); + else + ret = ud_asmvprintf(u, fmt, ap); + va_end(ap); + return ret; +} void ud_syn_print_addr(struct ud *u, uint64_t addr); void ud_syn_print_imm(struct ud* u, const struct ud_operand *op); diff --git a/libudis86/types.h b/libudis86/types.h index f13bd7b..2e2692a 100644 --- a/libudis86/types.h +++ b/libudis86/types.h @@ -166,6 +166,22 @@ struct ud_operand { uint8_t _oprcode; }; +/* ----------------------------------------------------------------------------- + * enum ud_syn_class - Type of disassembled syntex elements + * ----------------------------------------------------------------------------- + */ +enum ud_syn_class { + UD_prefix, + UD_opcode, + UD_directive, + UD_register, + UD_immediate, + UD_address, + UD_operator, + UD_opsize, + UD_symbol, +}; + /* ----------------------------------------------------------------------------- * struct ud - The udis86 object. * ----------------------------------------------------------------------------- @@ -234,6 +250,11 @@ struct ud void * user_opaque_data; struct ud_itab_entry * itab_entry; struct ud_lookup_table_list_entry *le; + + /* + * Assembly output hook + */ + int (*asmvprintf_hook)(struct ud*, enum ud_syn_class, const char *, va_list); }; /* ----------------------------------------------------------------------------- diff --git a/libudis86/udis86.c b/libudis86/udis86.c index e039c4e..17c38e3 100644 --- a/libudis86/udis86.c +++ b/libudis86/udis86.c @@ -312,6 +312,27 @@ ud_set_sym_resolver(struct ud *u, const char* (*resolver)(struct ud*, } +/* ============================================================================= + * ud_set_asmvprintf_hook + * Set asmvprintf hook. + * + * The asmvprintf hook could be used to implement custom assembly code + * printing procedure with the help of udis86 builtin syntax formatting + * machanism. The most signficant scenario is the syntax highlighting. + * + * The function pointer maybe NULL which resets symbol resolution. + * ============================================================================= + */ +void +ud_set_asmvprintf_hook(struct ud *u, + int (*asmvprintf_hook)(struct ud*, + enum ud_syn_class, + const char *, + va_list)) +{ + u->asmvprintf_hook = asmvprintf_hook; +} + /* ============================================================================= * ud_insn_mnemonic * Return the current instruction mnemonic. diff --git a/udcli/udcli.c b/udcli/udcli.c index 9b044ca..0dfadb8 100644 --- a/udcli/udcli.c +++ b/udcli/udcli.c @@ -73,10 +73,11 @@ static char help[] = " hexadecimal representation. Example: 0f 01 ae 00\n" " -noff : Do not display the offset of instructions.\n" " -nohex : Do not display the hexadecimal code of instructions.\n" + " -color : Colorize the disassembly code.\n" " -h : Display this help message.\n" " --version: Show version.\n" "\n" - "Udcli is a front-end to the Udis86 Disassembler Library.\n" + "Udcli is a front-end to the Udis86 Disassembler Library.\n" "http://udis86.sourceforge.net/\n" }; @@ -88,15 +89,71 @@ unsigned char o_do_off = 1; unsigned char o_do_hex = 1; unsigned char o_do_x = 0; unsigned o_vendor = UD_VENDOR_AMD; +unsigned char o_colorize = 0; int input_hook_x(ud_t* u); int input_hook_file(ud_t* u); +#ifdef _WIN32 + +#include + +#define CLR_BLACK 0|8 +#define CLR_BLUE 1|8 +#define CLR_GREEN 2|8 +#define CLR_CYAN 3|8 +#define CLR_RED 4|8 +#define CLR_PINK 5|8 +#define CLR_YELLOW 6|8 +#define CLR_WHITE 7|8 + +static void color(int clr) +{ + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), clr % 8); +} + +#else + +#define CLR_BLACK 0|8 +#define CLR_RED 1|8 +#define CLR_GREEN 2|8 +#define CLR_YELLOW 3|8 +#define CLR_BLUE 4|8 +#define CLR_PINK 5|8 +#define CLR_CYAN 6|8 +#define CLR_WHITE 7|8 + +static void color(int clr) +{ + char ctrl[32]; + int fore_clr = clr % 8; + sprintf(ctrl, "\033[%d;%dm", + clr > 7 ? 1 : 0, 30 + fore_clr); + printf("%s", ctrl); +} + +#endif + +static int asmvprintf_colorized(struct ud *u, enum ud_syn_class sc, + const char *fmt, va_list ap) +{ + int ret; + int cmap[] = { + CLR_PINK, CLR_RED, CLR_GREEN, CLR_WHITE, + CLR_YELLOW, CLR_WHITE, CLR_GREEN, CLR_CYAN + }; + color(cmap[sc]); + ret = vprintf(fmt, ap); + color(CLR_WHITE); + return ret; +} + int main(int argc, char **argv) { char *prog_path = *argv; char *s; ud_t ud_obj; + void (*translator)(struct ud *) = 0; /* initialize */ ud_init(&ud_obj); @@ -133,6 +190,8 @@ int main(int argc, char **argv) o_do_off = 0; else if (strcmp(*argv,"-nohex") == 0) o_do_hex = 0; + else if (strcmp(*argv,"-color") == 0) + o_colorize = 1; else if (strcmp(*argv,"-x") == 0) o_do_x = 1; else if (strcmp(*argv,"-s") == 0) @@ -202,15 +261,24 @@ int main(int argc, char **argv) if (o_do_x) ud_set_input_hook(&ud_obj, input_hook_x); - else ud_set_input_hook(&ud_obj, input_hook_file); + else ud_set_input_hook(&ud_obj, input_hook_file); if (o_skip) { o_count += o_skip; ud_input_skip(&ud_obj, o_skip); } + if (o_colorize) { + ud_set_asmvprintf_hook(&ud_obj, asmvprintf_colorized); + /* disable auto-translate */ + translator = ud_obj.translator; + ud_set_syntax(&ud_obj, NULL); + } + /* disassembly loop */ while (ud_disassemble(&ud_obj)) { + if (o_colorize) + color(CLR_WHITE); if (o_do_off) printf("%016" FMT64 "x ", ud_insn_off(&ud_obj)); if (o_do_hex) { @@ -224,12 +292,15 @@ int main(int argc, char **argv) printf("%15s -", ""); printf("%-16s", hex2); } - } + } else printf(" %-24s", ud_insn_asm(&ud_obj)); + if (translator) + (*translator)(&ud_obj); + printf("\n"); } - + exit(EXIT_SUCCESS); return 0; }