mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
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>
This commit is contained in:
1 parent
4f27f31a47
commit
40924689a9
5 files changed
+602
-14
No files matched your search
@@ -27,6 +27,11 @@ SRCS += xc_tbuf.c
|
||||
ifeq ($(XEN_TARGET_ARCH),x86_32)
|
||||
SRCS += xc_ptrace.c
|
||||
SRCS += xc_ptrace_core.c
|
||||
SRCS += xc_pagetab.c
|
||||
endif
|
||||
|
||||
ifeq ($(XEN_TARGET_ARCH),x86_64)
|
||||
SRCS += xc_pagetab.c
|
||||
endif
|
||||
|
||||
BUILD_SRCS :=
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
/******************************************************************************
|
||||
* xc_pagetab.c
|
||||
*
|
||||
* Function to translate virtual to physical addresses.
|
||||
*/
|
||||
#include "xc_private.h"
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
#define L1_PAGETABLE_SHIFT_PAE 12
|
||||
#define L2_PAGETABLE_SHIFT_PAE 21
|
||||
#define L3_PAGETABLE_SHIFT_PAE 30
|
||||
|
||||
#define L1_PAGETABLE_SHIFT 12
|
||||
#define L2_PAGETABLE_SHIFT 22
|
||||
|
||||
#define L0_PAGETABLE_MASK_PAE 0x0000000ffffff000ULL
|
||||
#define L1_PAGETABLE_MASK_PAE 0x1ffULL
|
||||
#define L2_PAGETABLE_MASK_PAE 0x1ffULL
|
||||
#define L3_PAGETABLE_MASK_PAE 0x3ULL
|
||||
|
||||
#define L0_PAGETABLE_MASK 0xfffff000ULL
|
||||
#define L1_PAGETABLE_MASK 0x3ffULL
|
||||
#define L2_PAGETABLE_MASK 0x3ffULL
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
#define L1_PAGETABLE_SHIFT_PAE 12
|
||||
#define L2_PAGETABLE_SHIFT_PAE 21
|
||||
#define L3_PAGETABLE_SHIFT_PAE 30
|
||||
#define L4_PAGETABLE_SHIFT_PAE 39
|
||||
|
||||
#define L1_PAGETABLE_SHIFT L1_PAGETABLE_SHIFT_PAE
|
||||
#define L2_PAGETABLE_SHIFT L2_PAGETABLE_SHIFT_PAE
|
||||
|
||||
#define L0_PAGETABLE_MASK_PAE 0x000000fffffff000ULL
|
||||
#define L1_PAGETABLE_MASK_PAE 0x1ffULL
|
||||
#define L2_PAGETABLE_MASK_PAE 0x1ffULL
|
||||
#define L3_PAGETABLE_MASK_PAE 0x1ffULL
|
||||
#define L4_PAGETABLE_MASK_PAE 0x1ffULL
|
||||
|
||||
#define L0_PAGETABLE_MASK L0_PAGETABLE_MASK_PAE
|
||||
#define L1_PAGETABLE_MASK L1_PAGETABLE_MASK_PAE
|
||||
#define L2_PAGETABLE_MASK L2_PAGETABLE_MASK_PAE
|
||||
|
||||
#endif
|
||||
|
||||
unsigned long xc_translate_foreign_address(int xc_handle, uint32_t dom,
|
||||
int vcpu, unsigned long long virt )
|
||||
{
|
||||
vcpu_guest_context_t ctx;
|
||||
unsigned long long cr3;
|
||||
void *pd, *pt, *pdppage = NULL, *pdp, *pml = NULL;
|
||||
unsigned long long pde, pte, pdpe, pmle;
|
||||
unsigned long mfn = 0;
|
||||
#if defined (__i386__)
|
||||
static int pt_levels = 0;
|
||||
|
||||
if (pt_levels == 0) {
|
||||
xen_capabilities_info_t xen_caps = "";
|
||||
|
||||
if (xc_version(xc_handle, XENVER_capabilities, &xen_caps) != 0)
|
||||
goto out;
|
||||
if (strstr(xen_caps, "xen-3.0-x86_64"))
|
||||
pt_levels = 4;
|
||||
else if (strstr(xen_caps, "xen-3.0-x86_32p"))
|
||||
pt_levels = 3;
|
||||
else if (strstr(xen_caps, "xen-3.0-x86_32"))
|
||||
pt_levels = 2;
|
||||
else
|
||||
goto out;
|
||||
}
|
||||
#elif defined (__x86_64__)
|
||||
#define pt_levels 4
|
||||
#endif
|
||||
|
||||
if (xc_domain_get_vcpu_context(xc_handle, dom, vcpu, &ctx) != 0) {
|
||||
fprintf(stderr, "failed to retreive vcpu context\n");
|
||||
goto out;
|
||||
}
|
||||
cr3 = ctx.ctrlreg[3];
|
||||
|
||||
/* Page Map Level 4 */
|
||||
|
||||
#if defined(__i386__)
|
||||
pmle = cr3;
|
||||
#elif defined(__x86_64__)
|
||||
pml = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, cr3 >> PAGE_SHIFT);
|
||||
if (pml == NULL) {
|
||||
fprintf(stderr, "failed to map PML4\n");
|
||||
goto out;
|
||||
}
|
||||
pmle = *(unsigned long long *)(pml + 8 * ((virt >> L4_PAGETABLE_SHIFT_PAE) & L4_PAGETABLE_MASK_PAE));
|
||||
if((pmle & 1) == 0) {
|
||||
fprintf(stderr, "page entry not present in PML4\n");
|
||||
goto out_unmap_pml;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Page Directory Pointer Table */
|
||||
|
||||
if (pt_levels >= 3) {
|
||||
pdppage = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, pmle >> PAGE_SHIFT);
|
||||
if (pdppage == NULL) {
|
||||
fprintf(stderr, "failed to map PDP\n");
|
||||
goto out_unmap_pml;
|
||||
}
|
||||
if (pt_levels >= 4)
|
||||
pdp = pdppage;
|
||||
else
|
||||
/* PDP is only 32 bit aligned with 3 level pts */
|
||||
pdp = pdppage + (pmle & ~(XC_PAGE_MASK | 0x1f));
|
||||
|
||||
pdpe = *(unsigned long long *)(pdp + 8 * ((virt >> L3_PAGETABLE_SHIFT_PAE) & L3_PAGETABLE_MASK_PAE));
|
||||
|
||||
if((pdpe & 1) == 0) {
|
||||
fprintf(stderr, "page entry not present in PDP\n");
|
||||
goto out_unmap_pdp;
|
||||
}
|
||||
} else {
|
||||
pdpe = pmle;
|
||||
}
|
||||
|
||||
/* Page Directory */
|
||||
|
||||
pd = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, pdpe >> PAGE_SHIFT);
|
||||
if (pd == NULL) {
|
||||
fprintf(stderr, "failed to map PD\n");
|
||||
goto out_unmap_pdp;
|
||||
}
|
||||
|
||||
if (pt_levels >= 3)
|
||||
pde = *(unsigned long long *)(pd + 8 * ((virt >> L2_PAGETABLE_SHIFT_PAE) & L2_PAGETABLE_MASK_PAE));
|
||||
else
|
||||
pde = *(unsigned long long *)(pd + 4 * ((virt >> L2_PAGETABLE_SHIFT) & L2_PAGETABLE_MASK));
|
||||
|
||||
if ((pde & 1) == 0) {
|
||||
fprintf(stderr, "page entry not present in PD\n");
|
||||
goto out_unmap_pd;
|
||||
}
|
||||
|
||||
/* Page Table */
|
||||
|
||||
if (pde & 0x00000008) { /* 4M page (or 2M in PAE mode) */
|
||||
fprintf(stderr, "Cannot currently cope with 2/4M pages\n");
|
||||
exit(-1);
|
||||
} else { /* 4k page */
|
||||
pt = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ,
|
||||
pde >> PAGE_SHIFT);
|
||||
|
||||
if (pt == NULL) {
|
||||
fprintf(stderr, "failed to map PT\n");
|
||||
goto out_unmap_pd;
|
||||
}
|
||||
|
||||
if (pt_levels >= 3)
|
||||
pte = *(unsigned long long *)(pt + 8 * ((virt >> L1_PAGETABLE_SHIFT_PAE) & L1_PAGETABLE_MASK_PAE));
|
||||
else
|
||||
pte = *(unsigned long long *)(pt + 4 * ((virt >> L1_PAGETABLE_SHIFT) & L1_PAGETABLE_MASK));
|
||||
|
||||
if ((pte & 0x00000001) == 0) {
|
||||
fprintf(stderr, "page entry not present in PT\n");
|
||||
goto out_unmap_pt;
|
||||
}
|
||||
|
||||
if (pt_levels >= 3)
|
||||
mfn = (pte & L0_PAGETABLE_MASK_PAE) >> PAGE_SHIFT;
|
||||
else
|
||||
mfn = (pte & L0_PAGETABLE_MASK) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
out_unmap_pt:
|
||||
munmap(pt, PAGE_SIZE);
|
||||
out_unmap_pd:
|
||||
munmap(pd, PAGE_SIZE);
|
||||
out_unmap_pdp:
|
||||
munmap(pdppage, PAGE_SIZE);
|
||||
out_unmap_pml:
|
||||
munmap(pml, PAGE_SIZE);
|
||||
out:
|
||||
return mfn;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -416,6 +416,19 @@ void *xc_map_foreign_range(int xc_handle, uint32_t dom,
|
||||
void *xc_map_foreign_batch(int xc_handle, uint32_t dom, int prot,
|
||||
unsigned long *arr, int num );
|
||||
|
||||
/**
|
||||
* Translates a virtual address in the context of a given domain and
|
||||
* vcpu returning the machine page frame number of the associated
|
||||
* page.
|
||||
*
|
||||
* @parm xc_handle a handle on an open hypervisor interface
|
||||
* @parm dom the domain to perform the translation in
|
||||
* @parm vcpu the vcpu to perform the translation on
|
||||
* @parm virt the virtual address to translate
|
||||
*/
|
||||
unsigned long xc_translate_foreign_address(int xc_handle, uint32_t dom,
|
||||
int vcpu, unsigned long long virt);
|
||||
|
||||
int xc_get_pfn_list(int xc_handle, uint32_t domid, unsigned long *pfn_buf,
|
||||
unsigned long max_pfns);
|
||||
|
||||
|
||||
@@ -15,25 +15,29 @@ HDRS = $(wildcard *.h)
|
||||
OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
|
||||
|
||||
BIN = xentrace tbctl setsize
|
||||
LIBBIN = xenctx
|
||||
SCRIPTS = xentrace_format
|
||||
MAN1 = $(wildcard *.1)
|
||||
MAN8 = $(wildcard *.8)
|
||||
|
||||
all: build
|
||||
build: $(BIN)
|
||||
build: $(BIN) $(LIBBIN)
|
||||
|
||||
install: build
|
||||
[ -d $(DESTDIR)/usr/bin ] || $(INSTALL_DIR) $(DESTDIR)/usr/bin
|
||||
[ -d $(DESTDIR)/usr/$(LIBDIR)/xen/bin ] || \
|
||||
$(INSTALL_DIR) $(DESTDIR)/usr/$(LIBDIR)/xen/bin
|
||||
[ -d $(DESTDIR)/usr/share/man/man1 ] || \
|
||||
$(INSTALL_DIR) $(DESTDIR)/usr/share/man/man1
|
||||
[ -d $(DESTDIR)/usr/share/man/man8 ] || \
|
||||
$(INSTALL_DIR) $(DESTDIR)/usr/share/man/man8
|
||||
$(INSTALL_PROG) $(BIN) $(SCRIPTS) $(DESTDIR)/usr/bin
|
||||
$(INSTALL_PROG) $(LIBBIN) $(DESTDIR)/usr/$(LIBDIR)/xen/bin
|
||||
$(INSTALL_DATA) $(MAN1) $(DESTDIR)/usr/share/man/man1
|
||||
$(INSTALL_DATA) $(MAN8) $(DESTDIR)/usr/share/man/man8
|
||||
|
||||
clean:
|
||||
$(RM) *.a *.so *.o *.rpm $(BIN)
|
||||
$(RM) *.a *.so *.o *.rpm $(BIN) $(LIBBIN)
|
||||
|
||||
%: %.c $(HDRS) Makefile
|
||||
$(CC) $(CFLAGS) -o $@ $< -L$(XEN_LIBXC) -lxenctrl
|
||||
+386
-12
@@ -20,15 +20,184 @@
|
||||
#include <errno.h>
|
||||
#include <argp.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "xenctrl.h"
|
||||
|
||||
int xc_handle = 0;
|
||||
int domid = 0;
|
||||
int frame_ptrs = 0;
|
||||
int stack_trace = 0;
|
||||
|
||||
#if defined (__i386__)
|
||||
#define FMT_SIZE_T "%08x"
|
||||
#define STACK_POINTER(regs) (regs->esp)
|
||||
#define FRAME_POINTER(regs) (regs->ebp)
|
||||
#define INSTR_POINTER(regs) (regs->eip)
|
||||
#define STACK_ROWS 4
|
||||
#define STACK_COLS 8
|
||||
#elif defined (__x86_64__)
|
||||
#define FMT_SIZE_T "%016lx"
|
||||
#define STACK_POINTER(regs) (regs->rsp)
|
||||
#define FRAME_POINTER(regs) (regs->rbp)
|
||||
#define INSTR_POINTER(regs) (regs->rip)
|
||||
#define STACK_ROWS 4
|
||||
#define STACK_COLS 4
|
||||
#endif
|
||||
|
||||
struct symbol {
|
||||
size_t address;
|
||||
char type;
|
||||
char *name;
|
||||
struct symbol *next;
|
||||
} *symbol_table = NULL;
|
||||
|
||||
size_t kernel_stext, kernel_etext, kernel_sinittext, kernel_einittext;
|
||||
|
||||
int is_kernel_text(size_t addr)
|
||||
{
|
||||
#if defined (__i386__)
|
||||
if (symbol_table == NULL)
|
||||
return (addr > 0xc000000);
|
||||
#elif defined (__x86_64__)
|
||||
if (symbol_table == NULL)
|
||||
return (addr > 0xffffffff80000000UL);
|
||||
#endif
|
||||
|
||||
if (addr >= kernel_stext &&
|
||||
addr <= kernel_etext)
|
||||
return 1;
|
||||
if (addr >= kernel_sinittext &&
|
||||
addr <= kernel_einittext)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_symbol(struct symbol *symbol)
|
||||
{
|
||||
if (symbol == NULL)
|
||||
return;
|
||||
if (symbol->name)
|
||||
free(symbol->name);
|
||||
free(symbol);
|
||||
}
|
||||
|
||||
void insert_symbol(struct symbol *symbol)
|
||||
{
|
||||
static struct symbol *prev = NULL;
|
||||
struct symbol *s = symbol_table;
|
||||
|
||||
if (s == NULL) {
|
||||
symbol_table = symbol;
|
||||
symbol->next = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* The System.map is usually already sorted... */
|
||||
if (prev
|
||||
&& prev->address < symbol->address
|
||||
&& (!prev->next || prev->next->address > symbol->address)) {
|
||||
s = prev;
|
||||
} else {
|
||||
/* ... otherwise do crappy/slow search for the correct place */
|
||||
while(s && s->next && s->next->address < symbol->address)
|
||||
s = s->next;
|
||||
}
|
||||
|
||||
symbol->next = s->next;
|
||||
s->next = symbol;
|
||||
prev = symbol;
|
||||
}
|
||||
|
||||
struct symbol *lookup_symbol(size_t address)
|
||||
{
|
||||
struct symbol *s = symbol_table;
|
||||
|
||||
while(s && s->next && s->next->address < address)
|
||||
s = s->next;
|
||||
|
||||
if (s && s->address < address)
|
||||
return s;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void print_symbol(size_t addr)
|
||||
{
|
||||
struct symbol *s;
|
||||
|
||||
if (!is_kernel_text(addr))
|
||||
return;
|
||||
|
||||
s = lookup_symbol(addr);
|
||||
|
||||
if (s==NULL)
|
||||
return;
|
||||
|
||||
if (addr==s->address)
|
||||
printf("%s", s->name);
|
||||
else
|
||||
printf("%s+%#x", s->name, (unsigned int)(addr - s->address));
|
||||
}
|
||||
|
||||
void read_symbol_table(const char *symtab)
|
||||
{
|
||||
char line[256];
|
||||
char *p;
|
||||
struct symbol *symbol;
|
||||
FILE *f;
|
||||
|
||||
f = fopen(symtab, "r");
|
||||
if(f == NULL) {
|
||||
fprintf(stderr, "failed to open symbol table %s\n", symtab);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
while(!feof(f)) {
|
||||
if(fgets(line,256,f)==NULL)
|
||||
break;
|
||||
|
||||
symbol = malloc(sizeof(*symbol));
|
||||
|
||||
/* need more checks for syntax here... */
|
||||
symbol->address = strtoull(line, &p, 16);
|
||||
p++;
|
||||
symbol->type = *p++;
|
||||
p++;
|
||||
|
||||
/* in the future we should handle the module name
|
||||
* being appended here, this would allow us to use
|
||||
* /proc/kallsyms as our symbol table
|
||||
*/
|
||||
if (p[strlen(p)-1] == '\n')
|
||||
p[strlen(p)-1] = '\0';
|
||||
symbol->name = strdup(p);
|
||||
|
||||
insert_symbol(symbol);
|
||||
|
||||
if (strcmp(symbol->name, "_stext") == 0)
|
||||
kernel_stext = symbol->address;
|
||||
else if (strcmp(symbol->name, "_etext") == 0)
|
||||
kernel_etext = symbol->address;
|
||||
else if (strcmp(symbol->name, "_sinittext") == 0)
|
||||
kernel_sinittext = symbol->address;
|
||||
else if (strcmp(symbol->name, "_einittext") == 0)
|
||||
kernel_einittext = symbol->address;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
void print_ctx(vcpu_guest_context_t *ctx1)
|
||||
{
|
||||
struct cpu_user_regs *regs = &ctx1->user_regs;
|
||||
|
||||
printf("eip: %08x\t", regs->eip);
|
||||
printf("eip: %08x ", regs->eip);
|
||||
print_symbol(regs->eip);
|
||||
printf("\n");
|
||||
|
||||
printf("esp: %08x\n", regs->esp);
|
||||
|
||||
printf("eax: %08x\t", regs->eax);
|
||||
@@ -51,7 +220,9 @@ void print_ctx(vcpu_guest_context_t *ctx1)
|
||||
{
|
||||
struct cpu_user_regs *regs = &ctx1->user_regs;
|
||||
|
||||
printf("rip: %08lx\t", regs->rip);
|
||||
printf("rip: %08lx ", regs->rip);
|
||||
print_symbol(regs->rip);
|
||||
printf("\n");
|
||||
printf("rsp: %08lx\n", regs->rsp);
|
||||
|
||||
printf("rax: %08lx\t", regs->rax);
|
||||
@@ -63,8 +234,8 @@ void print_ctx(vcpu_guest_context_t *ctx1)
|
||||
printf("rdi: %08lx\t", regs->rdi);
|
||||
printf("rbp: %08lx\n", regs->rbp);
|
||||
|
||||
printf("r8: %08lx\t", regs->r8);
|
||||
printf("r9: %08lx\t", regs->r9);
|
||||
printf(" r8: %08lx\t", regs->r8);
|
||||
printf(" r9: %08lx\t", regs->r9);
|
||||
printf("r10: %08lx\t", regs->r10);
|
||||
printf("r11: %08lx\n", regs->r11);
|
||||
|
||||
@@ -81,35 +252,238 @@ void print_ctx(vcpu_guest_context_t *ctx1)
|
||||
}
|
||||
#endif
|
||||
|
||||
void dump_ctx(uint32_t domid, uint32_t vcpu)
|
||||
void *map_page(vcpu_guest_context_t *ctx, int vcpu, size_t virt)
|
||||
{
|
||||
static unsigned long previous_mfn = 0;
|
||||
static void *mapped = NULL;
|
||||
|
||||
unsigned long mfn = xc_translate_foreign_address(xc_handle, domid, vcpu, virt);
|
||||
unsigned long offset = virt & ~XC_PAGE_MASK;
|
||||
|
||||
if (mapped && mfn == previous_mfn)
|
||||
goto out;
|
||||
|
||||
if (mapped)
|
||||
munmap(mapped, XC_PAGE_SIZE);
|
||||
|
||||
previous_mfn = mfn;
|
||||
|
||||
mapped = xc_map_foreign_range(xc_handle, domid, XC_PAGE_SIZE, PROT_READ, mfn);
|
||||
|
||||
if (mapped == NULL) {
|
||||
fprintf(stderr, "failed to map page.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
out:
|
||||
return (void *)(mapped + offset);
|
||||
}
|
||||
|
||||
void print_stack(vcpu_guest_context_t *ctx, int vcpu)
|
||||
{
|
||||
struct cpu_user_regs *regs = &ctx->user_regs;
|
||||
size_t stack = STACK_POINTER(regs);
|
||||
size_t stack_limit = (STACK_POINTER(regs) & XC_PAGE_MASK) + XC_PAGE_SIZE;
|
||||
size_t frame;
|
||||
size_t instr;
|
||||
size_t *p;
|
||||
int i;
|
||||
|
||||
printf("\n");
|
||||
printf("Stack:\n");
|
||||
for (i=1; i<STACK_ROWS+1 && stack < stack_limit; i++) {
|
||||
while(stack < stack_limit && stack < STACK_POINTER(regs) + i*STACK_COLS*sizeof(stack)) {
|
||||
p = map_page(ctx, vcpu, stack);
|
||||
printf(" " FMT_SIZE_T, *p);
|
||||
stack += sizeof(stack);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Code:\n");
|
||||
instr = INSTR_POINTER(regs) - 21;
|
||||
for(i=0; i<32; i++) {
|
||||
unsigned char *c = map_page(ctx, vcpu, instr+i);
|
||||
if (instr+i == INSTR_POINTER(regs))
|
||||
printf("<%02x> ", *c);
|
||||
else
|
||||
printf("%02x ", *c);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("\n");
|
||||
|
||||
if(stack_trace)
|
||||
printf("Stack Trace:\n");
|
||||
else
|
||||
printf("Call Trace:\n");
|
||||
printf("%c [<" FMT_SIZE_T ">] ", stack_trace ? '*' : ' ', INSTR_POINTER(regs));
|
||||
|
||||
print_symbol(INSTR_POINTER(regs));
|
||||
printf(" <--\n");
|
||||
if (frame_ptrs) {
|
||||
stack = STACK_POINTER(regs);
|
||||
frame = FRAME_POINTER(regs);
|
||||
while(frame && stack < stack_limit) {
|
||||
if (stack_trace) {
|
||||
while (stack < frame) {
|
||||
p = map_page(ctx, vcpu, stack);
|
||||
printf("| " FMT_SIZE_T " ", *p);
|
||||
printf("\n");
|
||||
stack += sizeof(*p);
|
||||
}
|
||||
} else {
|
||||
stack = frame;
|
||||
}
|
||||
|
||||
p = map_page(ctx, vcpu, stack);
|
||||
frame = *p;
|
||||
if (stack_trace)
|
||||
printf("|-- " FMT_SIZE_T "\n", *p);
|
||||
stack += sizeof(*p);
|
||||
|
||||
if (frame) {
|
||||
p = map_page(ctx, vcpu, stack);
|
||||
printf("%c [<" FMT_SIZE_T ">] ", stack_trace ? '|' : ' ', *p);
|
||||
print_symbol(*p);
|
||||
printf("\n");
|
||||
stack += sizeof(*p);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stack = STACK_POINTER(regs);
|
||||
while(stack < stack_limit) {
|
||||
p = map_page(ctx, vcpu, stack);
|
||||
if (is_kernel_text(*p)) {
|
||||
printf(" [<" FMT_SIZE_T ">] ", *p);
|
||||
print_symbol(*p);
|
||||
printf("\n");
|
||||
} else if (stack_trace) {
|
||||
printf(" " FMT_SIZE_T "\n", *p);
|
||||
}
|
||||
stack += sizeof(*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump_ctx(int vcpu)
|
||||
{
|
||||
int ret;
|
||||
vcpu_guest_context_t ctx;
|
||||
|
||||
int xc_handle = xc_interface_open(); /* for accessing control interface */
|
||||
xc_handle = xc_interface_open(); /* for accessing control interface */
|
||||
|
||||
ret = xc_domain_pause(xc_handle, domid);
|
||||
if (ret < 0) {
|
||||
perror("xc_domain_pause");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
ret = xc_domain_get_vcpu_context(xc_handle, domid, vcpu, &ctx);
|
||||
if (ret != 0) {
|
||||
if (ret < 0) {
|
||||
xc_domain_unpause(xc_handle, domid);
|
||||
perror("xc_domain_get_vcpu_context");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
print_ctx(&ctx);
|
||||
if (is_kernel_text(ctx.user_regs.eip))
|
||||
print_stack(&ctx, vcpu);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("usage:\n\n");
|
||||
|
||||
printf(" xenctx [options] <DOMAIN> [VCPU]\n\n");
|
||||
|
||||
printf("options:\n");
|
||||
printf(" -f, --frame-pointers\n");
|
||||
printf(" assume the kernel was compiled with\n");
|
||||
printf(" frame pointers.\n");
|
||||
printf(" -s SYMTAB, --symbol-table=SYMTAB\n");
|
||||
printf(" read symbol table from SYMTAB.\n");
|
||||
printf(" --stack-trace print a complete stack trace.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ch;
|
||||
const char *sopts = "fs:h";
|
||||
const struct option lopts[] = {
|
||||
{"stack-trace", 0, NULL, 'S'},
|
||||
{"symbol-table", 1, NULL, 's'},
|
||||
{"frame-pointers", 0, NULL, 'f'},
|
||||
{"help", 0, NULL, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
const char *symbol_table = NULL;
|
||||
|
||||
int vcpu = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("usage: xenctx <domid> <optional vcpu>\n");
|
||||
while ((ch = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
|
||||
switch(ch) {
|
||||
case 'f':
|
||||
frame_ptrs = 1;
|
||||
break;
|
||||
case 's':
|
||||
symbol_table = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
stack_trace = 1;
|
||||
break;
|
||||
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) {
|
||||
printf("usage: xenctx [options] <domid> <optional vcpu>\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (argc == 3)
|
||||
vcpu = atoi(argv[2]);
|
||||
domid = atoi(argv[0]);
|
||||
if (domid==0) {
|
||||
fprintf(stderr, "cannot trace dom0\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
dump_ctx(atoi(argv[1]), vcpu);
|
||||
if (argc == 2)
|
||||
vcpu = atoi(argv[1]);
|
||||
|
||||
if (symbol_table)
|
||||
read_symbol_table(symbol_table);
|
||||
|
||||
dump_ctx(vcpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||