1 /******************************************************************************
2 * tools/xentrace/xenctx.c
3 *
4 * Tool for dumping the cpu context
5 *
6 * Copyright (C) 2005 by Intel Corp
7 *
8 * Author: Arun Sharma <arun.sharma@intel.com>
9 * Date: February 2005
10 */
11
12 #include <time.h>
13 #include <stdlib.h>
14 #include <sys/mman.h>
15 #include <stdio.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <signal.h>
22 #include <ctype.h>
23 #include <string.h>
24 #include <inttypes.h>
25 #include <getopt.h>
26 #include <limits.h>
27
28 #define XC_WANT_COMPAT_MAP_FOREIGN_API
29 #include <xenctrl.h>
30 #include <xen/foreign/x86_32.h>
31 #include <xen/foreign/x86_64.h>
32 #include <xen/hvm/save.h>
33
34 #define DEFAULT_NR_STACK_PAGES 1
35 #define DEFAULT_BYTES_PER_LINE 32
36 #define DEFAULT_LINES 5
37
38 /* Note: the order of these matter.
39 * NOT_KERNEL_ADDR must be < both KERNEL_DATA_ADDR and KERNEL_TEXT_ADDR.
40 * KERNEL_DATA_ADDR must be < KERNEL_TEXT_ADDR. */
41 typedef enum type_of_addr_ {
42 NOT_KERNEL_ADDR,
43 KERNEL_DATA_ADDR,
44 KERNEL_TEXT_ADDR,
45 } type_of_addr;
46
47 #if defined (__i386__) || defined (__x86_64__)
48 static const uint64_t cr_reg_mask[5] = { [2] = ~UINT64_C(0) };
49 static const uint64_t dr_reg_mask[8] = { [0 ... 3] = ~UINT64_C(0) };
50 typedef unsigned long long guest_word_t;
51 #define FMT_16B_WORD "%04llx"
52 #define FMT_32B_WORD "%08llx"
53 #define FMT_64B_WORD "%016llx"
54 /* Word-length of the guest's own data structures */
55 int guest_word_size = sizeof (unsigned long);
56 /* Word-length of the context record we get from xen */
57 int ctxt_word_size = sizeof (unsigned long);
58 int guest_protected_mode = 1;
59 #elif defined(__arm__)
60 #define NO_TRANSLATION
61 typedef uint64_t guest_word_t;
62 #define FMT_16B_WORD "%04llx"
63 #define FMT_32B_WORD "%08llx"
64 #define FMT_64B_WORD "%016llx"
65 #elif defined(__aarch64__)
66 #define NO_TRANSLATION
67 typedef uint64_t guest_word_t;
68 #define FMT_16B_WORD "%04llx"
69 #define FMT_32B_WORD "%08llx"
70 #define FMT_64B_WORD "%016llx"
71 #endif
72
73 #define MAX_BYTES_PER_LINE 128
74
75 static struct xenctx {
76 xc_interface *xc_handle;
77 int domid;
78 int frame_ptrs;
79 int stack_trace;
80 int disp_all;
81 int nr_stack_pages;
82 int bytes_per_line;
83 int lines;
84 int decode_as_ascii;
85 int tag_stack_dump;
86 int tag_call_trace;
87 int all_vcpus;
88 #ifndef NO_TRANSLATION
89 guest_word_t mem_addr;
90 guest_word_t stk_addr;
91 int do_memory;
92 int do_stack;
93 #endif
94 int kernel_start_set;
95 xc_dominfo_t dominfo;
96 } xenctx;
97
98 struct symbol {
99 guest_word_t address;
100 char *name;
101 struct symbol *next;
102 } *symbol_table = NULL;
103
104 guest_word_t kernel_stext, kernel_etext, kernel_sinittext, kernel_einittext, kernel_hypercallpage;
105 guest_word_t kernel_text;
106
107 #if defined (__i386__) || defined (__arm__)
108 unsigned long long kernel_start = 0xc0000000;
109 unsigned long long kernel_end = 0xffffffffULL;
110 #elif defined (__x86_64__)
111 unsigned long long kernel_start = 0xffffffff80000000UL;
112 unsigned long long kernel_end = 0xffffffffffffffffUL;
113 #elif defined (__aarch64__)
114 unsigned long long kernel_start = 0xffffff8000000000UL;
115 unsigned long long kernel_end = 0xffffffffffffffffULL;
116 #endif
117
kernel_addr(guest_word_t addr)118 static type_of_addr kernel_addr(guest_word_t addr)
119 {
120 if ( symbol_table == NULL )
121 {
122 if ( addr > kernel_start )
123 return KERNEL_TEXT_ADDR;
124 else
125 return NOT_KERNEL_ADDR;
126 }
127
128 if (addr >= kernel_stext &&
129 addr <= kernel_etext)
130 return KERNEL_TEXT_ADDR;
131 if ( kernel_hypercallpage &&
132 (addr >= kernel_hypercallpage &&
133 addr <= kernel_hypercallpage + 4096) )
134 return KERNEL_TEXT_ADDR;
135 if (addr >= kernel_sinittext &&
136 addr <= kernel_einittext)
137 return KERNEL_TEXT_ADDR;
138 if ( xenctx.kernel_start_set )
139 {
140 if ( addr > kernel_start )
141 return KERNEL_TEXT_ADDR;
142 } else {
143 if ( addr >= kernel_text &&
144 addr <= kernel_end )
145 return KERNEL_DATA_ADDR;
146 if ( addr >= kernel_start &&
147 addr <= kernel_end )
148 return KERNEL_TEXT_ADDR;
149 }
150 return NOT_KERNEL_ADDR;
151 }
152
153 #if 0
154 static void free_symbol(struct symbol *symbol)
155 {
156 if (symbol == NULL)
157 return;
158 if (symbol->name)
159 free(symbol->name);
160 free(symbol);
161 }
162 #endif
163
insert_symbol(struct symbol * symbol)164 static void insert_symbol(struct symbol *symbol)
165 {
166 static struct symbol *prev = NULL;
167 struct symbol *s = symbol_table;
168
169 if (s == NULL) {
170 symbol_table = symbol;
171 symbol->next = NULL;
172 return;
173 }
174
175 /* The System.map is usually already sorted... */
176 if (prev
177 && prev->address <= symbol->address
178 && (!prev->next || prev->next->address > symbol->address)) {
179 s = prev;
180 } else {
181 /* ... otherwise do crappy/slow search for the correct place */
182 while (s->next && s->next->address <= symbol->address)
183 s = s->next;
184 }
185
186 symbol->next = s->next;
187 s->next = symbol;
188 prev = symbol;
189 }
190
lookup_symbol(guest_word_t address)191 static struct symbol *lookup_symbol(guest_word_t address)
192 {
193 struct symbol *s = symbol_table;
194
195 if (!s)
196 return NULL;
197
198 while (s->next && s->next->address < address)
199 s = s->next;
200
201 return s->next && s->next->address <= address ? s->next : s;
202 }
203
print_symbol(guest_word_t addr,type_of_addr type)204 static void print_symbol(guest_word_t addr, type_of_addr type)
205 {
206 struct symbol *s;
207
208 if ( kernel_addr(addr) < type )
209 return;
210
211 s = lookup_symbol(addr);
212
213 if (s==NULL)
214 return;
215
216 if (addr==s->address)
217 printf(" %s", s->name);
218 else
219 printf(" %s+%#x", s->name, (unsigned int)(addr - s->address));
220 }
221
read_symbol_table(const char * symtab)222 static void read_symbol_table(const char *symtab)
223 {
224 char type, line[256];
225 char *p;
226 struct symbol *symbol;
227 FILE *f;
228 guest_word_t address;
229
230 f = fopen(symtab, "r");
231 if(f == NULL) {
232 fprintf(stderr, "failed to open symbol table %s\n", symtab);
233 exit(-1);
234 }
235
236 while(!feof(f)) {
237 if(fgets(line,256,f)==NULL)
238 break;
239
240 /* need more checks for syntax here... */
241 address = strtoull(line, &p, 16);
242 if (!isspace((uint8_t)*p++))
243 continue;
244 type = *p++;
245 if (!isalpha((uint8_t)type) && type != '?')
246 continue;
247 if (!isspace((uint8_t)*p++))
248 continue;
249
250 /* in the future we should handle the module name
251 * being appended here, this would allow us to use
252 * /proc/kallsyms as our symbol table
253 */
254 if (p[strlen(p)-1] == '\n')
255 p[strlen(p)-1] = '\0';
256
257 switch (type) {
258 case 'A': /* global absolute */
259 case 'a': /* local absolute */
260 break;
261 case 'U': /* undefined */
262 case 'v': /* undefined weak object */
263 case 'w': /* undefined weak function */
264 continue;
265 default:
266 symbol = malloc(sizeof(*symbol));
267 if (symbol == NULL) {
268 fclose(f);
269 return;
270 }
271
272 symbol->address = address;
273 symbol->name = strdup(p);
274 if (symbol->name == NULL) {
275 free(symbol);
276 fclose(f);
277 return;
278 }
279
280 insert_symbol(symbol);
281 break;
282 }
283
284 if (strcmp(p, "_stext") == 0)
285 kernel_stext = address;
286 else if (strcmp(p, "_etext") == 0)
287 kernel_etext = address;
288 else if ( strcmp(p, "_text") == 0 )
289 kernel_text = address;
290 else if ( strcmp(p, "_end") == 0 || strcmp(p, "__bss_stop") == 0 )
291 kernel_end = address;
292 else if (strcmp(p, "_sinittext") == 0)
293 kernel_sinittext = address;
294 else if (strcmp(p, "_einittext") == 0)
295 kernel_einittext = address;
296 else if (strcmp(p, "hypercall_page") == 0)
297 kernel_hypercallpage = address;
298 }
299
300 fclose(f);
301 }
302
303 #if defined(__i386__) || defined(__x86_64__)
304 #define CR0_PE 0x1
305 char *flag_values[22][2] =
306 {/* clear, set, bit# */
307 { NULL, "c" }, // 0 Carry
308 { NULL, NULL }, // 1
309 { NULL, "p" }, // 2 Parity
310 { NULL, NULL }, // 3
311 { NULL, "a" }, // 4 Adjust
312 { NULL, NULL }, // 5
313 { "nz", "z" }, // 6 Zero
314 { NULL, "s" }, // 7 Sign
315 { NULL, "tf" }, // 8 Trap
316 { NULL, "i" }, // 9 Interrupt (enabled)
317 { NULL, "d=b" }, // 10 Direction
318 { NULL, "o" }, // 11 Overflow
319 { NULL, NULL }, // 12 12+13 == IOPL
320 { NULL, NULL }, // 13
321 { NULL, "nt" }, // 14 Nested Task
322 { NULL, NULL }, // 15
323 { NULL, "rf" }, // 16 Resume Flag
324 { NULL, "v86" }, // 17 Virtual 8086 mode
325 { NULL, "ac" }, // 18 Alignment Check (enabled)
326 { NULL, "vif" }, // 19 Virtual Interrupt (enabled)
327 { NULL, "vip" }, // 20 Virtual Interrupt Pending
328 { NULL, "cid" } // 21 Cpuid Identification Flag
329 };
330
print_flags(uint64_t flags)331 static void print_flags(uint64_t flags)
332 {
333 int i;
334
335 printf("\nflags: %08" PRIx64, flags);
336 for (i = 21; i >= 0; i--) {
337 char *s = flag_values[i][(flags >> i) & 1];
338 if (s != NULL)
339 printf(" %s", s);
340 }
341 printf("\n");
342 }
343
print_special(void * regs,const char * name,unsigned int mask,const uint64_t reg_is_addr_mask[],int width)344 static void print_special(void *regs, const char *name, unsigned int mask,
345 const uint64_t reg_is_addr_mask[], int width)
346 {
347 unsigned int i;
348
349 printf("\n");
350 for (i = 0; mask; mask >>= 1, ++i)
351 if (mask & 1) {
352 if ( width == 4 )
353 {
354 printf("%s%u: %08"PRIx32, name, i, ((uint32_t *) regs)[i]);
355 if ( reg_is_addr_mask[i] )
356 print_symbol(reg_is_addr_mask[i] & ((uint32_t *) regs)[i],
357 KERNEL_DATA_ADDR);
358 }
359 else
360 {
361 printf("%s%u: %016"PRIx64, name, i, ((uint64_t *) regs)[i]);
362 if ( reg_is_addr_mask[i] )
363 print_symbol(reg_is_addr_mask[i] & ((uint64_t *) regs)[i],
364 KERNEL_DATA_ADDR);
365 }
366 printf("\n");
367 }
368 }
369
print_ctx_32(vcpu_guest_context_x86_32_t * ctx)370 static void print_ctx_32(vcpu_guest_context_x86_32_t *ctx)
371 {
372 struct cpu_user_regs_x86_32 *regs = &ctx->user_regs;
373
374 printf("cs:eip: %04x:%08x", regs->cs, regs->eip);
375 print_symbol(regs->eip, KERNEL_TEXT_ADDR);
376 print_flags(regs->eflags);
377 printf("ss:esp: %04x:%08x\n", regs->ss, regs->esp);
378
379 printf("eax: %08x\t", regs->eax);
380 printf("ebx: %08x\t", regs->ebx);
381 printf("ecx: %08x\t", regs->ecx);
382 printf("edx: %08x\n", regs->edx);
383
384 printf("esi: %08x\t", regs->esi);
385 printf("edi: %08x\t", regs->edi);
386 printf("ebp: %08x\n", regs->ebp);
387
388 printf(" ds: %04x\t", regs->ds);
389 printf(" es: %04x\t", regs->es);
390 printf(" fs: %04x\t", regs->fs);
391 printf(" gs: %04x\n", regs->gs);
392
393 if (xenctx.disp_all) {
394 print_special(ctx->ctrlreg, "cr", 0x1d, cr_reg_mask, 4);
395 print_special(ctx->debugreg, "dr", 0xcf, dr_reg_mask, 4);
396 }
397 }
398
print_ctx_32on64(vcpu_guest_context_x86_64_t * ctx)399 static void print_ctx_32on64(vcpu_guest_context_x86_64_t *ctx)
400 {
401 struct cpu_user_regs_x86_64 *regs = &ctx->user_regs;
402
403 printf("cs:eip: %04x:%08x", regs->cs, (uint32_t)regs->eip);
404 print_symbol((uint32_t)regs->eip, KERNEL_TEXT_ADDR);
405 print_flags((uint32_t)regs->eflags);
406 printf("ss:esp: %04x:%08x\n", regs->ss, (uint32_t)regs->esp);
407
408 printf("eax: %08x\t", (uint32_t)regs->eax);
409 printf("ebx: %08x\t", (uint32_t)regs->ebx);
410 printf("ecx: %08x\t", (uint32_t)regs->ecx);
411 printf("edx: %08x\n", (uint32_t)regs->edx);
412
413 printf("esi: %08x\t", (uint32_t)regs->esi);
414 printf("edi: %08x\t", (uint32_t)regs->edi);
415 printf("ebp: %08x\n", (uint32_t)regs->ebp);
416
417 printf(" ds: %04x\t", regs->ds);
418 printf(" es: %04x\t", regs->es);
419 printf(" fs: %04x\t", regs->fs);
420 printf(" gs: %04x\n", regs->gs);
421
422 if (xenctx.disp_all) {
423 uint32_t tmp_regs[8];
424 int i;
425
426 for (i = 0; i < 5; i++)
427 tmp_regs[i] = ctx->ctrlreg[i];
428 print_special(tmp_regs, "cr", 0x1d, cr_reg_mask, 4);
429 for (i = 0; i < 8; i++)
430 tmp_regs[i] = ctx->debugreg[i];
431 print_special(tmp_regs, "dr", 0xcf, dr_reg_mask, 4);
432 }
433 }
434
print_ctx_64(vcpu_guest_context_x86_64_t * ctx)435 static void print_ctx_64(vcpu_guest_context_x86_64_t *ctx)
436 {
437 struct cpu_user_regs_x86_64 *regs = &ctx->user_regs;
438
439 printf("rip: %016"PRIx64, regs->rip);
440 print_symbol(regs->rip, KERNEL_TEXT_ADDR);
441 print_flags(regs->rflags);
442 printf("rsp: %016"PRIx64"\n", regs->rsp);
443
444 printf("rax: %016"PRIx64"\t", regs->rax);
445 printf("rcx: %016"PRIx64"\t", regs->rcx);
446 printf("rdx: %016"PRIx64"\n", regs->rdx);
447
448 printf("rbx: %016"PRIx64"\t", regs->rbx);
449 printf("rsi: %016"PRIx64"\t", regs->rsi);
450 printf("rdi: %016"PRIx64"\n", regs->rdi);
451
452 printf("rbp: %016"PRIx64"\t", regs->rbp);
453 printf(" r8: %016"PRIx64"\t", regs->r8);
454 printf(" r9: %016"PRIx64"\n", regs->r9);
455
456 printf("r10: %016"PRIx64"\t", regs->r10);
457 printf("r11: %016"PRIx64"\t", regs->r11);
458 printf("r12: %016"PRIx64"\n", regs->r12);
459
460 printf("r13: %016"PRIx64"\t", regs->r13);
461 printf("r14: %016"PRIx64"\t", regs->r14);
462 printf("r15: %016"PRIx64"\n", regs->r15);
463
464 printf(" cs: %04x\t", regs->cs);
465 printf(" ss: %04x\t", regs->ss);
466 printf(" ds: %04x\t", regs->ds);
467 printf(" es: %04x\n", regs->es);
468
469 printf(" fs: %04x @ %016"PRIx64, regs->fs, ctx->fs_base);
470 print_symbol(ctx->fs_base, KERNEL_DATA_ADDR);
471 printf("\n");
472 printf(" gs: %04x @ %016"PRIx64"/%016"PRIx64, regs->gs,
473 ctx->gs_base_kernel, ctx->gs_base_user);
474 if ( symbol_table )
475 {
476 print_symbol(ctx->gs_base_kernel, KERNEL_DATA_ADDR);
477 printf("/");
478 print_symbol(ctx->gs_base_user, KERNEL_DATA_ADDR);
479 }
480 printf("\n");
481
482 if (xenctx.disp_all) {
483 print_special(ctx->ctrlreg, "cr", 0x1d, cr_reg_mask, 8);
484 print_special(ctx->debugreg, "dr", 0xcf, dr_reg_mask, 8);
485 }
486 }
487
print_ctx(vcpu_guest_context_any_t * ctx)488 static void print_ctx(vcpu_guest_context_any_t *ctx)
489 {
490 if (ctxt_word_size == 4)
491 print_ctx_32(&ctx->x32);
492 else if (guest_word_size != 8)
493 print_ctx_32on64(&ctx->x64);
494 else
495 print_ctx_64(&ctx->x64);
496 }
497
498 #define NONPROT_MODE_SEGMENT_SHIFT 4
499
instr_pointer(vcpu_guest_context_any_t * ctx)500 static guest_word_t instr_pointer(vcpu_guest_context_any_t *ctx)
501 {
502 guest_word_t r;
503 if (ctxt_word_size == 4)
504 {
505 r = ctx->x32.user_regs.eip;
506
507 if ( !guest_protected_mode )
508 r += ctx->x32.user_regs.cs << NONPROT_MODE_SEGMENT_SHIFT;
509 }
510 else
511 {
512 r = ctx->x64.user_regs.rip;
513
514 if ( !guest_protected_mode )
515 r += ctx->x64.user_regs.cs << NONPROT_MODE_SEGMENT_SHIFT;
516 }
517
518 return r;
519 }
520
stack_pointer(vcpu_guest_context_any_t * ctx)521 static guest_word_t stack_pointer(vcpu_guest_context_any_t *ctx)
522 {
523 guest_word_t r;
524 if (ctxt_word_size == 4)
525 {
526 r = ctx->x32.user_regs.esp;
527
528 if ( !guest_protected_mode )
529 r += ctx->x32.user_regs.ss << NONPROT_MODE_SEGMENT_SHIFT;
530 }
531 else
532 {
533 r = ctx->x64.user_regs.rsp;
534
535 if ( !guest_protected_mode )
536 r += ctx->x64.user_regs.ss << NONPROT_MODE_SEGMENT_SHIFT;
537 }
538
539 return r;
540 }
541
frame_pointer(vcpu_guest_context_any_t * ctx)542 static guest_word_t frame_pointer(vcpu_guest_context_any_t *ctx)
543 {
544 if (ctxt_word_size == 4)
545 return ctx->x32.user_regs.ebp;
546 else
547 return ctx->x64.user_regs.rbp;
548 }
549
550 #elif defined(__arm__) || defined(__aarch64__)
551
print_ctx_32(vcpu_guest_context_t * ctx)552 static void print_ctx_32(vcpu_guest_context_t *ctx)
553 {
554 vcpu_guest_core_regs_t *regs = &ctx->user_regs;
555
556 printf("PC: %08"PRIx32, regs->pc32);
557 print_symbol(regs->pc32, KERNEL_TEXT_ADDR);
558 printf("\n");
559 printf("CPSR: %08"PRIx32"\n", regs->cpsr);
560 printf("USR: SP:%08"PRIx32" LR:%08"PRIx32"\n",
561 regs->sp_usr, regs->lr_usr);
562 printf("SVC: SPSR:%08"PRIx32" SP:%08"PRIx32" LR:%08"PRIx32"\n",
563 regs->spsr_svc, regs->sp_svc, regs->lr_svc);
564 printf("FIQ: SPSR:%08"PRIx32" SP:%08"PRIx32" LR:%08"PRIx32"\n",
565 regs->spsr_fiq, regs->sp_fiq, regs->lr_fiq);
566 printf("IRQ: SPSR:%08"PRIx32" SP:%08"PRIx32" LR:%08"PRIx32"\n",
567 regs->spsr_irq, regs->sp_irq, regs->lr_irq);
568 printf("ABT: SPSR:%08"PRIx32" SP:%08"PRIx32" LR:%08"PRIx32"\n",
569 regs->spsr_abt, regs->sp_abt, regs->lr_abt);
570 printf("UND: SPSR:%08"PRIx32" SP:%08"PRIx32" LR:%08"PRIx32"\n",
571 regs->spsr_und, regs->sp_und, regs->lr_und);
572
573 printf("\n");
574 printf(" r0_usr: %08"PRIx32"\t", regs->r0_usr);
575 printf(" r1_usr: %08"PRIx32"\t", regs->r1_usr);
576 printf(" r2_usr: %08"PRIx32"\n", regs->r2_usr);
577
578 printf(" r3_usr: %08"PRIx32"\t", regs->r3_usr);
579 printf(" r4_usr: %08"PRIx32"\t", regs->r4_usr);
580 printf(" r5_usr: %08"PRIx32"\n", regs->r5_usr);
581
582 printf(" r6_usr: %08"PRIx32"\t", regs->r6_usr);
583 printf(" r7_usr: %08"PRIx32"\t", regs->r7_usr);
584 printf(" r8_usr: %08"PRIx32"\n", regs->r8_usr);
585
586 printf(" r9_usr: %08"PRIx32"\t", regs->r9_usr);
587 printf("r10_usr: %08"PRIx32"\t", regs->r10_usr);
588 printf("r11_usr: %08"PRIx32"\n", regs->r11_usr);
589
590 printf("r12_usr: %08"PRIx32"\n", regs->r12_usr);
591 printf("\n");
592
593 printf(" r8_fiq: %08"PRIx32"\n", regs->r8_fiq);
594
595 printf(" r9_fiq: %08"PRIx32"\t", regs->r9_fiq);
596 printf("r10_fiq: %08"PRIx32"\t", regs->r10_fiq);
597 printf("r11_fiq: %08"PRIx32"\n", regs->r11_fiq);
598
599 printf("r12_fiq: %08"PRIx32"\n", regs->r12_fiq);
600 printf("\n");
601 }
602
603 #ifdef __aarch64__
print_ctx_64(vcpu_guest_context_t * ctx)604 static void print_ctx_64(vcpu_guest_context_t *ctx)
605 {
606 vcpu_guest_core_regs_t *regs = &ctx->user_regs;
607
608 printf("PC: %016"PRIx64, regs->pc64);
609 print_symbol(regs->pc64, KERNEL_TEXT_ADDR);
610 printf("\n");
611
612 printf("LR: %016"PRIx64"\n", regs->x30);
613 printf("ELR_EL1: %016"PRIx64"\n", regs->elr_el1);
614
615 printf("CPSR: %08"PRIx32"\n", regs->cpsr);
616 printf("SPSR_EL1: %08"PRIx32"\n", regs->spsr_el1);
617
618 printf("SP_EL0: %016"PRIx64"\n", regs->sp_el0);
619 printf("SP_EL1: %016"PRIx64"\n", regs->sp_el1);
620
621 printf("\n");
622 printf(" x0: %016"PRIx64"\t", regs->x0);
623 printf(" x1: %016"PRIx64"\t", regs->x1);
624 printf(" x2: %016"PRIx64"\n", regs->x2);
625
626 printf(" x3: %016"PRIx64"\t", regs->x3);
627 printf(" x4: %016"PRIx64"\t", regs->x4);
628 printf(" x5: %016"PRIx64"\n", regs->x5);
629
630 printf(" x6: %016"PRIx64"\t", regs->x6);
631 printf(" x7: %016"PRIx64"\t", regs->x7);
632 printf(" x8: %016"PRIx64"\n", regs->x8);
633
634 printf(" x9: %016"PRIx64"\t", regs->x9);
635 printf("x10: %016"PRIx64"\t", regs->x10);
636 printf("x11: %016"PRIx64"\n", regs->x11);
637
638 printf("x12: %016"PRIx64"\t", regs->x12);
639 printf("x13: %016"PRIx64"\t", regs->x13);
640 printf("x14: %016"PRIx64"\n", regs->x14);
641
642 printf("x15: %016"PRIx64"\t", regs->x15);
643 printf("x16: %016"PRIx64"\t", regs->x16);
644 printf("x17: %016"PRIx64"\n", regs->x17);
645
646 printf("x18: %016"PRIx64"\t", regs->x18);
647 printf("x19: %016"PRIx64"\t", regs->x19);
648 printf("x20: %016"PRIx64"\n", regs->x20);
649
650 printf("x21: %016"PRIx64"\t", regs->x21);
651 printf("x22: %016"PRIx64"\t", regs->x22);
652 printf("x23: %016"PRIx64"\n", regs->x23);
653
654 printf("x24: %016"PRIx64"\t", regs->x24);
655 printf("x25: %016"PRIx64"\t", regs->x25);
656 printf("x26: %016"PRIx64"\n", regs->x26);
657
658 printf("x27: %016"PRIx64"\t", regs->x27);
659 printf("x28: %016"PRIx64"\t", regs->x28);
660 printf("x29: %016"PRIx64"\n", regs->x29);
661 printf("\n");
662 }
663 #endif /* __aarch64__ */
664
print_ctx(vcpu_guest_context_any_t * ctx_any)665 static void print_ctx(vcpu_guest_context_any_t *ctx_any)
666 {
667 vcpu_guest_context_t *ctx = &ctx_any->c;
668
669 #ifdef __aarch64__
670 if (ctx->user_regs.cpsr & PSR_MODE_BIT)
671 print_ctx_32(ctx);
672 else
673 print_ctx_64(ctx);
674 #else
675 print_ctx_32(ctx);
676 #endif
677
678 printf("SCTLR: %08"PRIx32"\n", ctx->sctlr);
679 printf("TTBCR: %016"PRIx64"\n", ctx->ttbcr);
680 printf("TTBR0: %016"PRIx64"\n", ctx->ttbr0);
681 printf("TTBR1: %016"PRIx64"\n", ctx->ttbr1);
682 }
683
684 #endif
685
686 #ifndef NO_TRANSLATION
map_page(vcpu_guest_context_any_t * ctx,int vcpu,guest_word_t virt)687 static void *map_page(vcpu_guest_context_any_t *ctx, int vcpu, guest_word_t virt)
688 {
689 static unsigned long previous_mfn = 0;
690 static void *mapped = NULL;
691
692 unsigned long mfn = xc_translate_foreign_address(xenctx.xc_handle, xenctx.domid, vcpu, virt);
693 unsigned long offset = virt & ~XC_PAGE_MASK;
694
695 if (mapped && mfn == previous_mfn)
696 goto out;
697
698 if (mapped)
699 munmap(mapped, XC_PAGE_SIZE);
700
701 previous_mfn = mfn;
702
703 mapped = xc_map_foreign_range(xenctx.xc_handle, xenctx.domid, XC_PAGE_SIZE, PROT_READ, mfn);
704
705 if (mapped == NULL) {
706 fprintf(stderr, "\nfailed to map page for "FMT_32B_WORD".\n", virt);
707 return NULL;
708 }
709
710 out:
711 return (void *)(mapped + offset);
712 }
713
read_stack_word(guest_word_t * src,int width)714 static guest_word_t read_stack_word(guest_word_t *src, int width)
715 {
716 guest_word_t word = 0;
717 /* Little-endian only */
718 memcpy(&word, src, width);
719 return word;
720 }
721
read_mem_word(vcpu_guest_context_any_t * ctx,int vcpu,guest_word_t virt,int width)722 static guest_word_t read_mem_word(vcpu_guest_context_any_t *ctx, int vcpu,
723 guest_word_t virt, int width)
724 {
725 if ( (virt & 7) == 0 )
726 {
727 guest_word_t *p = map_page(ctx, vcpu, virt);
728
729 if ( p )
730 return read_stack_word(p, width);
731 else
732 return -1;
733 }
734 else
735 {
736 guest_word_t word = 0;
737 char *src, *dst;
738 int i;
739
740 /* Little-endian only */
741 dst = (char *)&word;
742 for (i = 0; i < width; i++)
743 {
744 src = map_page(ctx, vcpu, virt + i);
745 if ( src )
746 *dst++ = *src;
747 else
748 {
749 guest_word_t missing = -1LL;
750
751 /* Return all ones for missing memory */
752 memcpy(dst, &missing, width - i);
753 return word;
754 }
755 }
756 return word;
757 }
758 }
759
print_stack_word(guest_word_t word,int width)760 static void print_stack_word(guest_word_t word, int width)
761 {
762 if (width == 2)
763 printf(FMT_16B_WORD, word);
764 else if (width == 4)
765 printf(FMT_32B_WORD, word);
766 else
767 printf(FMT_64B_WORD, word);
768 }
769
print_lines(vcpu_guest_context_any_t * ctx,int vcpu,int width,guest_word_t mem_addr,guest_word_t mem_limit)770 static int print_lines(vcpu_guest_context_any_t *ctx, int vcpu, int width,
771 guest_word_t mem_addr, guest_word_t mem_limit)
772 {
773 guest_word_t mem_start = mem_addr;
774 guest_word_t word;
775 guest_word_t ascii[MAX_BYTES_PER_LINE/4];
776 int i;
777
778 for (i = 1; i < xenctx.lines + 1 && mem_addr < mem_limit; i++)
779 {
780 int j = 0;
781 int k;
782
783 if ( xenctx.tag_stack_dump )
784 {
785 print_stack_word(mem_addr, width);
786 printf(":");
787 }
788 while ( mem_addr < mem_limit &&
789 mem_addr < mem_start + i * xenctx.bytes_per_line )
790 {
791 void *p = map_page(ctx, vcpu, mem_addr);
792 if ( !p )
793 return -1;
794 word = read_mem_word(ctx, vcpu, mem_addr, width);
795 if ( xenctx.decode_as_ascii )
796 ascii[j++] = word;
797 printf(" ");
798 print_stack_word(word, width);
799 mem_addr += width;
800 }
801 if ( xenctx.decode_as_ascii )
802 {
803 /*
804 * Line up ascii output if less than bytes_per_line
805 * were printed.
806 */
807 for (k = j; k < xenctx.bytes_per_line / width; k++)
808 printf(" %*s", width * 2, "");
809 printf(" ");
810 for (k = 0; k < j; k++)
811 {
812 int l;
813 unsigned char *bytep = (unsigned char *)&ascii[k];
814
815 for (l = 0; l < width; l++)
816 {
817 if (isprint(*bytep))
818 printf("%c", *bytep);
819 else
820 printf(".");
821 bytep++;
822 }
823 }
824 }
825 printf("\n");
826 }
827 printf("\n");
828 return 0;
829 }
830
print_mem(vcpu_guest_context_any_t * ctx,int vcpu,int width,guest_word_t mem_addr)831 static void print_mem(vcpu_guest_context_any_t *ctx, int vcpu, int width,
832 guest_word_t mem_addr)
833 {
834 printf("Memory (address ");
835 print_stack_word(mem_addr, width);
836 printf("):\n");
837 print_lines(ctx, vcpu, width, mem_addr,
838 mem_addr + xenctx.lines * xenctx.bytes_per_line);
839 }
840
print_code(vcpu_guest_context_any_t * ctx,int vcpu)841 static int print_code(vcpu_guest_context_any_t *ctx, int vcpu)
842 {
843 guest_word_t instr;
844 int i;
845
846 instr = instr_pointer(ctx);
847 printf("Code (instr addr %08llx)\n", instr);
848 instr -= 21;
849 for(i=0; i<32; i++) {
850 unsigned char *c = map_page(ctx, vcpu, instr+i);
851 if (!c)
852 return -1;
853 if (instr+i == instr_pointer(ctx))
854 printf("<%02x> ", *c);
855 else
856 printf("%02x ", *c);
857 }
858 printf("\n\n\n");
859 return 0;
860 }
861
print_stack_addr(guest_word_t addr,int width)862 static void print_stack_addr(guest_word_t addr, int width)
863 {
864 print_stack_word(addr, width);
865 printf(": ");
866 }
867
print_stack(vcpu_guest_context_any_t * ctx,int vcpu,int width,guest_word_t stk_addr_start)868 static int print_stack(vcpu_guest_context_any_t *ctx, int vcpu, int width,
869 guest_word_t stk_addr_start)
870 {
871 guest_word_t stack = stk_addr_start;
872 guest_word_t stack_limit;
873 guest_word_t frame;
874 guest_word_t word;
875 guest_word_t *p;
876
877 if ( width )
878 xenctx.bytes_per_line =
879 ((xenctx.bytes_per_line + width - 1) / width) * width;
880 stack_limit = ((stack_pointer(ctx) + XC_PAGE_SIZE)
881 & ~((guest_word_t) XC_PAGE_SIZE - 1))
882 + (xenctx.nr_stack_pages - 1) * XC_PAGE_SIZE;
883 if ( xenctx.lines )
884 {
885 printf("Stack:\n");
886 if ( print_lines(ctx, vcpu, width, stack, stack_limit) )
887 return -1;
888 }
889
890 if ( !guest_protected_mode )
891 return 0;
892
893 if(xenctx.stack_trace)
894 printf("Stack Trace:\n");
895 else
896 printf("Call Trace:\n");
897 if ( !xenctx.do_stack )
898 {
899 printf("%*s %c [<", width*2, "", xenctx.stack_trace ? '*' : ' ');
900 print_stack_word(instr_pointer(ctx), width);
901 printf(">]");
902
903 print_symbol(instr_pointer(ctx), KERNEL_TEXT_ADDR);
904 printf(" <--\n");
905 }
906 if (xenctx.frame_ptrs) {
907 stack = stack_pointer(ctx);
908 frame = frame_pointer(ctx);
909 while(frame && stack < stack_limit) {
910 if (xenctx.stack_trace) {
911 while (stack < frame) {
912 p = map_page(ctx, vcpu, stack);
913 if (!p)
914 return -1;
915 print_stack_addr(stack, width);
916 printf("| ");
917 print_stack_word(read_stack_word(p, width), width);
918 printf("\n");
919 stack += width;
920 }
921 } else {
922 stack = frame;
923 }
924
925 p = map_page(ctx, vcpu, stack);
926 if (!p)
927 return -1;
928 frame = read_stack_word(p, width);
929 if (xenctx.stack_trace) {
930 print_stack_addr(stack, width);
931 printf("|-- ");
932 print_stack_word(read_stack_word(p, width), width);
933 printf("\n");
934 }
935 stack += width;
936
937 if (frame) {
938 p = map_page(ctx, vcpu, stack);
939 if (!p)
940 return -1;
941 word = read_stack_word(p, width);
942 print_stack_addr(stack, width);
943 printf("%c [<", xenctx.stack_trace ? '|' : ' ');
944 print_stack_word(word, width);
945 printf(">]");
946 print_symbol(word, KERNEL_TEXT_ADDR);
947 printf("\n");
948 stack += width;
949 }
950 }
951 } else {
952 stack = stk_addr_start;
953 while(stack < stack_limit) {
954 p = map_page(ctx, vcpu, stack);
955 if (!p)
956 return -1;
957 word = read_mem_word(ctx, vcpu, stack, width);
958 if ( kernel_addr(word) >= KERNEL_TEXT_ADDR )
959 {
960 print_stack_addr(stack, width);
961 printf(" [<");
962 print_stack_word(word, width);
963 printf(">]");
964 print_symbol(word, KERNEL_TEXT_ADDR);
965 printf("\n");
966 } else if (xenctx.stack_trace) {
967 print_stack_addr(stack, width);
968 printf(" ");
969 print_stack_word(word, width);
970 printf("\n");
971 }
972 stack += width;
973 }
974 }
975 return 0;
976 }
977 #endif
978
dump_ctx(int vcpu)979 static void dump_ctx(int vcpu)
980 {
981 vcpu_guest_context_any_t ctx;
982
983 if (xc_vcpu_getcontext(xenctx.xc_handle, xenctx.domid, vcpu, &ctx) < 0) {
984 perror("xc_vcpu_getcontext");
985 return;
986 }
987
988 #if defined(__i386__) || defined(__x86_64__)
989 {
990 if (xenctx.dominfo.hvm) {
991 struct hvm_hw_cpu cpuctx;
992 xen_capabilities_info_t xen_caps = "";
993 if (xc_domain_hvm_getcontext_partial(
994 xenctx.xc_handle, xenctx.domid, HVM_SAVE_CODE(CPU),
995 vcpu, &cpuctx, sizeof cpuctx) != 0) {
996 perror("xc_domain_hvm_getcontext_partial");
997 return;
998 }
999 guest_protected_mode = (cpuctx.cr0 & CR0_PE);
1000 guest_word_size = (cpuctx.msr_efer & 0x400) ? 8 :
1001 guest_protected_mode ? 4 : 2;
1002 /* HVM guest context records are always host-sized */
1003 if (xc_version(xenctx.xc_handle, XENVER_capabilities, &xen_caps) != 0) {
1004 perror("xc_version");
1005 return;
1006 }
1007 ctxt_word_size = (strstr(xen_caps, "xen-3.0-x86_64")) ? 8 : 4;
1008 } else {
1009 unsigned int gw;
1010 if ( !xc_domain_get_guest_width(xenctx.xc_handle, xenctx.domid, &gw) )
1011 ctxt_word_size = guest_word_size = gw;
1012 }
1013 }
1014 #endif
1015
1016 #ifndef NO_TRANSLATION
1017 if ( xenctx.do_memory )
1018 {
1019 print_mem(&ctx, vcpu, guest_word_size, xenctx.mem_addr);
1020 return;
1021 }
1022 if ( xenctx.do_stack )
1023 {
1024 print_stack(&ctx, vcpu, guest_word_size, xenctx.stk_addr);
1025 return;
1026 }
1027 #endif
1028 print_ctx(&ctx);
1029 #ifndef NO_TRANSLATION
1030 if (print_code(&ctx, vcpu))
1031 return;
1032 if ( !guest_protected_mode ||
1033 kernel_addr(instr_pointer(&ctx)) >= KERNEL_TEXT_ADDR )
1034 if ( print_stack(&ctx, vcpu, guest_word_size,
1035 stack_pointer(&ctx)) )
1036 return;
1037 #endif
1038 }
1039
dump_all_vcpus(void)1040 static void dump_all_vcpus(void)
1041 {
1042 xc_vcpuinfo_t vinfo;
1043 int vcpu;
1044 for (vcpu = 0; vcpu <= xenctx.dominfo.max_vcpu_id; vcpu++)
1045 {
1046 if ( xc_vcpu_getinfo(xenctx.xc_handle, xenctx.domid, vcpu, &vinfo) )
1047 continue;
1048 if ( vinfo.online )
1049 {
1050 printf("vcpu%d:\n", vcpu);
1051 dump_ctx(vcpu);
1052 printf("\n");
1053 }
1054 else
1055 printf("vcpu%d offline\n\n", vcpu);
1056 }
1057 }
1058
usage(void)1059 static void usage(void)
1060 {
1061 printf("usage:\n\n");
1062
1063 printf(" xenctx [options] <DOMAIN> [VCPU]\n\n");
1064
1065 printf("options:\n");
1066 printf(" -f, --frame-pointers\n");
1067 printf(" assume the kernel was compiled with\n");
1068 printf(" frame pointers.\n");
1069 printf(" -s SYMTAB, --symbol-table=SYMTAB\n");
1070 printf(" read symbol table from SYMTAB.\n");
1071 printf(" -S, --stack-trace print a complete stack trace.\n");
1072 printf(" -k KADDR, --kernel-start=KADDR\n");
1073 printf(" set user/kernel split. (default 0x"FMT_32B_WORD")\n",
1074 kernel_start);
1075 printf(" -a, --all display more registers\n");
1076 printf(" -C, --all-vcpus print info for all vcpus\n");
1077 printf(" -n PAGES, --display-stack-pages=PAGES\n");
1078 printf(" Display N pages from the stack pointer. (default %d)\n",
1079 DEFAULT_NR_STACK_PAGES);
1080 printf(" Changes stack limit. Note: use with caution (easy\n");
1081 printf(" to get garbage).\n");
1082 printf(" -b <bytes>, --bytes-per-line <bytes>\n");
1083 printf(" change the number of bytes per line output for Stack.\n");
1084 printf(" (default %d) Note: rounded to native size (4 or 8 bytes).\n",
1085 DEFAULT_BYTES_PER_LINE);
1086 printf(" -l <lines>, --lines <lines>\n");
1087 printf(" change the number of lines output for Stack. (default %d)\n",
1088 DEFAULT_LINES);
1089 printf(" Can be specified as MAX. Note: Fewer lines will be output\n");
1090 printf(" if stack limit reached.\n");
1091 printf(" -D, --decode-as-ascii\n");
1092 printf(" add a decode of Stack dump as ascii.\n");
1093 printf(" -t, --tag-stack-dump\n");
1094 printf(" add address on each line of Stack dump.\n");
1095 #ifndef NO_TRANSLATION
1096 printf(" -m maddr, --memory=maddr\n");
1097 printf(" dump memory at maddr.\n");
1098 printf(" -d daddr, --dump-as-stack=daddr\n");
1099 printf(" dump memory as a stack at daddr.\n");
1100 #endif
1101 }
1102
main(int argc,char ** argv)1103 int main(int argc, char **argv)
1104 {
1105 int ch;
1106 int ret;
1107 const char *prog = argv[0];
1108 static const char *sopts = "fs:hak:SCn:b:l:Dt"
1109 #ifndef NO_TRANSLATION
1110 "m:d:"
1111 #endif
1112 ;
1113 static const struct option lopts[] = {
1114 {"stack-trace", 0, NULL, 'S'},
1115 {"symbol-table", 1, NULL, 's'},
1116 {"frame-pointers", 0, NULL, 'f'},
1117 {"kernel-start", 1, NULL, 'k'},
1118 {"display-stack-pages", 0, NULL, 'n'},
1119 {"decode-as-ascii", 0, NULL, 'D'},
1120 {"tag-stack-dump", 0, NULL, 't'},
1121 #ifndef NO_TRANSLATION
1122 {"memory", 1, NULL, 'm'},
1123 {"dump-as-stack", 1, NULL, 'd'},
1124 #endif
1125 {"bytes-per-line", 1, NULL, 'b'},
1126 {"lines", 1, NULL, 'l'},
1127 {"all", 0, NULL, 'a'},
1128 {"all-vcpus", 0, NULL, 'C'},
1129 {"help", 0, NULL, 'h'},
1130 {0, 0, 0, 0}
1131 };
1132 const char *symbol_table = NULL;
1133
1134 int vcpu = 0;
1135 int do_default = 1;
1136
1137 xenctx.bytes_per_line = DEFAULT_BYTES_PER_LINE;
1138 xenctx.lines = DEFAULT_LINES;
1139 xenctx.nr_stack_pages = DEFAULT_NR_STACK_PAGES;
1140
1141 while ((ch = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
1142 switch(ch) {
1143 case 'f':
1144 xenctx.frame_ptrs = 1;
1145 break;
1146 case 's':
1147 symbol_table = optarg;
1148 break;
1149 case 'S':
1150 xenctx.stack_trace = 1;
1151 break;
1152 case 'a':
1153 xenctx.disp_all = 1;
1154 break;
1155 case 'n':
1156 xenctx.nr_stack_pages = strtol(optarg, NULL, 0);
1157 if ( xenctx.nr_stack_pages < 1)
1158 {
1159 fprintf(stderr,
1160 "%s: Unsupported value(%d) for --display-stack-pages '%s'. Needs to be >= 1\n",
1161 prog, xenctx.nr_stack_pages, optarg);
1162 exit(-1);
1163 }
1164 break;
1165 case 'D':
1166 xenctx.decode_as_ascii = 1;
1167 break;
1168 case 't':
1169 xenctx.tag_stack_dump = 1;
1170 break;
1171 case 'b':
1172 xenctx.bytes_per_line = strtol(optarg, NULL, 0);
1173 if ( xenctx.bytes_per_line < 4 ||
1174 xenctx.bytes_per_line > MAX_BYTES_PER_LINE )
1175 {
1176 fprintf(stderr,
1177 "%s: Unsupported value for --bytes-per-line '%s'. Needs to be 4 <= %d <= %d\n",
1178 prog, optarg, xenctx.bytes_per_line,
1179 MAX_BYTES_PER_LINE);
1180 exit(-1);
1181 }
1182 break;
1183 case 'l':
1184 if ( !strcmp(optarg, "all") || !strcmp(optarg, "ALL") ||
1185 !strcmp(optarg, "max") || !strcmp(optarg, "MAX") )
1186 xenctx.lines = INT_MAX - 1;
1187 else
1188 xenctx.lines = strtol(optarg, NULL, 0);
1189 if ( xenctx.lines < 0 || xenctx.lines == INT_MAX)
1190 {
1191 fprintf(stderr,
1192 "%s: Unsupported value(%d) for --lines '%s'. Needs to be >= 0, < %d\n",
1193 prog, xenctx.lines, optarg, INT_MAX);
1194 exit(-1);
1195 }
1196 break;
1197 case 'C':
1198 xenctx.all_vcpus = 1;
1199 do_default = 0;
1200 break;
1201 case 'k':
1202 kernel_start = strtoull(optarg, NULL, 0);
1203 xenctx.kernel_start_set = 1;
1204 break;
1205 #ifndef NO_TRANSLATION
1206 case 'm':
1207 xenctx.mem_addr = strtoull(optarg, NULL, 0);
1208 xenctx.do_memory = 1;
1209 do_default = 0;
1210 break;
1211 case 'd':
1212 xenctx.stk_addr = strtoull(optarg, NULL, 0);
1213 xenctx.do_stack = 1;
1214 do_default = 0;
1215 break;
1216 #endif
1217 case 'h':
1218 usage();
1219 exit(-1);
1220 case '?':
1221 fprintf(stderr, "%s --help for more options\n", prog);
1222 exit(-1);
1223 }
1224 }
1225
1226 argv += optind; argc -= optind;
1227
1228 if (argc < 1 || argc > 2) {
1229 printf("usage: xenctx [options] <domid> <optional vcpu>\n");
1230 exit(-1);
1231 }
1232
1233 #ifndef NO_TRANSLATION
1234 if ( xenctx.frame_ptrs && xenctx.do_stack )
1235 {
1236 fprintf(stderr,
1237 "%s: both --frame-pointers and --dump-as-stack is not supported\n",
1238 prog);
1239 exit(-1);
1240 }
1241 #endif
1242
1243 xenctx.domid = atoi(argv[0]);
1244 if (xenctx.domid==0) {
1245 fprintf(stderr, "cannot trace dom0\n");
1246 exit(-1);
1247 }
1248
1249 if ( argc == 2 )
1250 {
1251 if ( xenctx.all_vcpus )
1252 {
1253 fprintf(stderr,
1254 "%s: both --all-vcpus and [VCPU] is not supported\n",
1255 prog);
1256 exit(-1);
1257 }
1258 vcpu = atoi(argv[1]);
1259 }
1260
1261 if (symbol_table)
1262 read_symbol_table(symbol_table);
1263
1264 xenctx.xc_handle = xc_interface_open(0,0,0); /* for accessing control interface */
1265 if (xenctx.xc_handle == NULL) {
1266 perror("xc_interface_open");
1267 exit(-1);
1268 }
1269
1270 ret = xc_domain_getinfo(xenctx.xc_handle, xenctx.domid, 1, &xenctx.dominfo);
1271 if (ret < 0) {
1272 perror("xc_domain_getinfo");
1273 exit(-1);
1274 }
1275
1276 ret = xc_domain_pause(xenctx.xc_handle, xenctx.domid);
1277 if (ret < 0) {
1278 perror("xc_domain_pause");
1279 exit(-1);
1280 }
1281
1282 #ifndef NO_TRANSLATION
1283 if ( xenctx.do_memory )
1284 {
1285 dump_ctx(vcpu);
1286 if ( xenctx.do_stack || xenctx.all_vcpus )
1287 printf("\n");
1288 }
1289 xenctx.do_memory = 0;
1290 if ( xenctx.do_stack )
1291 {
1292 dump_ctx(vcpu);
1293 if ( xenctx.all_vcpus )
1294 printf("\n");
1295 }
1296 xenctx.do_stack = 0;
1297 #endif
1298 if (xenctx.all_vcpus)
1299 dump_all_vcpus();
1300 if ( do_default )
1301 dump_ctx(vcpu);
1302
1303 ret = xc_domain_unpause(xenctx.xc_handle, xenctx.domid);
1304 if (ret < 0) {
1305 perror("xc_domain_unpause");
1306 exit(-1);
1307 }
1308
1309 ret = xc_interface_close(xenctx.xc_handle);
1310 if (ret < 0) {
1311 perror("xc_interface_close");
1312 exit(-1);
1313 }
1314
1315 return 0;
1316 }
1317
1318 /*
1319 * Local variables:
1320 * mode: C
1321 * c-file-style: "BSD"
1322 * c-basic-offset: 4
1323 * tab-width: 4
1324 * indent-tabs-mode: nil
1325 * End:
1326 */
1327