cstool: add x86 debug information
This commit is contained in:
parent
4e52d98ced
commit
089893ed98
|
@ -2,19 +2,25 @@
|
|||
|
||||
include ../functions.mk
|
||||
|
||||
.PHONY: clean
|
||||
.PHONY: clean all
|
||||
|
||||
LIBNAME = capstone
|
||||
|
||||
CFLAGS = -I../include
|
||||
LDFLAGS = -O3 -Wall -L.. -l$(LIBNAME)
|
||||
|
||||
cstool: cstool.o
|
||||
TARGET = cstool
|
||||
SOURCES := $(wildcard *.c)
|
||||
OBJECTS := $(SOURCES:.c=.o)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
ifeq ($(V),0)
|
||||
$(call log,LINK,$@)
|
||||
@${CC} $< $(LDFLAGS) -o $@
|
||||
@${CC} $(OBJECTS) $(LDFLAGS) -o $@
|
||||
else
|
||||
${CC} $< $(LDFLAGS) -o $@
|
||||
${CC} $(OBJECTS) $(LDFLAGS) -o $@
|
||||
endif
|
||||
|
||||
clean:
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#define VERSION "1.0"
|
||||
|
||||
void print_insn_detail_x86(csh ud, cs_mode mode, cs_insn *ins);
|
||||
|
||||
// convert hexchar to hexnum
|
||||
static uint8_t char_to_hexnum(char c)
|
||||
{
|
||||
|
@ -53,7 +55,7 @@ static uint8_t *preprocess(char *code, size_t *size)
|
|||
static void usage(char *prog)
|
||||
{
|
||||
printf("Cstool v%s for Capstone Disassembler Engine (www.capstone-engine.org)\n\n", VERSION);
|
||||
printf("Syntax: %s <arch+mode> <assembly-hexstring> [start-address-in-hex-format]\n", prog);
|
||||
printf("Syntax: %s [-d:print all debug information] <arch+mode> <assembly-hexstring> [start-address-in-hex-format]\n", prog);
|
||||
printf("\nThe following <arch+mode> options are supported:\n");
|
||||
|
||||
if (cs_support(CS_ARCH_X86)) {
|
||||
|
@ -114,30 +116,55 @@ int main(int argc, char **argv)
|
|||
uint64_t address = 0;
|
||||
cs_insn *insn;
|
||||
cs_err err;
|
||||
bool x86_arch = false;
|
||||
cs_mode md;
|
||||
char *platform;
|
||||
bool x86_arch = false, debug_flag = false;
|
||||
|
||||
if (argc != 3 && argc != 4) {
|
||||
if (argc != 3 && argc != 4 && argc != 5) {
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mode = argv[1];
|
||||
assembly = preprocess(argv[2], &size);
|
||||
if (assembly == NULL) {
|
||||
printf("ERROR: invalid assembler-string argument, quit!\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (argc == 4) {
|
||||
// cstool <arch> <assembly> <address>
|
||||
char *temp;
|
||||
address = strtoull(argv[3], &temp, 16);
|
||||
if (temp == argv[3] || *temp != '\0' || errno == ERANGE) {
|
||||
printf("ERROR: invalid address argument, quit!\n");
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "-d")) {
|
||||
if (argc == 3) {
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
debug_flag = true;
|
||||
mode = argv[2];
|
||||
assembly = preprocess(argv[3], &size);
|
||||
if (argc == 5) {
|
||||
char *temp;
|
||||
address = strtoull(argv[4], &temp, 16);
|
||||
if (temp == argv[4] || *temp != '\0' || errno == ERANGE) {
|
||||
printf("ERROR: invalid address argument, quit!\n");
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (argc == 5) {
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mode = argv[1];
|
||||
assembly = preprocess(argv[2], &size);
|
||||
if (assembly == NULL) {
|
||||
printf("ERROR: invalid assembler-string argument, quit!\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (argc == 4) {
|
||||
// cstool <arch> <assembly> <address>
|
||||
char *temp;
|
||||
address = strtoull(argv[3], &temp, 16);
|
||||
if (temp == argv[3] || *temp != '\0' || errno == ERANGE) {
|
||||
printf("ERROR: invalid address argument, quit!\n");
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(mode, "arm")) {
|
||||
err = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &handle);
|
||||
}
|
||||
|
@ -188,6 +215,8 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
if (!strcmp(mode, "x32")) {
|
||||
md = CS_MODE_32;
|
||||
platform = "x32";
|
||||
x86_arch = true;
|
||||
err = cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
|
||||
}
|
||||
|
@ -247,7 +276,11 @@ int main(int argc, char **argv)
|
|||
return -1;
|
||||
}
|
||||
|
||||
count = cs_disasm(handle, assembly, size, address, 0, &insn);
|
||||
if (debug_flag) {
|
||||
cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
|
||||
}
|
||||
|
||||
count = cs_disasm(handle, assembly, size, address, 0, &insn);
|
||||
if (count > 0) {
|
||||
size_t i;
|
||||
|
||||
|
@ -265,6 +298,11 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
printf(" %s\t%s\n", insn[i].mnemonic, insn[i].op_str);
|
||||
if (debug_flag) {
|
||||
if (x86_arch) {
|
||||
print_insn_detail_x86(handle, md, &insn[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
cs_free(insn, count);
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/* Second-Best Disassembler Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013> */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <platform.h>
|
||||
#include <capstone.h>
|
||||
|
||||
|
||||
|
||||
static void print_string_hex(char *comment, unsigned char *str, size_t len)
|
||||
{
|
||||
unsigned char *c;
|
||||
|
||||
printf("%s", comment);
|
||||
for (c = str; c < str + len; c++) {
|
||||
printf("0x%02x ", *c & 0xff);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void print_insn_detail_x86(csh ud, cs_mode mode, cs_insn *ins)
|
||||
{
|
||||
int count, i;
|
||||
cs_x86 *x86;
|
||||
|
||||
// detail can be NULL on "data" instruction if SKIPDATA option is turned ON
|
||||
if (ins->detail == NULL)
|
||||
return;
|
||||
|
||||
x86 = &(ins->detail->x86);
|
||||
|
||||
print_string_hex("\tPrefix:", x86->prefix, 4);
|
||||
|
||||
print_string_hex("\tOpcode:", x86->opcode, 4);
|
||||
|
||||
printf("\trex: 0x%x\n", x86->rex);
|
||||
|
||||
printf("\taddr_size: %u\n", x86->addr_size);
|
||||
printf("\tmodrm: 0x%x\n", x86->modrm);
|
||||
printf("\tdisp: 0x%x\n", x86->disp);
|
||||
|
||||
// SIB is not available in 16-bit mode
|
||||
if ((mode & CS_MODE_16) == 0) {
|
||||
printf("\tsib: 0x%x\n", x86->sib);
|
||||
if (x86->sib_base != X86_REG_INVALID)
|
||||
printf("\t\tsib_base: %s\n", cs_reg_name(ud, x86->sib_base));
|
||||
if (x86->sib_index != X86_REG_INVALID)
|
||||
printf("\t\tsib_index: %s\n", cs_reg_name(ud, x86->sib_index));
|
||||
if (x86->sib_scale != 0)
|
||||
printf("\t\tsib_scale: %d\n", x86->sib_scale);
|
||||
}
|
||||
|
||||
// SSE code condition
|
||||
if (x86->sse_cc != X86_SSE_CC_INVALID) {
|
||||
printf("\tsse_cc: %u\n", x86->sse_cc);
|
||||
}
|
||||
|
||||
// AVX code condition
|
||||
if (x86->avx_cc != X86_AVX_CC_INVALID) {
|
||||
printf("\tavx_cc: %u\n", x86->avx_cc);
|
||||
}
|
||||
|
||||
// AVX Suppress All Exception
|
||||
if (x86->avx_sae) {
|
||||
printf("\tavx_sae: %u\n", x86->avx_sae);
|
||||
}
|
||||
|
||||
// AVX Rounding Mode
|
||||
if (x86->avx_rm != X86_AVX_RM_INVALID) {
|
||||
printf("\tavx_rm: %u\n", x86->avx_rm);
|
||||
}
|
||||
|
||||
count = cs_op_count(ud, ins, X86_OP_IMM);
|
||||
if (count) {
|
||||
printf("\timm_count: %u\n", count);
|
||||
for (i = 1; i < count + 1; i++) {
|
||||
int index = cs_op_index(ud, ins, X86_OP_IMM, i);
|
||||
printf("\t\timms[%u]: 0x%" PRIx64 "\n", i, x86->operands[index].imm);
|
||||
}
|
||||
}
|
||||
|
||||
if (x86->op_count)
|
||||
printf("\top_count: %u\n", x86->op_count);
|
||||
for (i = 0; i < x86->op_count; i++) {
|
||||
cs_x86_op *op = &(x86->operands[i]);
|
||||
|
||||
switch((int)op->type) {
|
||||
case X86_OP_REG:
|
||||
printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(ud, op->reg));
|
||||
break;
|
||||
case X86_OP_IMM:
|
||||
printf("\t\toperands[%u].type: IMM = 0x%" PRIx64 "\n", i, op->imm);
|
||||
break;
|
||||
case X86_OP_MEM:
|
||||
printf("\t\toperands[%u].type: MEM\n", i);
|
||||
if (op->mem.segment != X86_REG_INVALID)
|
||||
printf("\t\t\toperands[%u].mem.segment: REG = %s\n", i, cs_reg_name(ud, op->mem.segment));
|
||||
if (op->mem.base != X86_REG_INVALID)
|
||||
printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(ud, op->mem.base));
|
||||
if (op->mem.index != X86_REG_INVALID)
|
||||
printf("\t\t\toperands[%u].mem.index: REG = %s\n", i, cs_reg_name(ud, op->mem.index));
|
||||
if (op->mem.scale != 1)
|
||||
printf("\t\t\toperands[%u].mem.scale: %u\n", i, op->mem.scale);
|
||||
if (op->mem.disp != 0)
|
||||
printf("\t\t\toperands[%u].mem.disp: 0x%" PRIx64 "\n", i, op->mem.disp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// AVX broadcast type
|
||||
if (op->avx_bcast != X86_AVX_BCAST_INVALID)
|
||||
printf("\t\toperands[%u].avx_bcast: %u\n", i, op->avx_bcast);
|
||||
|
||||
// AVX zero opmask {z}
|
||||
if (op->avx_zero_opmask != false)
|
||||
printf("\t\toperands[%u].avx_zero_opmask: TRUE\n", i);
|
||||
|
||||
printf("\t\toperands[%u].size: %u\n", i, op->size);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
Loading…
Reference in New Issue