/******************************************************************************* * Copyright (c) 2015 Xilinx, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompany this distribution. * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * You may elect to redistribute this code under either of these licenses. * * Contributors: * Xilinx - initial API and implementation *******************************************************************************/ #include <tcf/config.h> #if SERVICE_Disassembly #include <assert.h> #include <stdio.h> #include <tcf/framework/context.h> #include <tcf/services/symbols.h> #include <machine/x86_64/tcf/disassembler-x86_64.h> #define PREFIX_LOCK 0x0001 #define PREFIX_REPNZ 0x0002 #define PREFIX_REPZ 0x0004 #define PREFIX_CS 0x0008 #define PREFIX_SS 0x0010 #define PREFIX_DS 0x0020 #define PREFIX_ES 0x0040 #define PREFIX_FS 0x0080 #define PREFIX_GS 0x0100 #define PREFIX_DATA_SIZE 0x0200 #define PREFIX_ADDR_SIZE 0x0400 #define REX_W 0x08 #define REX_R 0x04 #define REX_X 0x02 #define REX_B 0x01 static char buf[128]; static size_t buf_pos = 0; static DisassemblerParams * params = NULL; static uint64_t instr_addr = 0; static uint8_t * code_buf = NULL; static size_t code_pos = 0; static size_t code_len = 0; static uint32_t prefix = 0; static uint32_t vex = 0; static uint8_t rex = 0; static unsigned data_size = 0; static unsigned addr_size = 0; static int x86_64 = 0; static uint8_t get_code(void) { uint8_t c = 0; if (code_pos < code_len) c = code_buf[code_pos]; code_pos++; return c; } static void add_char(char ch) { if (buf_pos >= sizeof(buf) - 1) return; buf[buf_pos++] = ch; } static void add_str(const char * s) { while (*s) add_char(*s++); } static void add_dec_uint32(uint32_t n) { char s[32]; size_t i = 0; do { s[i++] = (char)('0' + n % 10); n = n / 10; } while (n != 0); while (i > 0) add_char(s[--i]); } #if 0 /* Not used yet */ static void add_dec_uint64(uint64_t n) { char s[64]; size_t i = 0; do { s[i++] = (char)('0' + (int)(n % 10)); n = n / 10; } while (n != 0); while (i > 0) add_char(s[--i]); } #endif static void add_hex_uint32(uint32_t n) { char s[32]; size_t i = 0; while (i < 8) { uint32_t d = n & 0xf; if (i > 0 && n == 0) break; s[i++] = (char)(d < 10 ? '0' + d : 'a' + d - 10); n = n >> 4; } while (i > 0) add_char(s[--i]); } static void add_hex_uint64(uint64_t n) { char s[64]; size_t i = 0; while (i < 16) { uint32_t d = n & 0xf; if (i > 0 && n == 0) break; s[i++] = (char)(d < 10 ? '0' + d : 'a' + d - 10); n = n >> 4; } while (i > 0) add_char(s[--i]); } #if 0 /* Not used yet */ static void add_flt_uint32(uint32_t n) { char buf[32]; union { uint32_t n; float f; } u; u.n = n; snprintf(buf, sizeof(buf), "%g", u.f); add_str(buf); } static void add_flt_uint64(uint64_t n) { char buf[32]; union { uint64_t n; double d; } u; u.n = n; snprintf(buf, sizeof(buf), "%g", u.d); add_str(buf); } #endif static void add_addr(uint64_t addr) { while (buf_pos < 16) add_char(' '); add_str("; addr=0x"); add_hex_uint64(addr); #if ENABLE_Symbols if (params->ctx != NULL) { Symbol * sym = NULL; char * name = NULL; ContextAddress sym_addr = 0; if (find_symbol_by_addr(params->ctx, STACK_NO_FRAME, (ContextAddress)addr, &sym) < 0) return; if (get_symbol_name(sym, &name) < 0 || name == NULL) return; if (get_symbol_address(sym, &sym_addr) < 0) return; if (sym_addr <= addr) { add_str(": "); add_str(name); if (sym_addr < addr) { add_str(" + 0x"); add_hex_uint64(addr - (uint64_t)sym_addr); } } } #endif } static void add_reg(unsigned reg, unsigned size) { if (reg >= 8) { add_char('r'); add_dec_uint32(reg); switch (size) { case 1: add_char('l'); break; case 2: add_char('w'); break; case 4: add_char('d'); break; } return; } if (x86_64 && size == 1 && reg >= 4 && reg <= 7) { switch (reg) { case 4: add_str("spl"); break; case 5: add_str("bpl"); break; case 6: add_str("sil"); break; case 7: add_str("dil"); break; } return; } if (size == 1) { switch (reg) { case 0: add_str("al"); break; case 1: add_str("cl"); break; case 2: add_str("dl"); break; case 3: add_str("bl"); break; case 4: add_str("ah"); break; case 5: add_str("ch"); break; case 6: add_str("dh"); break; case 7: add_str("bh"); break; } } else { switch (size) { case 4: add_char('e'); break; case 8: add_char('r'); break; } switch (reg) { case 0: add_str("ax"); break; case 1: add_str("cx"); break; case 2: add_str("dx"); break; case 3: add_str("bx"); break; case 4: add_str("sp"); break; case 5: add_str("bp"); break; case 6: add_str("si"); break; case 7: add_str("di"); break; } } } static void add_seg_reg(unsigned reg) { switch (reg) { case 0: add_str("es"); break; case 1: add_str("cs"); break; case 2: add_str("ss"); break; case 3: add_str("ds"); break; case 4: add_str("fs"); break; case 5: add_str("gs"); break; case 6: add_str("s6"); break; case 7: add_str("s7"); break; } } #if 0 static void add_ctrl_reg(unsigned reg) { add_str("cr"); add_dec_uint32(reg); } static void add_dbg_reg(unsigned reg) { add_str("dr"); add_dec_uint32(reg); } #endif static void add_ttt(unsigned ttt) { switch (ttt) { case 0: add_str("o"); break; case 1: add_str("no"); break; case 2: add_str("b"); break; case 3: add_str("ae"); break; case 4: add_str("e"); break; case 5: add_str("ne"); break; case 6: add_str("be"); break; case 7: add_str("a"); break; case 8: add_str("s"); break; case 9: add_str("ns"); break; case 10: add_str("pe"); break; case 11: add_str("po"); break; case 12: add_str("l"); break; case 13: add_str("ge"); break; case 14: add_str("le"); break; case 15: add_str("g"); break; } } static void add_disp8(void) { uint32_t disp = get_code(); if (disp < 0x80) { add_char('+'); } else { add_char('-'); disp = (disp ^ 0xff) + 1; } add_str("0x"); add_hex_uint32(disp); } static void add_disp16(void) { uint32_t disp = get_code(); disp |= (uint32_t)get_code() << 8; add_str("0x"); add_hex_uint32(disp); } static void add_disp32(void) { uint32_t disp = get_code(); disp |= (uint32_t)get_code() << 8; disp |= (uint32_t)get_code() << 16; disp |= (uint32_t)get_code() << 24; add_str("0x"); add_hex_uint32(disp); } static void add_imm8(void) { uint32_t imm = get_code(); add_str("0x"); add_hex_uint32(imm); } static void add_imm16(void) { uint32_t imm = get_code(); imm |= (uint32_t)get_code() << 8; add_str("0x"); add_hex_uint32(imm); } static void add_imm32(void) { uint32_t imm = get_code(); imm |= (uint32_t)get_code() << 8; imm |= (uint32_t)get_code() << 16; imm |= (uint32_t)get_code() << 24; add_str("0x"); add_hex_uint32(imm); } #if 0 /* Not used yet */ static void add_imm64(void) { uint64_t imm = get_code(); imm |= (uint64_t)get_code() << 8; imm |= (uint64_t)get_code() << 16; imm |= (uint64_t)get_code() << 24; imm |= (uint64_t)get_code() << 32; imm |= (uint64_t)get_code() << 40; imm |= (uint64_t)get_code() << 48; imm |= (uint64_t)get_code() << 56; add_str("0x"); add_hex_uint64(imm); }
static void add_addr(uint64_t addr) { add_hex_uint64(addr); #if ENABLE_Symbols if (ctx != NULL) { Symbol * sym = NULL; char * name = NULL; ContextAddress sym_addr = 0; if (find_symbol_by_addr(ctx, STACK_NO_FRAME, (ContextAddress)addr, &sym) < 0) return; if (get_symbol_name(sym, &name) < 0 || name == NULL) return; if (get_symbol_address(sym, &sym_addr) < 0) return; if (sym_addr <= addr) { add_str(" ; "); add_str(name); if (sym_addr < addr) { add_str(" + 0x"); add_hex_uint64(addr - sym_addr); } } } #endif }
static void add_moffs(int wide) { uint64_t addr = 0; unsigned i = 0; while (i < addr_size) { addr |= (uint64_t)get_code() << (i * 8); i++; } add_str("[0x"); add_hex_uint64(addr); add_char(']'); }
static void add_rel(unsigned size) { uint64_t offs = 0; uint64_t sign = (uint64_t)1 << (size * 8 - 1); uint64_t mask = sign - 1; unsigned i = 0; while (i < size) { offs |= (uint64_t)get_code() << (i * 8); i++; } if (offs & sign) { offs = (offs ^ (sign | mask)) + 1; add_str("-0x"); add_hex_uint64(offs); add_addr(instr_addr + code_pos - offs); } else { add_str("+0x"); add_hex_uint64(offs); add_addr(instr_addr + code_pos + offs); } }