Esempio n. 1
0
/*******************************************************************************
 * 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);
}
Esempio n. 2
0
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
}
Esempio n. 3
0
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(']');
}
Esempio n. 4
0
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);
    }
}