diff options
Diffstat (limited to 'tools/debugger/xenitp/xenitp.c')
-rw-r--r-- | tools/debugger/xenitp/xenitp.c | 1599 |
1 files changed, 1599 insertions, 0 deletions
diff --git a/tools/debugger/xenitp/xenitp.c b/tools/debugger/xenitp/xenitp.c new file mode 100644 index 0000000000..2c9f5cd6f2 --- /dev/null +++ b/tools/debugger/xenitp/xenitp.c @@ -0,0 +1,1599 @@ +/* tools/debugger/xenitp.c - A low-level debugger. + + Based on xenctxt.c, but heavily modified. + Copyright 2007 Tristan Gingold <tgingold@free.fr> + + Xenitp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xenitp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <time.h> +#include <stdlib.h> +#include <sys/mman.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <argp.h> +#include <signal.h> +#include <string.h> +#include <getopt.h> + +#include "xenctrl.h" +#include <xen/sys/privcmd.h> +#include "dis-asm.h" + +#ifdef __HYPERVISOR_ia64_debug_op +#define HAVE_DEBUG_OP +#endif + +static int xc_handle = 0; +static int domid = 0; +static vcpu_guest_context_t *cur_ctx; +static int cur_vcpu; + +#define PSR_BN (1UL << 44) +#define PSR_SS (1UL << 40) +#define PSR_DB (1UL << 24) +#define PSR_TB (1UL << 26) +#define PSR_DD (1UL << 39) +#define PSR_ID (1UL << 37) +#define PSR_IT (1UL << 36) +#define PSR_DT (1UL << 17) +#define PSR_RI_SHIFT 41 +#define CFM_SOF_MASK 0x3f + +int virt_to_phys (int is_inst, unsigned long vaddr, unsigned long *paddr); + +inline unsigned int ctx_slot (vcpu_guest_context_t *ctx) +{ + return (ctx->regs.psr >> PSR_RI_SHIFT) & 3; +} + +unsigned char * +target_map_memory (unsigned long paddr) +{ + static unsigned long cur_page = -1; + static unsigned char *cur_map = NULL; + + if ((paddr >> XC_PAGE_SHIFT) != cur_page) { + if (cur_map) { + munmap (cur_map, XC_PAGE_SIZE); + cur_map = NULL; + } + cur_page = paddr >> XC_PAGE_SHIFT; + cur_map = xc_map_foreign_range (xc_handle, domid, XC_PAGE_SIZE, + PROT_READ, cur_page); + if (cur_map == NULL) { + perror ("cannot map page"); + cur_page = -1; + return NULL; + } + } + return cur_map + (paddr & (XC_PAGE_SIZE - 1)); +} + +/* Get LENGTH bytes from info's buffer, at target address memaddr. + Transfer them to myaddr. */ +int +target_read_memory (bfd_vma memaddr, bfd_byte *myaddr, + unsigned int length, struct disassemble_info *info) +{ + int i; + unsigned long paddr; + + if (cur_ctx->regs.psr & PSR_IT) { + if (virt_to_phys (1, memaddr, &paddr) != 0) + return EIO; + } + else { + /* Clear UC. */ + paddr = memaddr & ~(1UL << 63); + } + + for (i = 0; i < length; i++) { + unsigned char *p = target_map_memory (paddr + i); + + if (p == NULL) + return EIO; + myaddr[i] = *p; + } + return 0; +} + +/* Print an error message. We can assume that this is in response to + an error return from buffer_read_memory. */ +void +perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info) +{ + if (status != EIO) + /* Can't happen. */ + (*info->fprintf_func) (info->stream, "Unknown error %d\n", status); + else + /* Actually, address between memaddr and memaddr + len was + out of bounds. */ + (*info->fprintf_func) (info->stream, + "Address 0x%" PRIx64 " is out of bounds.\n", + memaddr); +} + +/* This could be in a separate file, to save miniscule amounts of space + in statically linked executables. */ + +/* Just print the address is hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ + +void +generic_print_address (bfd_vma addr, struct disassemble_info *info) +{ + (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr); +} + +/* Just return the given address. */ + +int +generic_symbol_at_address (bfd_vma addr, struct disassemble_info * info) +{ + return 1; +} + +bfd_boolean +generic_symbol_is_valid (asymbol * sym ATTRIBUTE_UNUSED, + struct disassemble_info *info ATTRIBUTE_UNUSED) +{ + return 1; +} + +bfd_vma bfd_getl32 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0]; + v |= (unsigned long) addr[1] << 8; + v |= (unsigned long) addr[2] << 16; + v |= (unsigned long) addr[3] << 24; + + return (bfd_vma) v; +} + +bfd_vma bfd_getl64 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0]; + v |= (unsigned long) addr[1] << 8; + v |= (unsigned long) addr[2] << 16; + v |= (unsigned long) addr[3] << 24; + v |= (unsigned long) addr[4] << 32; + v |= (unsigned long) addr[5] << 40; + v |= (unsigned long) addr[6] << 48; + v |= (unsigned long) addr[7] << 56; + + return (bfd_vma) v; +} + +bfd_vma bfd_getb32 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0] << 24; + v |= (unsigned long) addr[1] << 16; + v |= (unsigned long) addr[2] << 8; + v |= (unsigned long) addr[3]; + + return (bfd_vma) v; +} + +bfd_vma bfd_getl16 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0]; + v |= (unsigned long) addr[1] << 8; + + return (bfd_vma) v; +} + +bfd_vma bfd_getb16 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0] << 24; + v |= (unsigned long) addr[1] << 16; + + return (bfd_vma) v; +} + +void +init_disassemble_info (struct disassemble_info *info, void *stream, + fprintf_ftype fprintf_func) +{ + memset (info, 0, sizeof (*info)); + + info->flavour = bfd_target_unknown_flavour; + info->arch = bfd_arch_unknown; + info->endian = BFD_ENDIAN_UNKNOWN; + info->octets_per_byte = 1; + info->fprintf_func = fprintf_func; + info->stream = stream; + info->read_memory_func = target_read_memory; + info->memory_error_func = perror_memory; + info->print_address_func = generic_print_address; + info->symbol_at_address_func = generic_symbol_at_address; + info->symbol_is_valid = generic_symbol_is_valid; + info->display_endian = BFD_ENDIAN_UNKNOWN; +} + + +void target_disas (FILE *out, unsigned long code, unsigned long size) +{ + unsigned long pc; + int count; + struct disassemble_info disasm_info; + int slot; + int (*print_insn)(bfd_vma pc, disassemble_info *info); + + INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); + + disasm_info.read_memory_func = target_read_memory; +#if 0 + disasm_info.buffer = NULL; + disasm_info.buffer_vma = (unsigned long)code; + disasm_info.buffer_length = size; +#endif + + disasm_info.endian = BFD_ENDIAN_LITTLE; + disasm_info.mach = 0; //bfd_mach_ia64; + print_insn = print_insn_ia64; + + for (pc = code, slot = 0; pc < code + size; pc += count, slot++) { + fprintf (out, "0x%016lx+%d:%c ", code, slot, + ((pc & ~0x0fUL) == cur_ctx->regs.ip + && slot == ctx_slot (cur_ctx)) ? '*' : ' '); + + count = print_insn (pc, &disasm_info); +#if 0 + { + int i; + uint8_t b; + + fprintf (out, " {"); + for (i = 0; i < count; i++) { + target_read_memory (pc + i, &b, 1, &disasm_info); + fprintf (out, " %02x", b); + } + fprintf (out, " }"); + } +#endif + fprintf (out, "\n"); + if (count < 0) + break; + } +} + + +#define PTE_ED_SHIFT 52 +#define PTE_ED_MASK 1 +#define PTE_PPN_SHIFT 12 +#define PTE_PPN_MASK 0x3fffffffff +#define PTE_AR_SHIFT 9 +#define PTE_AR_MASK 7 +#define PTE_PL_SHIFT 7 +#define PTE_PL_MASK 3 +#define PTE_D_SHIFT 6 +#define PTE_D_MASK 1 +#define PTE_A_SHIFT 5 +#define PTE_A_MASK 1 +#define PTE_MA_SHIFT 2 +#define PTE_MA_MASK 7 +#define PTE_P_SHIFT 0 +#define PTE_P_MASK 1 +#define ITIR_KEY_SHIFT 8 +#define ITIR_KEY_MASK 0xffffff +#define ITIR_PS_SHIFT 2 +#define ITIR_PS_MASK 0x3f +#define ITIR_PS_MIN 12 +#define ITIR_PS_MAX 28 +#define RR_RID_SHIFT 8 +#define RR_RID_MASK 0xffffff +#define RR_PS_SHIFT 2 +#define RR_PS_MASK 0x3f +#define RR_VE_MASK 1 + +static const char *get_ps (int ps_val) +{ + static const char ps[][5] = {" 4K", " 8K", " 16K", " ", + " 64K", " ", "256K", " ", + " 1M", " ", " 4M", " ", + " 16M", " ", " 64M", " ", + "256M"}; + return ((ps_val >= ITIR_PS_MIN && ps_val <= ITIR_PS_MAX) ? + ps[ps_val - ITIR_PS_MIN] : " "); + +} + +static void print_a_tr (int i, const struct ia64_tr_entry *tr) +{ + int ps_val, ma_val; + unsigned long pa; + + static const char ma[][4] = {"WB ", " ", " ", " ", + "UC ", "UCE", "WC ", "Nat"}; + + ps_val = tr->itir >> ITIR_PS_SHIFT & ITIR_PS_MASK; + ma_val = tr->pte >> PTE_MA_SHIFT & PTE_MA_MASK; + pa = (tr->pte >> PTE_PPN_SHIFT & PTE_PPN_MASK) << PTE_PPN_SHIFT; + pa = (pa >> ps_val) << ps_val; + printf (" [%d] %ld %06lx %016lx %013lx %02d %s %ld %ld %ld %ld " + "%ld %d %s %06lx\n", i, + tr->pte >> PTE_P_SHIFT & PTE_P_MASK, + tr->rid >> RR_RID_SHIFT & RR_RID_MASK, + tr->vadr, pa, ps_val, get_ps (ps_val), + tr->pte >> PTE_ED_SHIFT & PTE_ED_MASK, + tr->pte >> PTE_PL_SHIFT & PTE_PL_MASK, + tr->pte >> PTE_AR_SHIFT & PTE_AR_MASK, + tr->pte >> PTE_A_SHIFT & PTE_A_MASK, + tr->pte >> PTE_D_SHIFT & PTE_D_MASK, + ma_val, ma[ma_val], + tr->itir >> ITIR_KEY_SHIFT & ITIR_KEY_MASK); +} + +void print_ctx (vcpu_guest_context_t *ctx) +{ + struct vcpu_guest_context_regs *regs = &ctx->regs; + int i; + unsigned int rbs_size, cfm_sof; + + rbs_size = (regs->ar.bsp - regs->ar.bspstore) / 8; + cfm_sof = (regs->cfm & CFM_SOF_MASK); + printf ("bspstore: %016lx bsp: %016lx rbs_size=%d, sof=%d\n", + regs->ar.bspstore, regs->ar.bsp, rbs_size, cfm_sof); + + for (i = 0; i < cfm_sof; i++) { + int off = cfm_sof - i; + unsigned int rbs_off = + (((62 - ((rbs_size + regs->rbs_voff) % 64) + off)) / 63) + off; + if (rbs_off > rbs_size) + break; + printf (" r%02d: %016lx%s", 32 + i, + regs->rbs[rbs_size - rbs_off], + (i % 3) != 2 ? " " : "\n"); + } + if ((i % 3) != 0) + printf ("\n"); + + printf ("\n"); + printf (" r1: %016lx ", regs->r[1]); + printf (" r2: %016lx ", regs->r[2]); + printf (" r3: %016lx\n", regs->r[3]); + printf (" r4: %016lx ", regs->r[4]); + printf (" r5: %016lx ", regs->r[5]); + printf (" r6: %016lx\n", regs->r[6]); + printf (" r7: %016lx ", regs->r[7]); + printf (" r8: %016lx ", regs->r[8]); + printf (" r9: %016lx\n", regs->r[9]); + printf (" r10: %016lx ", regs->r[10]); + printf (" r11: %016lx ", regs->r[11]); + printf (" sp: %016lx\n", regs->r[12]); + printf (" tp: %016lx ", regs->r[13]); + printf (" r14: %016lx ", regs->r[14]); + printf (" r15: %016lx\n", regs->r[15]); + printf (" r16: %016lx ", regs->r[16]); + printf (" r17: %016lx ", regs->r[17]); + printf (" r18: %016lx\n", regs->r[18]); + printf (" r19: %016lx ", regs->r[19]); + printf (" r20: %016lx ", regs->r[20]); + printf (" r21: %016lx\n", regs->r[21]); + printf (" r22: %016lx ", regs->r[22]); + printf (" r23: %016lx ", regs->r[23]); + printf (" r24: %016lx\n", regs->r[24]); + printf (" r25: %016lx ", regs->r[25]); + printf (" r26: %016lx ", regs->r[26]); + printf (" r27: %016lx\n", regs->r[27]); + printf (" r28: %016lx ", regs->r[28]); + printf (" r29: %016lx ", regs->r[29]); + printf (" r30: %016lx\n", regs->r[30]); + printf (" r31: %016lx ", regs->r[31]); + printf (" "); + printf (" b0: %016lx\n", regs->b[0]); + + printf ("\n"); + printf (" psr: %016lx ", regs->psr); + printf (" cfm: %016lx ", regs->cfm); + printf (" pr: %016lx\n", regs->pr); + + printf ("\n"); + printf (" ip: %016lx+%d", regs->ip, (int)(regs->psr >> PSR_RI_SHIFT) & 3); + printf ("\n"); + target_disas (stdout, regs->ip, 16); +} + +void print_br (vcpu_guest_context_t *ctx) +{ + struct vcpu_guest_context_regs *regs = &ctx->regs; + + printf (" b0: %016lx ", regs->b[0]); + printf (" b1: %016lx ", regs->b[1]); + printf (" b2: %016lx\n", regs->b[2]); + printf (" b3: %016lx ", regs->b[3]); + printf (" b4: %016lx ", regs->b[4]); + printf (" b5: %016lx\n", regs->b[5]); + printf (" b6: %016lx ", regs->b[6]); + printf (" b7: %016lx\n", regs->b[7]); +} + +void print_regs (vcpu_guest_context_t *ctx) +{ + struct vcpu_guest_context_regs *regs = &ctx->regs; + + printf (" r1: %016lx ", regs->r[1]); + printf (" r2: %016lx ", regs->r[2]); + printf (" r3: %016lx\n", regs->r[3]); + printf (" r4: %016lx ", regs->r[4]); + printf (" r5: %016lx ", regs->r[5]); + printf (" r6: %016lx\n", regs->r[6]); + printf (" r7: %016lx ", regs->r[7]); + printf (" r8: %016lx ", regs->r[8]); + printf (" r9: %016lx\n", regs->r[9]); + printf (" r10: %016lx ", regs->r[10]); + printf (" r11: %016lx ", regs->r[11]); + printf (" sp: %016lx\n", regs->r[12]); + printf (" tp: %016lx ", regs->r[13]); + printf (" r14: %016lx ", regs->r[14]); + printf (" r15: %016lx\n", regs->r[15]); + + printf (" Bank %d (current) Bank %d\n", + (regs->psr & PSR_BN) ? 1 : 0, (regs->psr & PSR_BN) ? 0 : 1); + printf ("16:%016lx ", regs->r[16]); + printf ("17:%016lx ", regs->r[17]); + printf ("16:%016lx ", regs->bank[0]); + printf ("17:%016lx\n", regs->bank[1]); + printf ("18:%016lx ", regs->r[18]); + printf ("19:%016lx ", regs->r[19]); + printf ("18:%016lx ", regs->bank[2]); + printf ("19:%016lx\n", regs->bank[3]); + printf ("20:%016lx ", regs->r[20]); + printf ("21:%016lx ", regs->r[21]); + printf ("20:%016lx ", regs->bank[4]); + printf ("21:%016lx\n", regs->bank[5]); + printf ("22:%016lx ", regs->r[22]); + printf ("23:%016lx ", regs->r[23]); + printf ("22:%016lx ", regs->bank[6]); + printf ("23:%016lx\n", regs->bank[7]); + printf ("24:%016lx ", regs->r[24]); + printf ("25:%016lx ", regs->r[25]); + printf ("24:%016lx ", regs->bank[8]); + printf ("25:%016lx\n", regs->bank[9]); + printf ("26:%016lx ", regs->r[26]); + printf ("27:%016lx ", regs->r[27]); + printf ("26:%016lx ", regs->bank[10]); + printf ("27:%016lx\n", regs->bank[11]); + printf ("28:%016lx ", regs->r[28]); + printf ("29:%016lx ", regs->r[29]); + printf ("28:%016lx ", regs->bank[12]); + printf ("29:%016lx\n", regs->bank[13]); + printf ("30:%016lx ", regs->r[30]); + printf ("31:%016lx ", regs->r[31]); + printf ("30:%016lx ", regs->bank[14]); + printf ("31:%016lx\n", regs->bank[15]); + printf ("\n"); +} + +void print_cr (vcpu_guest_context_t *ctx) +{ + struct vcpu_guest_context_regs *regs = &ctx->regs; + + printf (" dcr: %016lx ", regs->cr.dcr); + printf (" itm: %016lx ", regs->cr.itm); + printf (" iva: %016lx\n", regs->cr.iva); + printf (" pta: %016lx ", regs->cr.pta); + printf (" ipsr: %016lx ", regs->cr.ipsr); + printf (" isr: %016lx\n", regs->cr.isr); + printf (" iip: %016lx ", regs->cr.iip); + printf (" ifa: %016lx ", regs->cr.ifa); + printf (" itir: %016lx\n", regs->cr.itir); + printf (" iipa: %016lx ", regs->cr.iipa); + printf (" ifs: %016lx ", regs->cr.ifs); + printf (" iim: %016lx\n", regs->cr.iim); + printf (" iha: %016lx ", regs->cr.iha); + printf (" lid: %016lx ", regs->cr.lid); + printf (" ivr: %016lx\n", regs->cr.ivr); + printf (" tpr: %016lx ", regs->cr.tpr); + printf (" eoi: %016lx ", regs->cr.eoi); + printf (" irr0: %016lx\n", regs->cr.irr[0]); + printf (" irr1: %016lx ", regs->cr.irr[1]); + printf (" irr2: %016lx ", regs->cr.irr[2]); + printf (" irr3: %016lx\n", regs->cr.irr[3]); + printf (" itv: %016lx ", regs->cr.itv); + printf (" pmv: %016lx ", regs->cr.pmv); + printf (" cmcv: %016lx\n", regs->cr.cmcv); + printf (" lrr0: %016lx ", regs->cr.lrr0); + printf (" lrr1: %016lx ", regs->cr.lrr1); + printf (" ev_cb:%016lx\n", ctx->event_callback_ip); +} + +void print_ar (vcpu_guest_context_t *ctx) +{ + struct vcpu_guest_context_regs *regs = &ctx->regs; + + printf (" kr0: %016lx ", regs->ar.kr[0]); + printf (" kr1: %016lx ", regs->ar.kr[1]); + printf (" kr2: %016lx\n", regs->ar.kr[2]); + printf (" kr3: %016lx ", regs->ar.kr[3]); + printf (" kr4: %016lx ", regs->ar.kr[4]); + printf (" kr5: %016lx\n", regs->ar.kr[5]); + printf (" kr6: %016lx ", regs->ar.kr[6]); + printf (" kr7: %016lx ", regs->ar.kr[7]); + printf (" rsc: %016lx\n", regs->ar.rsc); + printf (" bsp: %016lx ", regs->ar.bsp); + printf (" bsps: %016lx ", regs->ar.bspstore); + printf (" rnat: %016lx\n", regs->ar.rnat); + printf (" csd: %016lx ", regs->ar.csd); + printf (" ccv: %016lx ", regs->ar.ccv); + printf (" unat: %016lx\n", regs->ar.unat); + printf (" fpsr: %016lx ", regs->ar.fpsr); + printf (" itc: %016lx\n", regs->ar.itc); + printf (" pfs: %016lx ", regs->ar.pfs); + printf (" lc: %016lx ", regs->ar.lc); + printf (" ec: %016lx\n", regs->ar.ec); +} + +void print_a_rr (int num, unsigned long rr) +{ + int ps_val = (rr >> RR_PS_SHIFT) & RR_PS_MASK; + + printf (" [%d] %06lx %02x %s %ld\n", + num, (rr >> RR_RID_SHIFT) & RR_RID_MASK, + ps_val, get_ps (ps_val), rr & RR_VE_MASK); +} + +void print_rr (vcpu_guest_context_t *ctx) +{ + struct vcpu_guest_context_regs *regs = &ctx->regs; + int i; + + printf (" rr: rid ps ve\n"); + for (i = 0; i < 8; i++) + print_a_rr (i, regs->rr[i]); +} + +void print_db (vcpu_guest_context_t *ctx) +{ + struct vcpu_guest_context_regs *regs = &ctx->regs; + int i; + + for (i = 0; i < 7; i += 2) + printf (" ibr[%d]: %016lx ibr[%d]: %016lx\n", + i, regs->ibr[i], i + 1, regs->ibr[i + 1]); + printf ("\n"); + for (i = 0; i < 7; i += 2) + printf (" dbr[%d]: %016lx dbr[%d]: %016lx\n", + i, regs->dbr[i], i + 1, regs->dbr[i + 1]); +} + +struct bit_descr { + const char *name; + unsigned char sz; +}; + +const struct bit_descr psr_bits[] = + { + {"", 1 }, {"be", 1 }, {"up", 1 }, {"ac", 1 }, + {"mfl", 1 }, {"mfh", 1 }, {"", 7 }, + {"ic", 1 }, {"i", 1 }, {"pk", 1 }, + {"", 1 }, {"dt", 1 }, {"dfl", 1 }, {"dfh", 1 }, + {"sp", 1 }, {"pp", 1 }, {"di", 1 }, {"si", 1 }, + {"db", 1 }, {"lp", 1 }, {"tb", 1 }, {"rt", 1 }, + {"", 4 }, + {"cpl", 2 }, {"is", 1 }, {"mc", 1 }, + {"it", 1 }, {"id", 1 }, {"da", 1 }, {"dd", 1 }, + {"ss", 1 }, {"ri", 2 }, {"ed", 1 }, + {"bn", 1 }, {"ia", 1 }, {"vm", 1 }, + {NULL, 0 } + }; + +void print_bits (const struct bit_descr *desc, unsigned long val) +{ + const struct bit_descr *d; + unsigned int off; + + /* Reverse order. */ + for (d = desc, off = 0; d->name; d++) + off += d->sz; + + d--; + + while (1) { + off -= d->sz; + if (*d->name) { + if (d->sz != 1 || ((val >> off) & 1)) + printf (" %s", d->name); + if (d->sz != 1) + printf ("=%lx", (val >> off) & ((1 << d->sz) - 1)); + } + if (d == desc) + break; + d--; + } +} + +void print_tr (vcpu_guest_context_t *ctx) +{ + struct vcpu_tr_regs *tr = &ctx->regs.tr; + int i; + + printf ("\n itr: P rid va pa ps ed pl " + "ar a d ma key\n"); + + for (i = 0; i < 8; i++) + print_a_tr (i, &tr->itrs[i]); + + printf ("\n dtr: P rid va pa ps ed pl " + "ar a d ma key\n"); + + for (i = 0; i < 8; i++) + print_a_tr (i, &tr->dtrs[i]); +} + +int lock_pages (void *addr, size_t len); +void unlock_pages (void *addr, size_t len); +int do_xen_hypercall (int xc_handle, privcmd_hypercall_t *hypercall); + +#ifdef HAVE_DEBUG_OP +static int do_ia64_debug_op (int xc_handle, + unsigned long cmd, unsigned long domain, + xen_ia64_debug_op_t *op) +{ + int ret = -1; + privcmd_hypercall_t hypercall; + + hypercall.op = __HYPERVISOR_ia64_debug_op; + hypercall.arg[0] = cmd; + hypercall.arg[1] = domain; + hypercall.arg[2] = (unsigned long)op; + + if (lock_pages (op, sizeof (*op)) != 0) { + perror ("Could not lock memory for Xen hypercall"); + goto out1; + } + + ret = do_xen_hypercall (xc_handle, &hypercall); + if (ret < 0) { + if (errno == EACCES) + fprintf (stderr,"domctl operation failed -- need to " + "rebuild the user-space tool set?\n"); + } + + unlock_pages (op, sizeof (*op)); + +out1: + return ret; +} +#endif + +static volatile int ctrl_c_hit; + +void ctrl_c_handler (int sig) +{ + fflush (stdout); + ctrl_c_hit = 1; +} + +int wait_domain (int vcpu, vcpu_guest_context_t *ctx) +{ + struct timespec ts; + xc_dominfo_t dominfo; + int ret; + int cnt = 0; + + ts.tv_sec = 0; + ts.tv_nsec = 10*1000*1000; + + ret = xc_domain_unpause (xc_handle, domid); + if (ret < 0) + perror ("xc_domain_unpause"); + + ctrl_c_hit = 0; + + while (1) { + ret = xc_domain_getinfo (xc_handle, domid, 1, &dominfo); + if (ret < 0) + perror ("xc_domain_getinfo"); + + if (dominfo.paused) + break; + + if (ctrl_c_hit) { + /* Force pause. */ + ret = xc_domain_pause (xc_handle, domid); + if (ret < 0) + perror ("xc_domain_pause"); + + break; + } + + printf ("%c\b", "/-\\|"[(cnt++) % 4]); + fflush (stdout); + nanosleep (&ts, NULL); + } + return xc_vcpu_getcontext (xc_handle, domid, vcpu, ctx); +} + +int virt_to_phys (int is_inst, unsigned long vaddr, unsigned long *paddr) +{ + struct ia64_tr_entry *tr; + int i; + + /* Search in tr. */ + if (is_inst) + tr = cur_ctx->regs.tr.itrs; + else + tr = cur_ctx->regs.tr.dtrs; + for (i = 0; i < 8; i++, tr++) { + int ps_val = (tr->itir >> ITIR_PS_SHIFT) & ITIR_PS_MASK; + unsigned long ps_mask = (-1L) << ps_val; + + if ((tr->vadr & ps_mask) == (vaddr & ps_mask)) { + *paddr = ((tr->pte & (PTE_PPN_MASK << PTE_PPN_SHIFT)) & ps_mask) | + (vaddr & ~ps_mask); + return 0; + } + } + return -1; +} + +unsigned long * +get_reg_addr (const char *name) +{ + if (strcmp (name, "ip") == 0) + return &cur_ctx->regs.ip; + else if (strcmp (name, "psr") == 0) + return &cur_ctx->regs.psr; + else + return 0; +} + +enum prio_expr {EXPR_BASE, EXPR_SUM, EXPR_LOGIC, EXPR_PROD}; + +int parse_expr (unsigned char **buf, unsigned long *res, enum prio_expr prio); + +int next_char (unsigned char **buf) +{ + unsigned char *b; + + b = *buf; + while (isspace (*b)) + b++; + *buf = b; + return *b; +} + +int parse_unary (unsigned char **buf, unsigned long *res) +{ + unsigned char c; + + c = next_char (buf); + switch (c) { + case '0' ... '9': + { + char *e; + *res = strtoul (*buf, &e, 0); + if (e == (char *)*buf) { + printf ("bad literal\n"); + return -1; + } + *buf = e; + } + break; + case '+': + (*buf)++; + return parse_unary (buf, res); + case '$': + { + unsigned char *b; + unsigned char *e; + unsigned char c; + unsigned long *reg; + int len; + + b = *buf; + e = b + 1; + + while ((*e >= 'a' && *e <= 'z') || + (*e >= 'A' && *e <= 'Z') || + (*e >= '0' && *e <= '9') || + (*e == '_' || *e == '.')) + e++; + + if (b == e) { + printf ("identifier missing after '$'\n"); + return -1; + } + + b++; + len = e - b; + + c = b[len]; + b[len] = 0; + reg = get_reg_addr (b); + b[len] = c; + + if (reg != NULL) + *res = *reg; + else if (strncmp (b, "d2p", len) == 0 || + strncmp (b, "i2p", len) == 0) { + unsigned long vaddr; + + *buf = e; + if (parse_unary (buf, &vaddr) != 0) + return -1; + if (virt_to_phys (*b == 'i', vaddr, res) != 0) { + printf ("cannot find vaddr %016lx in tr\n", vaddr); + return -1; + } + return 0; + } + else { + printf ("unknown symbol\n"); + return -1; + } + *buf = e; + } + break; + case '(': + (*buf)++; + if (parse_expr (buf, res, EXPR_BASE) != 0) + return -1; + + if (next_char (buf) != ')') { + printf ("missing ')'\n"); + return -1; + } + else + (*buf)++; + break; + default: + printf ("unknown operand '%c' in expression\n", c); + return -1; + } + + return 0; +} + +int parse_expr (unsigned char **buf, unsigned long *res, enum prio_expr prio) +{ + unsigned long val = 0; + unsigned long val1; + + if (parse_unary (buf, &val) != 0) + return -1; + + while (1) { + switch (next_char (buf)) { + case '+': + if (prio > EXPR_SUM) + return 0; + + (*buf)++; + if (parse_expr (buf, &val1, EXPR_SUM) < 0) + return -1; + + val += val1; + break; + case '*': + if (prio > EXPR_PROD) + return 0; + + (*buf)++; + if (parse_expr (buf, &val1, EXPR_SUM) < 0) + return -1; + + val *= val1; + break; + default: + *res = val; + return 0; + } + } +} + +unsigned char *parse_arg (unsigned char **buf) +{ + unsigned char *res; + unsigned char *b = *buf; + + /* Eat leading spaces. */ + while (isspace (*b)) + b++; + + res = b; + while (*b && !isspace (*b)) + b++; + + /* Set the NUL terminator. */ + if (*b) + *b++ = 0; + + *buf = b; + return res; +} + +vcpu_guest_context_t vcpu_ctx[1]; + +int vcpu_setcontext (int vcpu) +{ + int ret; + + ret = xc_vcpu_setcontext (xc_handle, domid, vcpu, &vcpu_ctx[vcpu]); + if (ret < 0) + perror ("xc_vcpu_setcontext"); + + return ret; +} + +struct command_desc +{ + const char *name; + const char *help; + int (*cmd)(unsigned char *line); +}; + +static int +cmd_registers (unsigned char *line) +{ + print_ctx (cur_ctx); + return 0; +} + +static int +cmd_sstep (unsigned char *line) +{ + if ((cur_ctx->regs.psr & (PSR_SS | PSR_TB)) != PSR_SS) { + cur_ctx->regs.psr |= PSR_SS; + cur_ctx->regs.psr &= ~PSR_TB; + if (vcpu_setcontext (cur_vcpu) < 0) + return -1; + } + + if (wait_domain (cur_vcpu, cur_ctx) < 0) { + perror ("wait_domain"); + return -1; + } + + print_ctx (cur_ctx); + + return 0; +} + +static int +cmd_go (unsigned char *line) +{ + if ((cur_ctx->regs.psr & (PSR_SS | PSR_TB | PSR_DB)) != 0) { + cur_ctx->regs.psr &= ~(PSR_SS | PSR_TB); + cur_ctx->regs.psr |= PSR_DD | PSR_ID; + if (vcpu_setcontext (cur_vcpu) < 0) + return -1; + } + + if (wait_domain (cur_vcpu, cur_ctx) < 0) { + perror ("wait_domain"); + return -1; + } + + print_ctx (cur_ctx); + + return 0; +} + +static int +cmd_cb (unsigned char *line) +{ + if ((cur_ctx->regs.psr & (PSR_SS | PSR_TB)) != PSR_TB) { + cur_ctx->regs.psr &= ~PSR_SS; + cur_ctx->regs.psr |= PSR_TB; + if (vcpu_setcontext (cur_vcpu) < 0) + return -1; + } + + if (wait_domain (cur_vcpu, cur_ctx) < 0) { + perror ("wait_domain"); + return -1; + } + + print_ctx (cur_ctx); + + return 0; +} + +static int +cmd_quit (unsigned char *line) +{ + return -2; +} + +static int +cmd_echo (unsigned char *line) +{ + printf ("%s", line); + return 0; +} + +static int +cmd_disassemble (unsigned char *args) +{ + static unsigned long addr; + + if (*args != 0) + if (parse_expr (&args, &addr, 0) < 0) + return -1; + + target_disas (stdout, addr, 16); + addr += 16; + + return 0; +} + +static int +cmd_break (unsigned char *args) +{ + unsigned long addr; + int i; + + for (i = 0; i < 4; i++) + if (cur_ctx->regs.ibr[2 * i] == 0 && cur_ctx->regs.ibr[2 * i + 1] == 0) + break; + + if (i == 4) { + printf ("no availabe break points\n"); + return -1; + } + + if (parse_expr (&args, &addr, 0) < 0) + return -1; + + cur_ctx->regs.ibr[2 * i] = addr; + cur_ctx->regs.ibr[2 * i + 1] = 0x87fffffffffffff0UL; + cur_ctx->regs.psr |= PSR_DB; + + return vcpu_setcontext (cur_vcpu); +} + +static int +cmd_watch (unsigned char *args) +{ + unsigned long addr; + unsigned long mask; + int i; + + for (i = 0; i < 4; i++) + if (cur_ctx->regs.dbr[2 * i] == 0 && cur_ctx->regs.dbr[2 * i + 1] == 0) + break; + + if (i == 4) { + printf ("no availabe watch points\n"); + return -1; + } + + if (parse_expr (&args, &addr, 0) < 0) + return -1; + + if (parse_expr (&args, &mask, 0) < 0) + mask = 3; + + cur_ctx->regs.dbr[2 * i] = addr; + cur_ctx->regs.dbr[2 * i + 1] = ~((1UL << mask) - 1) | (0xc7UL << 56); + cur_ctx->regs.psr |= PSR_DB; + + return vcpu_setcontext (cur_vcpu); +} + +static int +cmd_delete (unsigned char *args) +{ + unsigned long num; + + if (parse_expr (&args, &num, 0) < 0) + return -1; + + if (num < 4) { + cur_ctx->regs.ibr[2 * num] = 0; + cur_ctx->regs.ibr[2 * num + 1] = 0; + } + else if (num < 8) { + num -= 4; + cur_ctx->regs.dbr[2 * num] = 0; + cur_ctx->regs.dbr[2 * num + 1] = 0; + } + else { + printf ("breakpoint out of range\n"); + return -1; + } + + cur_ctx->regs.psr |= PSR_DB; + + return vcpu_setcontext (cur_vcpu); +} + +static int +cmd_disable (unsigned char *args) +{ + unsigned long num; + + if (parse_expr (&args, &num, 0) < 0) + return -1; + + if (num >= 4) { + printf ("breakpoint out of range\n"); + return -1; + } + + cur_ctx->regs.ibr[2 * num + 1] &= ~(1UL << 63); + + return vcpu_setcontext (cur_vcpu); +} + +static int +cmd_enable (unsigned char *args) +{ + unsigned long num; + + if (parse_expr (&args, &num, 0) < 0) + return -1; + + if (num >= 4) { + printf ("breakpoint out of range\n"); + return -1; + } + + cur_ctx->regs.ibr[2 * num + 1] |= 1UL << 63; + + return vcpu_setcontext (cur_vcpu); +} + +static int +cmd_print (unsigned char *args) +{ + unsigned long addr; + + if (parse_expr (&args, &addr, 0) < 0) + return -1; + + printf ("res: 0x%016lx = %ld\n", addr, addr); + + return 0; +} + +struct bit_xlat { + unsigned int bit; + const char *name; +}; + +static const struct bit_xlat debug_flags[] = { + { XEN_IA64_DEBUG_ON_KERN_SSTEP, "sstep" }, + { XEN_IA64_DEBUG_ON_KERN_DEBUG, "debug" }, + { XEN_IA64_DEBUG_ON_KERN_TBRANCH, "tbranch" }, + { XEN_IA64_DEBUG_ON_EXTINT, "extint" }, + { XEN_IA64_DEBUG_ON_EXCEPT, "except" }, + { XEN_IA64_DEBUG_ON_EVENT, "event" }, + { XEN_IA64_DEBUG_ON_PRIVOP, "privop" }, + { XEN_IA64_DEBUG_ON_PAL, "pal" }, + { XEN_IA64_DEBUG_ON_SAL, "sal" }, + { XEN_IA64_DEBUG_ON_EFI, "efi" }, + { XEN_IA64_DEBUG_ON_RFI, "rfi" }, + { XEN_IA64_DEBUG_ON_MMU, "mmu" }, + { XEN_IA64_DEBUG_ON_BAD_MPA, "mpa" }, + { XEN_IA64_DEBUG_FORCE_SS, "ss" }, + { XEN_IA64_DEBUG_FORCE_DB, "db" }, + { XEN_IA64_DEBUG_ON_TR, "tr" }, + { XEN_IA64_DEBUG_ON_TC, "tc" }, + { 0, NULL } +}; + +static int +cmd_disp (unsigned char *arg) +{ + if (strcmp (arg, "br") == 0) + print_br (cur_ctx); + else if (strcmp (arg, "regs") == 0) + print_regs (cur_ctx); + else if (strcmp (arg, "cr") == 0) + print_cr (cur_ctx); + else if (strcmp (arg, "ar") == 0) + print_ar (cur_ctx); + else if (strcmp (arg, "tr") == 0) + print_tr (cur_ctx); + else if (strcmp (arg, "rr") == 0) + print_rr (cur_ctx); + else if (strcmp (arg, "db") == 0) + print_db (cur_ctx); + else if (strcmp (arg, "psr") == 0) { + printf ("psr:"); + print_bits (psr_bits, cur_ctx->regs.psr); + printf ("\n"); + } + else if (strcmp (arg, "ipsr") == 0) { + printf ("ipsr:"); + print_bits (psr_bits, cur_ctx->regs.cr.ipsr); + printf ("\n"); + } + else if (strcmp (arg, "break") == 0) { + int i; + + for (i = 0; i < 4; i++) + if (cur_ctx->regs.ibr[2 * i + 1]) + printf ("%d: 0x%016lx %s\n", i, cur_ctx->regs.ibr[2 * i], + (cur_ctx->regs.ibr[2 * i + 1] & (1UL << 63)) ? + "enabled" : "disabled"); + } + else if (strcmp (arg, "domain") == 0) { + xc_dominfo_t dominfo; +#ifdef HAVE_DEBUG_OP + xen_ia64_debug_op_t debug_op; + int i; +#endif + if (xc_domain_getinfo (xc_handle, domid, 1, &dominfo) < 0) { + perror ("xc_domain_getinfo"); + return 0; + } + + printf ("id=%d nr_pages=%lu shared_info_frame=%lu max_mem=%luKB\n", + dominfo.domid, dominfo.nr_pages, dominfo.shared_info_frame, + dominfo.max_memkb); + printf (" nr_online_vcpu=%u max_vcpu_id=%u\n", + dominfo.nr_online_vcpus, dominfo.max_vcpu_id); + printf (" status:"); + if (dominfo.dying) + printf (" dying"); + if (dominfo.crashed) + printf (" crashed"); + if (dominfo.shutdown) + printf (" shutdown(%u)", dominfo.shutdown_reason); + if (dominfo.paused) + printf (" paused"); + if (dominfo.blocked) + printf (" blocked"); + if (dominfo.running) + printf (" running"); + if (dominfo.hvm) + printf (" hvm"); + printf ("\n"); + +#ifdef HAVE_DEBUG_OP + if (do_ia64_debug_op (xc_handle, XEN_IA64_DEBUG_OP_GET_FLAGS, + domid, &debug_op) < 0) { + perror ("xc_domain_getinfo"); + return 0; + } + printf ("debug flags: %08lx: ", debug_op.flags); + for (i = 0; debug_flags[i].name; i++) + if (debug_flags[i].bit & debug_op.flags) + printf (" %s", debug_flags[i].name); + printf ("\n"); +#endif + } + else if (*arg == 0) + printf ("choose among br, regs, cr, ar, tr, rr, dbg\n"); + else + printf ("cannot disp '%s'\n", arg); + return 0; +} + +static int +cmd_bev (unsigned char *arg) +{ + xen_ia64_debug_op_t debug_op; + int i; + + if (do_ia64_debug_op (xc_handle, XEN_IA64_DEBUG_OP_GET_FLAGS, + domid, &debug_op) < 0) { + perror ("get debug flags"); + return 0; + } + if (arg == NULL || arg[0] == 0) { + printf ("debug flags: %08lx:\n", debug_op.flags); + for (i = 0; debug_flags[i].name; i++) + printf (" %c%s\n", + (debug_flags[i].bit & debug_op.flags) ? '+' : '-', + debug_flags[i].name); + return 0; + } + else { + char *p = strtok (arg, " "); + + while (p != NULL) { + unsigned int flag = 0; + + for (i = 0; debug_flags[i].name; i++) + if (strcmp (p, debug_flags[i].name) == 0 + || ((p[0] == '-' || p[0] == '+') + && strcmp (p + 1, debug_flags[i].name) == 0)) { + flag = debug_flags[i].bit; + break; + } + if (flag == 0) { + printf ("unknown event %s\n", p); + return 0; + } + if (p[0] == '-') + debug_op.flags &= ~flag; + else + debug_op.flags |= flag; + + p = strtok (NULL, " "); + } + if (do_ia64_debug_op (xc_handle, XEN_IA64_DEBUG_OP_SET_FLAGS, + domid, &debug_op) < 0) { + perror ("set debug flags"); + return -1; + } + /* Disabling force_SS and force_DB requires setting psr. */ + return vcpu_setcontext (cur_vcpu); + } +} + +static int +cmd_set (unsigned char *line) +{ + unsigned char *reg; + unsigned long *addr; + unsigned long val; + + reg = parse_arg (&line); + + addr = get_reg_addr (reg); + if (addr == NULL) { + printf ("unknown register %s\n", reg); + return -1; + } + + if (parse_expr (&line, &val, 0) < 0) + return -1; + + *addr = val; + + return vcpu_setcontext (cur_vcpu); +} + +const struct command_desc commands[]; + +static int +cmd_help (unsigned char *line) +{ + int i; + + for (i = 0; commands[i].name; i++) + printf ("%s -- %s\n", commands[i].name, commands[i].help); + + return 0; +} + +const struct command_desc commands[] = { + { "registers", "display current registers", cmd_registers }, + { "sstep", "single step", cmd_sstep }, + { "go", "resume execution", cmd_go }, + { "quit", "quit debugger", cmd_quit }, + { "echo", "display parameters", cmd_echo }, + { "disassemble", "disassemble memory", cmd_disassemble }, + { "break", "set a break point", cmd_break }, + { "watch", "set a watch point", cmd_watch }, + { "cb", "resume until branch", cmd_cb }, + { "delete", "delete a break point", cmd_delete }, + { "disable", "disable a break point", cmd_disable }, + { "enable", "enable a break point", cmd_enable }, + { "print", "print an expression", cmd_print }, + { "disp", "disp br/regs/cr/ar/tr/rr/db/psr/break/domain", cmd_disp}, + { "bev", "break on event", cmd_bev}, + { "set", "set reg val", cmd_set}, + { "help", "disp help", cmd_help }, + { NULL, NULL } +}; + + +int do_command (int vcpu, unsigned char *line) +{ + unsigned char *cmd; + unsigned char *args; + int i; + const struct command_desc *desc; + int flag_ambiguous; + + cur_vcpu = vcpu; + cur_ctx = &vcpu_ctx[vcpu]; + + cmd = parse_arg (&line); + args = line; + + desc = NULL; + flag_ambiguous = 0; + + for (i = 0; commands[i].name; i++) { + const char *n = commands[i].name; + unsigned char *c = cmd; + + while (*n == *c && *n) + n++, c++; + + if (*c == 0) { + /* Match. */ + if (desc != NULL) { + if (!flag_ambiguous) + printf ("ambiguous command: %s", desc->name); + printf (", %s", commands[i].name); + flag_ambiguous = 1; + } + else + desc = &commands[i]; + } + } + + if (flag_ambiguous) { + printf ("\n"); + return -3; + } + else if (!desc) { + printf ("command not found, try help\n"); + return -3; + } + + return (*desc->cmd)(args); +} + +void xenitp (int vcpu) +{ + int ret; + xc_dominfo_t dominfo; + struct sigaction sa; + + cur_ctx = &vcpu_ctx[vcpu]; + + xc_handle = xc_interface_open (); /* for accessing control interface */ + + ret = xc_domain_getinfo (xc_handle, domid, 1, &dominfo); + if (ret < 0) { + perror ("xc_domain_getinfo"); + exit (-1); + } + + if (xc_domain_setdebugging (xc_handle, domid, 1) != 0) + perror ("setdebugging"); + + ret = xc_domain_pause (xc_handle, domid); + if (ret < 0) { + perror ("xc_domain_pause"); + exit (-1); + } + + ret = xc_vcpu_getcontext (xc_handle, domid, vcpu, cur_ctx); + if (ret < 0) { + if (!dominfo.paused) + xc_domain_unpause (xc_handle, domid); + perror ("xc_vcpu_getcontext"); + exit (-1); + } + + print_ctx (cur_ctx); + + /* Catch ctrl-c. */ + sa.sa_handler = &ctrl_c_handler; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + if (sigaction (SIGINT, &sa, NULL) != 0) + perror ("sigaction"); + + while (1) { + unsigned char buf[128]; + int len; + + printf ("XenITP> "); + + if (fgets (buf, sizeof (buf), stdin) == NULL) + break; + + len = strlen (buf); + if (len > 1 && buf[len - 1] == '\n') + buf[len - 1] = 0; + + ret = do_command (vcpu, buf); + if (ret == -2) + break; + } + + /* Clear debug bits. */ + if ((cur_ctx->regs.psr & (PSR_SS | PSR_TB | PSR_DB)) != 0) { + cur_ctx->regs.psr &= ~(PSR_SS | PSR_TB | PSR_DB); + cur_ctx->regs.psr |= PSR_DD | PSR_ID; + vcpu_setcontext (cur_vcpu); + } + + /* Disable debugging. */ + if (xc_domain_setdebugging (xc_handle, domid, 0) != 0) + perror ("setdebugging"); + + if (!dominfo.paused) { + ret = xc_domain_unpause (xc_handle, domid); + if (ret < 0) { + perror ("xc_domain_unpause"); + exit (-1); + } + } + + xc_interface_close (xc_handle); + if (ret < 0) { + perror ("xc_interface_close"); + exit (-1); + } +} + +static void usage (void) +{ + printf ("usage:\n"); + printf (" xenitp <DOMAIN> [VCPU]\n"); + +} + +int main (int argc, char **argv) +{ + int ch; + static const char *sopts = "h" + ; + static const struct option lopts[] = { + {"help", 0, NULL, 'h'}, + {0, 0, 0, 0} + }; + int vcpu = 0; + + while ((ch = getopt_long (argc, argv, sopts, lopts, NULL)) != -1) { + switch (ch) { + case 'h': + usage (); + exit (-1); + case '?': + fprintf (stderr, "%s --help for more options\n", argv[0]); + exit (-1); + } + } + + argv += optind; + argc -= optind; + + if (argc < 1 || argc > 2) { + usage (); + exit (-1); + } + + domid = atoi (argv[0]); + if (domid == 0) { + fprintf (stderr, "cannot trace dom0\n"); + exit (-1); + } + + if (argc == 2) + vcpu = atoi (argv[1]); + + xenitp (vcpu); + + return 0; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ |