direct-io.hg

changeset 8435:8d5d4d58407f

Add support to xenctx for printing stack traces on x86_32 and x86_64.

To support this add xc_translate_foreign_address to libxc. This function
walks page tables and translates virtual addresses using a given domain
and vcpu page table.

Signed-off-by: Ian Campbell <Ian.Campbell@XenSource.com>
author Ian.Campbell@xensource.com
date Thu Dec 22 14:33:19 2005 +0000 (2005-12-22)
parents 934470721c46
children c9184cc4d1d1
files tools/libxc/Makefile tools/libxc/xc_pagetab.c tools/libxc/xenctrl.h tools/xentrace/Makefile tools/xentrace/xenctx.c
line diff
     1.1 --- a/tools/libxc/Makefile	Wed Dec 21 20:18:19 2005 +0100
     1.2 +++ b/tools/libxc/Makefile	Thu Dec 22 14:33:19 2005 +0000
     1.3 @@ -27,6 +27,11 @@ SRCS       += xc_tbuf.c
     1.4  ifeq ($(XEN_TARGET_ARCH),x86_32)
     1.5  SRCS       += xc_ptrace.c
     1.6  SRCS       += xc_ptrace_core.c
     1.7 +SRCS       += xc_pagetab.c
     1.8 +endif
     1.9 +
    1.10 +ifeq ($(XEN_TARGET_ARCH),x86_64)
    1.11 +SRCS       += xc_pagetab.c
    1.12  endif
    1.13  
    1.14  BUILD_SRCS :=
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/libxc/xc_pagetab.c	Thu Dec 22 14:33:19 2005 +0000
     2.3 @@ -0,0 +1,192 @@
     2.4 +/******************************************************************************
     2.5 + * xc_pagetab.c
     2.6 + *
     2.7 + * Function to translate virtual to physical addresses.
     2.8 + */
     2.9 +#include "xc_private.h"
    2.10 +
    2.11 +#if defined(__i386__)
    2.12 +
    2.13 +#define L1_PAGETABLE_SHIFT_PAE	12
    2.14 +#define L2_PAGETABLE_SHIFT_PAE	21
    2.15 +#define L3_PAGETABLE_SHIFT_PAE	30
    2.16 +
    2.17 +#define L1_PAGETABLE_SHIFT		12
    2.18 +#define L2_PAGETABLE_SHIFT		22
    2.19 +
    2.20 +#define L0_PAGETABLE_MASK_PAE	0x0000000ffffff000ULL
    2.21 +#define L1_PAGETABLE_MASK_PAE	0x1ffULL
    2.22 +#define L2_PAGETABLE_MASK_PAE	0x1ffULL
    2.23 +#define L3_PAGETABLE_MASK_PAE	0x3ULL
    2.24 +
    2.25 +#define L0_PAGETABLE_MASK		0xfffff000ULL
    2.26 +#define L1_PAGETABLE_MASK		0x3ffULL
    2.27 +#define L2_PAGETABLE_MASK		0x3ffULL
    2.28 +
    2.29 +#elif defined(__x86_64__)
    2.30 +
    2.31 +#define L1_PAGETABLE_SHIFT_PAE	12
    2.32 +#define L2_PAGETABLE_SHIFT_PAE	21
    2.33 +#define L3_PAGETABLE_SHIFT_PAE	30
    2.34 +#define L4_PAGETABLE_SHIFT_PAE	39
    2.35 +
    2.36 +#define L1_PAGETABLE_SHIFT		L1_PAGETABLE_SHIFT_PAE
    2.37 +#define L2_PAGETABLE_SHIFT		L2_PAGETABLE_SHIFT_PAE
    2.38 +
    2.39 +#define L0_PAGETABLE_MASK_PAE	0x000000fffffff000ULL
    2.40 +#define L1_PAGETABLE_MASK_PAE	0x1ffULL
    2.41 +#define L2_PAGETABLE_MASK_PAE	0x1ffULL
    2.42 +#define L3_PAGETABLE_MASK_PAE	0x1ffULL
    2.43 +#define L4_PAGETABLE_MASK_PAE	0x1ffULL
    2.44 +
    2.45 +#define L0_PAGETABLE_MASK		L0_PAGETABLE_MASK_PAE
    2.46 +#define L1_PAGETABLE_MASK		L1_PAGETABLE_MASK_PAE
    2.47 +#define L2_PAGETABLE_MASK		L2_PAGETABLE_MASK_PAE
    2.48 +
    2.49 +#endif
    2.50 +
    2.51 +unsigned long xc_translate_foreign_address(int xc_handle, uint32_t dom,
    2.52 +                                           int vcpu, unsigned long long virt )
    2.53 +{
    2.54 +    vcpu_guest_context_t ctx;
    2.55 +    unsigned long long cr3;
    2.56 +    void *pd, *pt, *pdppage = NULL, *pdp, *pml = NULL;
    2.57 +    unsigned long long pde, pte, pdpe, pmle;
    2.58 +    unsigned long mfn = 0;
    2.59 +#if defined (__i386__)
    2.60 +    static int pt_levels = 0;
    2.61 +
    2.62 +    if (pt_levels == 0) {
    2.63 +        xen_capabilities_info_t xen_caps = "";
    2.64 +
    2.65 +        if (xc_version(xc_handle, XENVER_capabilities, &xen_caps) != 0)
    2.66 +            goto out;
    2.67 +        if (strstr(xen_caps, "xen-3.0-x86_64"))
    2.68 +            pt_levels = 4;
    2.69 +        else if (strstr(xen_caps, "xen-3.0-x86_32p"))
    2.70 +            pt_levels = 3;
    2.71 +        else if (strstr(xen_caps, "xen-3.0-x86_32"))
    2.72 +            pt_levels = 2;
    2.73 +        else
    2.74 +            goto out;
    2.75 +    }
    2.76 +#elif defined (__x86_64__)
    2.77 +#define pt_levels 4
    2.78 +#endif
    2.79 +
    2.80 +    if (xc_domain_get_vcpu_context(xc_handle, dom, vcpu, &ctx) != 0) {
    2.81 +        fprintf(stderr, "failed to retreive vcpu context\n");
    2.82 +        goto out;
    2.83 +    }
    2.84 +    cr3 = ctx.ctrlreg[3];
    2.85 +
    2.86 +    /* Page Map Level 4 */
    2.87 +
    2.88 +#if defined(__i386__)
    2.89 +    pmle = cr3;
    2.90 +#elif defined(__x86_64__)
    2.91 +    pml = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, cr3 >> PAGE_SHIFT);
    2.92 +    if (pml == NULL) {
    2.93 +        fprintf(stderr, "failed to map PML4\n");
    2.94 +        goto out;
    2.95 +    }
    2.96 +    pmle = *(unsigned long long *)(pml + 8 * ((virt >> L4_PAGETABLE_SHIFT_PAE) & L4_PAGETABLE_MASK_PAE));
    2.97 +    if((pmle & 1) == 0) {
    2.98 +        fprintf(stderr, "page entry not present in PML4\n");
    2.99 +        goto out_unmap_pml;
   2.100 +    }
   2.101 +#endif
   2.102 +
   2.103 +    /* Page Directory Pointer Table */
   2.104 +
   2.105 +    if (pt_levels >= 3) {
   2.106 +        pdppage = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, pmle >> PAGE_SHIFT);
   2.107 +        if (pdppage == NULL) {
   2.108 +            fprintf(stderr, "failed to map PDP\n");
   2.109 +            goto out_unmap_pml;
   2.110 +        }
   2.111 +        if (pt_levels >= 4)
   2.112 +            pdp = pdppage;
   2.113 +        else
   2.114 +            /* PDP is only 32 bit aligned with 3 level pts */
   2.115 +            pdp = pdppage + (pmle & ~(XC_PAGE_MASK | 0x1f));
   2.116 +
   2.117 +        pdpe = *(unsigned long long *)(pdp + 8 * ((virt >> L3_PAGETABLE_SHIFT_PAE) & L3_PAGETABLE_MASK_PAE));
   2.118 +
   2.119 +        if((pdpe & 1) == 0) {
   2.120 +            fprintf(stderr, "page entry not present in PDP\n");
   2.121 +            goto out_unmap_pdp;
   2.122 +        }
   2.123 +    } else {
   2.124 +        pdpe = pmle;
   2.125 +    }
   2.126 +
   2.127 +    /* Page Directory */
   2.128 +
   2.129 +    pd = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, pdpe >> PAGE_SHIFT);
   2.130 +    if (pd == NULL) {
   2.131 +        fprintf(stderr, "failed to map PD\n");
   2.132 +        goto out_unmap_pdp;
   2.133 +    }
   2.134 +
   2.135 +    if (pt_levels >= 3)
   2.136 +        pde = *(unsigned long long *)(pd + 8 * ((virt >> L2_PAGETABLE_SHIFT_PAE) & L2_PAGETABLE_MASK_PAE));
   2.137 +    else
   2.138 +        pde = *(unsigned long long *)(pd + 4 * ((virt >> L2_PAGETABLE_SHIFT) & L2_PAGETABLE_MASK));
   2.139 +
   2.140 +    if ((pde & 1) == 0) {
   2.141 +        fprintf(stderr, "page entry not present in PD\n");
   2.142 +        goto out_unmap_pd;
   2.143 +    }
   2.144 +
   2.145 +    /* Page Table */
   2.146 +
   2.147 +    if (pde & 0x00000008) { /* 4M page (or 2M in PAE mode) */
   2.148 +        fprintf(stderr, "Cannot currently cope with 2/4M pages\n");
   2.149 +        exit(-1);
   2.150 +    } else { /* 4k page */
   2.151 +        pt = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ,
   2.152 +                                  pde >> PAGE_SHIFT);
   2.153 +
   2.154 +        if (pt == NULL) {
   2.155 +            fprintf(stderr, "failed to map PT\n");
   2.156 +            goto out_unmap_pd;
   2.157 +        }
   2.158 +
   2.159 +        if (pt_levels >= 3)
   2.160 +            pte = *(unsigned long long *)(pt + 8 * ((virt >> L1_PAGETABLE_SHIFT_PAE) & L1_PAGETABLE_MASK_PAE));
   2.161 +        else
   2.162 +            pte = *(unsigned long long *)(pt + 4 * ((virt >> L1_PAGETABLE_SHIFT) & L1_PAGETABLE_MASK));
   2.163 +
   2.164 +        if ((pte & 0x00000001) == 0) {
   2.165 +            fprintf(stderr, "page entry not present in PT\n");
   2.166 +            goto out_unmap_pt;
   2.167 +        }
   2.168 +
   2.169 +        if (pt_levels >= 3)
   2.170 +            mfn = (pte & L0_PAGETABLE_MASK_PAE) >> PAGE_SHIFT;
   2.171 +        else
   2.172 +            mfn = (pte & L0_PAGETABLE_MASK) >> PAGE_SHIFT;
   2.173 +    }
   2.174 +
   2.175 + out_unmap_pt:
   2.176 +    munmap(pt, PAGE_SIZE);
   2.177 + out_unmap_pd:
   2.178 +    munmap(pd, PAGE_SIZE);
   2.179 + out_unmap_pdp:
   2.180 +    munmap(pdppage, PAGE_SIZE);
   2.181 + out_unmap_pml:
   2.182 +    munmap(pml, PAGE_SIZE);
   2.183 + out:
   2.184 +    return mfn;
   2.185 +}
   2.186 +
   2.187 +/*
   2.188 + * Local variables:
   2.189 + * mode: C
   2.190 + * c-set-style: "BSD"
   2.191 + * c-basic-offset: 4
   2.192 + * tab-width: 4
   2.193 + * indent-tabs-mode: nil
   2.194 + * End:
   2.195 + */
     3.1 --- a/tools/libxc/xenctrl.h	Wed Dec 21 20:18:19 2005 +0100
     3.2 +++ b/tools/libxc/xenctrl.h	Thu Dec 22 14:33:19 2005 +0000
     3.3 @@ -416,6 +416,19 @@ void *xc_map_foreign_range(int xc_handle
     3.4  void *xc_map_foreign_batch(int xc_handle, uint32_t dom, int prot,
     3.5                             unsigned long *arr, int num );
     3.6  
     3.7 +/**
     3.8 + * Translates a virtual address in the context of a given domain and
     3.9 + * vcpu returning the machine page frame number of the associated
    3.10 + * page.
    3.11 + *
    3.12 + * @parm xc_handle a handle on an open hypervisor interface
    3.13 + * @parm dom the domain to perform the translation in
    3.14 + * @parm vcpu the vcpu to perform the translation on
    3.15 + * @parm virt the virtual address to translate
    3.16 + */
    3.17 +unsigned long xc_translate_foreign_address(int xc_handle, uint32_t dom,
    3.18 +					   int vcpu, unsigned long long virt);
    3.19 +
    3.20  int xc_get_pfn_list(int xc_handle, uint32_t domid, unsigned long *pfn_buf, 
    3.21                      unsigned long max_pfns);
    3.22  
     4.1 --- a/tools/xentrace/Makefile	Wed Dec 21 20:18:19 2005 +0100
     4.2 +++ b/tools/xentrace/Makefile	Thu Dec 22 14:33:19 2005 +0000
     4.3 @@ -15,25 +15,29 @@ HDRS     = $(wildcard *.h)
     4.4  OBJS     = $(patsubst %.c,%.o,$(wildcard *.c))
     4.5  
     4.6  BIN      = xentrace tbctl setsize
     4.7 +LIBBIN   = xenctx
     4.8  SCRIPTS  = xentrace_format
     4.9  MAN1     = $(wildcard *.1)
    4.10  MAN8     = $(wildcard *.8)
    4.11  
    4.12  all: build
    4.13 -build: $(BIN)
    4.14 +build: $(BIN) $(LIBBIN)
    4.15  
    4.16  install: build
    4.17  	[ -d $(DESTDIR)/usr/bin ] || $(INSTALL_DIR) $(DESTDIR)/usr/bin
    4.18 +	[ -d $(DESTDIR)/usr/$(LIBDIR)/xen/bin ] || \
    4.19 +		$(INSTALL_DIR) $(DESTDIR)/usr/$(LIBDIR)/xen/bin
    4.20  	[ -d $(DESTDIR)/usr/share/man/man1 ] || \
    4.21  		$(INSTALL_DIR) $(DESTDIR)/usr/share/man/man1
    4.22  	[ -d $(DESTDIR)/usr/share/man/man8 ] || \
    4.23  		$(INSTALL_DIR) $(DESTDIR)/usr/share/man/man8
    4.24  	$(INSTALL_PROG) $(BIN) $(SCRIPTS) $(DESTDIR)/usr/bin
    4.25 +	$(INSTALL_PROG) $(LIBBIN) $(DESTDIR)/usr/$(LIBDIR)/xen/bin
    4.26  	$(INSTALL_DATA) $(MAN1) $(DESTDIR)/usr/share/man/man1
    4.27  	$(INSTALL_DATA) $(MAN8) $(DESTDIR)/usr/share/man/man8
    4.28  
    4.29  clean:
    4.30 -	$(RM) *.a *.so *.o *.rpm $(BIN)
    4.31 +	$(RM) *.a *.so *.o *.rpm $(BIN) $(LIBBIN)
    4.32  
    4.33  %: %.c $(HDRS) Makefile
    4.34  	$(CC) $(CFLAGS) -o $@ $< -L$(XEN_LIBXC) -lxenctrl
     5.1 --- a/tools/xentrace/xenctx.c	Wed Dec 21 20:18:19 2005 +0100
     5.2 +++ b/tools/xentrace/xenctx.c	Thu Dec 22 14:33:19 2005 +0000
     5.3 @@ -20,15 +20,184 @@
     5.4  #include <errno.h>
     5.5  #include <argp.h>
     5.6  #include <signal.h>
     5.7 +#include <string.h>
     5.8 +#include <getopt.h>
     5.9  
    5.10  #include "xenctrl.h"
    5.11  
    5.12 +int xc_handle = 0;
    5.13 +int domid = 0;
    5.14 +int frame_ptrs = 0;
    5.15 +int stack_trace = 0;
    5.16 +
    5.17 +#if defined (__i386__)
    5.18 +#define FMT_SIZE_T		"%08x"
    5.19 +#define STACK_POINTER(regs)	(regs->esp)
    5.20 +#define FRAME_POINTER(regs)	(regs->ebp)
    5.21 +#define INSTR_POINTER(regs)	(regs->eip)
    5.22 +#define STACK_ROWS		4
    5.23 +#define STACK_COLS		8
    5.24 +#elif defined (__x86_64__)
    5.25 +#define FMT_SIZE_T		"%016lx"
    5.26 +#define STACK_POINTER(regs)	(regs->rsp)
    5.27 +#define FRAME_POINTER(regs)	(regs->rbp)
    5.28 +#define INSTR_POINTER(regs)	(regs->rip)
    5.29 +#define STACK_ROWS		4
    5.30 +#define STACK_COLS		4
    5.31 +#endif
    5.32 +
    5.33 +struct symbol {
    5.34 +    size_t address;
    5.35 +    char type;
    5.36 +    char *name;
    5.37 +    struct symbol *next;
    5.38 +} *symbol_table = NULL;
    5.39 +
    5.40 +size_t kernel_stext, kernel_etext, kernel_sinittext, kernel_einittext;
    5.41 +
    5.42 +int is_kernel_text(size_t addr)
    5.43 +{
    5.44 +#if defined (__i386__)
    5.45 +    if (symbol_table == NULL)
    5.46 +        return (addr > 0xc000000);
    5.47 +#elif defined (__x86_64__)
    5.48 +    if (symbol_table == NULL)
    5.49 +        return (addr > 0xffffffff80000000UL);
    5.50 +#endif
    5.51 +
    5.52 +    if (addr >= kernel_stext &&
    5.53 +        addr <= kernel_etext)
    5.54 +        return 1;
    5.55 +    if (addr >= kernel_sinittext &&
    5.56 +        addr <= kernel_einittext)
    5.57 +        return 1;
    5.58 +    return 0;
    5.59 +}
    5.60 +
    5.61 +void free_symbol(struct symbol *symbol)
    5.62 +{
    5.63 +    if (symbol == NULL)
    5.64 +        return;
    5.65 +    if (symbol->name)
    5.66 +        free(symbol->name);
    5.67 +    free(symbol);
    5.68 +}
    5.69 +
    5.70 +void insert_symbol(struct symbol *symbol)
    5.71 +{
    5.72 +    static struct symbol *prev = NULL;
    5.73 +    struct symbol *s = symbol_table;
    5.74 +
    5.75 +    if (s == NULL) {
    5.76 +        symbol_table = symbol;
    5.77 +        symbol->next = NULL;
    5.78 +        return;
    5.79 +    }
    5.80 +
    5.81 +    /* The System.map is usually already sorted... */
    5.82 +    if (prev
    5.83 +        && prev->address < symbol->address
    5.84 +        && (!prev->next || prev->next->address > symbol->address)) {
    5.85 +        s = prev;
    5.86 +    } else {
    5.87 +        /* ... otherwise do crappy/slow search for the correct place */
    5.88 +        while(s && s->next && s->next->address < symbol->address)
    5.89 +            s = s->next;
    5.90 +    }
    5.91 +
    5.92 +    symbol->next = s->next;
    5.93 +    s->next = symbol;
    5.94 +    prev = symbol;
    5.95 +}
    5.96 +
    5.97 +struct symbol *lookup_symbol(size_t address)
    5.98 +{
    5.99 +    struct symbol *s = symbol_table;
   5.100 +
   5.101 +    while(s && s->next && s->next->address < address)
   5.102 +        s = s->next;
   5.103 +
   5.104 +    if (s && s->address < address)
   5.105 +        return s;
   5.106 +
   5.107 +    return NULL;
   5.108 +}
   5.109 +
   5.110 +void print_symbol(size_t addr)
   5.111 +{
   5.112 +    struct symbol *s;
   5.113 +
   5.114 +    if (!is_kernel_text(addr))
   5.115 +        return;
   5.116 +
   5.117 +    s = lookup_symbol(addr);
   5.118 +
   5.119 +    if (s==NULL)
   5.120 +        return;
   5.121 +
   5.122 +    if (addr==s->address)
   5.123 +        printf("%s", s->name);
   5.124 +    else
   5.125 +        printf("%s+%#x", s->name, (unsigned int)(addr - s->address));
   5.126 +}
   5.127 +
   5.128 +void read_symbol_table(const char *symtab)
   5.129 +{
   5.130 +    char line[256];
   5.131 +    char *p;
   5.132 +    struct symbol *symbol;
   5.133 +    FILE *f;
   5.134 +
   5.135 +    f = fopen(symtab, "r");
   5.136 +    if(f == NULL) {
   5.137 +        fprintf(stderr, "failed to open symbol table %s\n", symtab);
   5.138 +        exit(-1);
   5.139 +    }
   5.140 +
   5.141 +    while(!feof(f)) {
   5.142 +        if(fgets(line,256,f)==NULL)
   5.143 +            break;
   5.144 +
   5.145 +        symbol = malloc(sizeof(*symbol));
   5.146 +
   5.147 +        /* need more checks for syntax here... */
   5.148 +        symbol->address = strtoull(line, &p, 16);
   5.149 +        p++;
   5.150 +        symbol->type = *p++;
   5.151 +        p++;
   5.152 +
   5.153 +        /* in the future we should handle the module name
   5.154 +         * being appended here, this would allow us to use
   5.155 +         * /proc/kallsyms as our symbol table
   5.156 +         */
   5.157 +        if (p[strlen(p)-1] == '\n')
   5.158 +            p[strlen(p)-1] = '\0';
   5.159 +        symbol->name = strdup(p);
   5.160 +
   5.161 +        insert_symbol(symbol);
   5.162 +
   5.163 +        if (strcmp(symbol->name, "_stext") == 0)
   5.164 +            kernel_stext = symbol->address;
   5.165 +        else if (strcmp(symbol->name, "_etext") == 0)
   5.166 +            kernel_etext = symbol->address;
   5.167 +        else if (strcmp(symbol->name, "_sinittext") == 0)
   5.168 +            kernel_sinittext = symbol->address;
   5.169 +        else if (strcmp(symbol->name, "_einittext") == 0)
   5.170 +            kernel_einittext = symbol->address;
   5.171 +    }
   5.172 +
   5.173 +    fclose(f);
   5.174 +}
   5.175 +
   5.176  #ifdef __i386__
   5.177  void print_ctx(vcpu_guest_context_t *ctx1)
   5.178  {
   5.179      struct cpu_user_regs *regs = &ctx1->user_regs;
   5.180  
   5.181 -    printf("eip: %08x\t", regs->eip);
   5.182 +    printf("eip: %08x ", regs->eip);
   5.183 +    print_symbol(regs->eip);
   5.184 +    printf("\n");
   5.185 +
   5.186      printf("esp: %08x\n", regs->esp);
   5.187  
   5.188      printf("eax: %08x\t", regs->eax);
   5.189 @@ -51,7 +220,9 @@ void print_ctx(vcpu_guest_context_t *ctx
   5.190  {
   5.191      struct cpu_user_regs *regs = &ctx1->user_regs;
   5.192  
   5.193 -    printf("rip: %08lx\t", regs->rip);
   5.194 +    printf("rip: %08lx ", regs->rip);
   5.195 +    print_symbol(regs->rip);
   5.196 +    printf("\n");
   5.197      printf("rsp: %08lx\n", regs->rsp);
   5.198  
   5.199      printf("rax: %08lx\t", regs->rax);
   5.200 @@ -63,8 +234,8 @@ void print_ctx(vcpu_guest_context_t *ctx
   5.201      printf("rdi: %08lx\t", regs->rdi);
   5.202      printf("rbp: %08lx\n", regs->rbp);
   5.203  
   5.204 -    printf("r8: %08lx\t", regs->r8);
   5.205 -    printf("r9: %08lx\t", regs->r9);
   5.206 +    printf(" r8: %08lx\t", regs->r8);
   5.207 +    printf(" r9: %08lx\t", regs->r9);
   5.208      printf("r10: %08lx\t", regs->r10);
   5.209      printf("r11: %08lx\n", regs->r11);
   5.210  
   5.211 @@ -81,35 +252,238 @@ void print_ctx(vcpu_guest_context_t *ctx
   5.212  }
   5.213  #endif
   5.214  
   5.215 -void dump_ctx(uint32_t domid, uint32_t vcpu)
   5.216 +void *map_page(vcpu_guest_context_t *ctx, int vcpu, size_t virt)
   5.217 +{
   5.218 +    static unsigned long previous_mfn = 0;
   5.219 +    static void *mapped = NULL;
   5.220 +
   5.221 +    unsigned long mfn = xc_translate_foreign_address(xc_handle, domid, vcpu, virt);
   5.222 +    unsigned long offset = virt & ~XC_PAGE_MASK;
   5.223 +
   5.224 +    if (mapped && mfn == previous_mfn)
   5.225 +        goto out;
   5.226 +
   5.227 +    if (mapped)
   5.228 +        munmap(mapped, XC_PAGE_SIZE);
   5.229 +
   5.230 +    previous_mfn = mfn;
   5.231 +
   5.232 +    mapped = xc_map_foreign_range(xc_handle, domid, XC_PAGE_SIZE, PROT_READ, mfn);
   5.233 +
   5.234 +    if (mapped == NULL) {
   5.235 +        fprintf(stderr, "failed to map page.\n");
   5.236 +        exit(-1);
   5.237 +    }
   5.238 +
   5.239 + out:
   5.240 +    return (void *)(mapped + offset);
   5.241 +}
   5.242 +
   5.243 +void print_stack(vcpu_guest_context_t *ctx, int vcpu)
   5.244 +{
   5.245 +    struct cpu_user_regs *regs = &ctx->user_regs;
   5.246 +    size_t stack = STACK_POINTER(regs);
   5.247 +    size_t stack_limit = (STACK_POINTER(regs) & XC_PAGE_MASK) + XC_PAGE_SIZE;
   5.248 +    size_t frame;
   5.249 +    size_t instr;
   5.250 +    size_t *p;
   5.251 +    int i;
   5.252 +
   5.253 +    printf("\n");
   5.254 +    printf("Stack:\n");
   5.255 +    for (i=1; i<STACK_ROWS+1 && stack < stack_limit; i++) {
   5.256 +        while(stack < stack_limit && stack < STACK_POINTER(regs) + i*STACK_COLS*sizeof(stack)) {
   5.257 +            p = map_page(ctx, vcpu, stack);
   5.258 +            printf(" " FMT_SIZE_T, *p);
   5.259 +            stack += sizeof(stack);
   5.260 +        }
   5.261 +        printf("\n");
   5.262 +    }
   5.263 +    printf("\n");
   5.264 +
   5.265 +    printf("Code:\n");
   5.266 +    instr = INSTR_POINTER(regs) - 21;
   5.267 +    for(i=0; i<32; i++) {
   5.268 +        unsigned char *c = map_page(ctx, vcpu, instr+i);
   5.269 +        if (instr+i == INSTR_POINTER(regs))
   5.270 +            printf("<%02x> ", *c);
   5.271 +        else
   5.272 +            printf("%02x ", *c);
   5.273 +    }
   5.274 +    printf("\n");
   5.275 +
   5.276 +    printf("\n");
   5.277 +
   5.278 +    if(stack_trace)
   5.279 +        printf("Stack Trace:\n");
   5.280 +    else
   5.281 +        printf("Call Trace:\n");
   5.282 +    printf("%c [<" FMT_SIZE_T ">] ", stack_trace ? '*' : ' ', INSTR_POINTER(regs));
   5.283 +
   5.284 +    print_symbol(INSTR_POINTER(regs));
   5.285 +    printf(" <--\n");
   5.286 +    if (frame_ptrs) {
   5.287 +        stack = STACK_POINTER(regs);
   5.288 +        frame = FRAME_POINTER(regs);
   5.289 +        while(frame && stack < stack_limit) {
   5.290 +            if (stack_trace) {
   5.291 +                while (stack < frame) {
   5.292 +                    p = map_page(ctx, vcpu, stack);
   5.293 +                    printf("|   " FMT_SIZE_T "   ", *p);
   5.294 +                    printf("\n");
   5.295 +                    stack += sizeof(*p);
   5.296 +                }
   5.297 +            } else {
   5.298 +                stack = frame;
   5.299 +            }
   5.300 +
   5.301 +            p = map_page(ctx, vcpu, stack);
   5.302 +            frame = *p;
   5.303 +            if (stack_trace)
   5.304 +                printf("|-- " FMT_SIZE_T "\n", *p);
   5.305 +            stack += sizeof(*p);
   5.306 +
   5.307 +            if (frame) {
   5.308 +                p = map_page(ctx, vcpu, stack);
   5.309 +                printf("%c [<" FMT_SIZE_T ">] ", stack_trace ? '|' : ' ', *p);
   5.310 +                print_symbol(*p);
   5.311 +                printf("\n");
   5.312 +                stack += sizeof(*p);
   5.313 +            }
   5.314 +        }
   5.315 +    } else {
   5.316 +        stack = STACK_POINTER(regs);
   5.317 +        while(stack < stack_limit) {
   5.318 +            p = map_page(ctx, vcpu, stack);
   5.319 +            if (is_kernel_text(*p)) {
   5.320 +                printf("  [<" FMT_SIZE_T ">] ", *p);
   5.321 +                print_symbol(*p);
   5.322 +                printf("\n");
   5.323 +            } else if (stack_trace) {
   5.324 +                printf("    " FMT_SIZE_T "\n", *p);
   5.325 +            }
   5.326 +            stack += sizeof(*p);
   5.327 +        }
   5.328 +    }
   5.329 +}
   5.330 +
   5.331 +void dump_ctx(int vcpu)
   5.332  {
   5.333      int ret;
   5.334      vcpu_guest_context_t ctx;
   5.335  
   5.336 -    int xc_handle = xc_interface_open(); /* for accessing control interface */
   5.337 +    xc_handle = xc_interface_open(); /* for accessing control interface */
   5.338 +
   5.339 +    ret = xc_domain_pause(xc_handle, domid);
   5.340 +    if (ret < 0) {
   5.341 +        perror("xc_domain_pause");
   5.342 +        exit(-1);
   5.343 +    }
   5.344  
   5.345      ret = xc_domain_get_vcpu_context(xc_handle, domid, vcpu, &ctx);
   5.346 -    if (ret != 0) {
   5.347 +    if (ret < 0) {
   5.348 +        xc_domain_unpause(xc_handle, domid);
   5.349          perror("xc_domain_get_vcpu_context");
   5.350          exit(-1);
   5.351      }
   5.352 +
   5.353      print_ctx(&ctx);
   5.354 +    if (is_kernel_text(ctx.user_regs.eip))
   5.355 +        print_stack(&ctx, vcpu);
   5.356 +
   5.357 +    ret = xc_domain_unpause(xc_handle, domid);
   5.358 +    if (ret < 0) {
   5.359 +        perror("xc_domain_unpause");
   5.360 +        exit(-1);
   5.361 +    }
   5.362 +
   5.363      xc_interface_close(xc_handle);
   5.364 +    if (ret < 0) {
   5.365 +        perror("xc_interface_close");
   5.366 +        exit(-1);
   5.367 +    }
   5.368 +}
   5.369 +
   5.370 +void usage(void)
   5.371 +{
   5.372 +    printf("usage:\n\n");
   5.373 +
   5.374 +    printf("  xenctx [options] <DOMAIN> [VCPU]\n\n");
   5.375 +
   5.376 +    printf("options:\n");
   5.377 +    printf("  -f, --frame-pointers\n");
   5.378 +    printf("                    assume the kernel was compiled with\n");
   5.379 +    printf("                    frame pointers.\n");
   5.380 +    printf("  -s SYMTAB, --symbol-table=SYMTAB\n");
   5.381 +    printf("                    read symbol table from SYMTAB.\n");
   5.382 +    printf("  --stack-trace     print a complete stack trace.\n");
   5.383  }
   5.384  
   5.385  int main(int argc, char **argv)
   5.386  {
   5.387 +    int ch;
   5.388 +    const char *sopts = "fs:h";
   5.389 +    const struct option lopts[] = {
   5.390 +        {"stack-trace", 0, NULL, 'S'},
   5.391 +        {"symbol-table", 1, NULL, 's'},
   5.392 +        {"frame-pointers", 0, NULL, 'f'},
   5.393 +        {"help", 0, NULL, 'h'},
   5.394 +        {0, 0, 0, 0}
   5.395 +    };
   5.396 +    const char *symbol_table = NULL;
   5.397 +
   5.398      int vcpu = 0;
   5.399  
   5.400 -    if (argc < 2) {
   5.401 -        printf("usage: xenctx <domid> <optional vcpu>\n");
   5.402 +    while ((ch = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
   5.403 +        switch(ch) {
   5.404 +        case 'f':
   5.405 +            frame_ptrs = 1;
   5.406 +            break;
   5.407 +        case 's':
   5.408 +            symbol_table = optarg;
   5.409 +            break;
   5.410 +        case 'S':
   5.411 +            stack_trace = 1;
   5.412 +            break;
   5.413 +        case 'h':
   5.414 +            usage();
   5.415 +            exit(-1);
   5.416 +        case '?':
   5.417 +            fprintf(stderr, "%s --help for more options\n", argv[0]);
   5.418 +            exit(-1);
   5.419 +        }
   5.420 +    }
   5.421 +
   5.422 +    argv += optind; argc -= optind;
   5.423 +
   5.424 +    if (argc < 1 || argc > 2) {
   5.425 +        printf("usage: xenctx [options] <domid> <optional vcpu>\n");
   5.426          exit(-1);
   5.427      }
   5.428  
   5.429 -    if (argc == 3)
   5.430 -        vcpu = atoi(argv[2]);
   5.431 +    domid = atoi(argv[0]);
   5.432 +    if (domid==0) {
   5.433 +            fprintf(stderr, "cannot trace dom0\n");
   5.434 +            exit(-1);
   5.435 +    }
   5.436  
   5.437 -    dump_ctx(atoi(argv[1]), vcpu);
   5.438 +    if (argc == 2)
   5.439 +        vcpu = atoi(argv[1]);
   5.440 +
   5.441 +    if (symbol_table)
   5.442 +        read_symbol_table(symbol_table);
   5.443 +
   5.444 +    dump_ctx(vcpu);
   5.445  
   5.446      return 0;
   5.447  }
   5.448 +
   5.449 +/*
   5.450 + * Local variables:
   5.451 + * mode: C
   5.452 + * c-set-style: "BSD"
   5.453 + * c-basic-offset: 4
   5.454 + * tab-width: 4
   5.455 + * indent-tabs-mode: nil
   5.456 + * End:
   5.457 + */