aboutsummaryrefslogtreecommitdiffstats
path: root/tools/xentrace/xenctx.c
diff options
context:
space:
mode:
authorIan.Campbell@xensource.com <Ian.Campbell@xensource.com>2005-12-22 14:33:19 +0000
committerIan.Campbell@xensource.com <Ian.Campbell@xensource.com>2005-12-22 14:33:19 +0000
commit40924689a9e86c301ebad2e6394ea359ec47b59f (patch)
treed2e6a25ae5d5c8948d474f5d2e6bd51b5d438515 /tools/xentrace/xenctx.c
parent4f27f31a471d94f55a39bc9a3eb02ca777112f59 (diff)
downloadxen-40924689a9e86c301ebad2e6394ea359ec47b59f.tar.gz
xen-40924689a9e86c301ebad2e6394ea359ec47b59f.tar.bz2
xen-40924689a9e86c301ebad2e6394ea359ec47b59f.zip
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>
Diffstat (limited to 'tools/xentrace/xenctx.c')
-rw-r--r--tools/xentrace/xenctx.c398
1 files changed, 386 insertions, 12 deletions
diff --git a/tools/xentrace/xenctx.c b/tools/xentrace/xenctx.c
index fbfd341cd8..32adccde7e 100644
--- a/tools/xentrace/xenctx.c
+++ b/tools/xentrace/xenctx.c
@@ -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);
+ }
+
+ if (argc == 2)
+ vcpu = atoi(argv[1]);
- dump_ctx(atoi(argv[1]), vcpu);
+ 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:
+ */