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 /* SCTLR is always 32-bit */
602 printf("SCTLR: %08"PRIx32"\n", (uint32_t)ctx->sctlr);
603 }
604
605 #ifdef __aarch64__
print_ctx_64(vcpu_guest_context_t * ctx)606 static void print_ctx_64(vcpu_guest_context_t *ctx)
607 {
608 vcpu_guest_core_regs_t *regs = &ctx->user_regs;
609
610 printf("PC: %016"PRIx64, regs->pc64);
611 print_symbol(regs->pc64, KERNEL_TEXT_ADDR);
612 printf("\n");
613
614 printf("LR: %016"PRIx64"\n", regs->x30);
615 printf("ELR_EL1: %016"PRIx64"\n", regs->elr_el1);
616
617 printf("CPSR: %08"PRIx32"\n", regs->cpsr);
618 printf("SPSR_EL1: %08"PRIx32"\n", regs->spsr_el1);
619
620 printf("SP_EL0: %016"PRIx64"\n", regs->sp_el0);
621 printf("SP_EL1: %016"PRIx64"\n", regs->sp_el1);
622
623 printf("\n");
624 printf(" x0: %016"PRIx64"\t", regs->x0);
625 printf(" x1: %016"PRIx64"\t", regs->x1);
626 printf(" x2: %016"PRIx64"\n", regs->x2);
627
628 printf(" x3: %016"PRIx64"\t", regs->x3);
629 printf(" x4: %016"PRIx64"\t", regs->x4);
630 printf(" x5: %016"PRIx64"\n", regs->x5);
631
632 printf(" x6: %016"PRIx64"\t", regs->x6);
633 printf(" x7: %016"PRIx64"\t", regs->x7);
634 printf(" x8: %016"PRIx64"\n", regs->x8);
635
636 printf(" x9: %016"PRIx64"\t", regs->x9);
637 printf("x10: %016"PRIx64"\t", regs->x10);
638 printf("x11: %016"PRIx64"\n", regs->x11);
639
640 printf("x12: %016"PRIx64"\t", regs->x12);
641 printf("x13: %016"PRIx64"\t", regs->x13);
642 printf("x14: %016"PRIx64"\n", regs->x14);
643
644 printf("x15: %016"PRIx64"\t", regs->x15);
645 printf("x16: %016"PRIx64"\t", regs->x16);
646 printf("x17: %016"PRIx64"\n", regs->x17);
647
648 printf("x18: %016"PRIx64"\t", regs->x18);
649 printf("x19: %016"PRIx64"\t", regs->x19);
650 printf("x20: %016"PRIx64"\n", regs->x20);
651
652 printf("x21: %016"PRIx64"\t", regs->x21);
653 printf("x22: %016"PRIx64"\t", regs->x22);
654 printf("x23: %016"PRIx64"\n", regs->x23);
655
656 printf("x24: %016"PRIx64"\t", regs->x24);
657 printf("x25: %016"PRIx64"\t", regs->x25);
658 printf("x26: %016"PRIx64"\n", regs->x26);
659
660 printf("x27: %016"PRIx64"\t", regs->x27);
661 printf("x28: %016"PRIx64"\t", regs->x28);
662 printf("x29: %016"PRIx64"\n", regs->x29);
663 printf("\n");
664 printf("SCTLR_EL1: %016"PRIx64"\n", ctx->sctlr);
665 }
666 #endif /* __aarch64__ */
667
print_ctx(vcpu_guest_context_any_t * ctx_any)668 static void print_ctx(vcpu_guest_context_any_t *ctx_any)
669 {
670 vcpu_guest_context_t *ctx = &ctx_any->c;
671
672 #ifdef __aarch64__
673 if (ctx->user_regs.cpsr & PSR_MODE_BIT)
674 print_ctx_32(ctx);
675 else
676 print_ctx_64(ctx);
677 #else
678 print_ctx_32(ctx);
679 #endif
680
681 printf("TTBCR: %016"PRIx64"\n", ctx->ttbcr);
682 printf("TTBR0: %016"PRIx64"\n", ctx->ttbr0);
683 printf("TTBR1: %016"PRIx64"\n", ctx->ttbr1);
684 }
685
686 #endif
687
688 #ifndef NO_TRANSLATION
map_page(vcpu_guest_context_any_t * ctx,int vcpu,guest_word_t virt)689 static void *map_page(vcpu_guest_context_any_t *ctx, int vcpu, guest_word_t virt)
690 {
691 static unsigned long previous_mfn = 0;
692 static void *mapped = NULL;
693
694 unsigned long mfn = xc_translate_foreign_address(xenctx.xc_handle, xenctx.domid, vcpu, virt);
695 unsigned long offset = virt & ~XC_PAGE_MASK;
696
697 if (mapped && mfn == previous_mfn)
698 goto out;
699
700 if (mapped)
701 munmap(mapped, XC_PAGE_SIZE);
702
703 previous_mfn = mfn;
704
705 mapped = xc_map_foreign_range(xenctx.xc_handle, xenctx.domid, XC_PAGE_SIZE, PROT_READ, mfn);
706
707 if (mapped == NULL) {
708 fprintf(stderr, "\nfailed to map page for "FMT_32B_WORD".\n", virt);
709 return NULL;
710 }
711
712 out:
713 return (void *)(mapped + offset);
714 }
715
read_stack_word(guest_word_t * src,int width)716 static guest_word_t read_stack_word(guest_word_t *src, int width)
717 {
718 guest_word_t word = 0;
719 /* Little-endian only */
720 memcpy(&word, src, width);
721 return word;
722 }
723
read_mem_word(vcpu_guest_context_any_t * ctx,int vcpu,guest_word_t virt,int width)724 static guest_word_t read_mem_word(vcpu_guest_context_any_t *ctx, int vcpu,
725 guest_word_t virt, int width)
726 {
727 if ( (virt & 7) == 0 )
728 {
729 guest_word_t *p = map_page(ctx, vcpu, virt);
730
731 if ( p )
732 return read_stack_word(p, width);
733 else
734 return -1;
735 }
736 else
737 {
738 guest_word_t word = 0;
739 char *src, *dst;
740 int i;
741
742 /* Little-endian only */
743 dst = (char *)&word;
744 for (i = 0; i < width; i++)
745 {
746 src = map_page(ctx, vcpu, virt + i);
747 if ( src )
748 *dst++ = *src;
749 else
750 {
751 guest_word_t missing = -1LL;
752
753 /* Return all ones for missing memory */
754 memcpy(dst, &missing, width - i);
755 return word;
756 }
757 }
758 return word;
759 }
760 }
761
print_stack_word(guest_word_t word,int width)762 static void print_stack_word(guest_word_t word, int width)
763 {
764 if (width == 2)
765 printf(FMT_16B_WORD, word);
766 else if (width == 4)
767 printf(FMT_32B_WORD, word);
768 else
769 printf(FMT_64B_WORD, word);
770 }
771
print_lines(vcpu_guest_context_any_t * ctx,int vcpu,int width,guest_word_t mem_addr,guest_word_t mem_limit)772 static int print_lines(vcpu_guest_context_any_t *ctx, int vcpu, int width,
773 guest_word_t mem_addr, guest_word_t mem_limit)
774 {
775 guest_word_t mem_start = mem_addr;
776 guest_word_t word;
777 guest_word_t ascii[MAX_BYTES_PER_LINE/4];
778 int i;
779
780 for (i = 1; i < xenctx.lines + 1 && mem_addr < mem_limit; i++)
781 {
782 int j = 0;
783 int k;
784
785 if ( xenctx.tag_stack_dump )
786 {
787 print_stack_word(mem_addr, width);
788 printf(":");
789 }
790 while ( mem_addr < mem_limit &&
791 mem_addr < mem_start + i * xenctx.bytes_per_line )
792 {
793 void *p = map_page(ctx, vcpu, mem_addr);
794 if ( !p )
795 return -1;
796 word = read_mem_word(ctx, vcpu, mem_addr, width);
797 if ( xenctx.decode_as_ascii )
798 ascii[j++] = word;
799 printf(" ");
800 print_stack_word(word, width);
801 mem_addr += width;
802 }
803 if ( xenctx.decode_as_ascii )
804 {
805 /*
806 * Line up ascii output if less than bytes_per_line
807 * were printed.
808 */
809 for (k = j; k < xenctx.bytes_per_line / width; k++)
810 printf(" %*s", width * 2, "");
811 printf(" ");
812 for (k = 0; k < j; k++)
813 {
814 int l;
815 unsigned char *bytep = (unsigned char *)&ascii[k];
816
817 for (l = 0; l < width; l++)
818 {
819 if (isprint(*bytep))
820 printf("%c", *bytep);
821 else
822 printf(".");
823 bytep++;
824 }
825 }
826 }
827 printf("\n");
828 }
829 printf("\n");
830 return 0;
831 }
832
print_mem(vcpu_guest_context_any_t * ctx,int vcpu,int width,guest_word_t mem_addr)833 static void print_mem(vcpu_guest_context_any_t *ctx, int vcpu, int width,
834 guest_word_t mem_addr)
835 {
836 printf("Memory (address ");
837 print_stack_word(mem_addr, width);
838 printf("):\n");
839 print_lines(ctx, vcpu, width, mem_addr,
840 mem_addr + xenctx.lines * xenctx.bytes_per_line);
841 }
842
print_code(vcpu_guest_context_any_t * ctx,int vcpu)843 static int print_code(vcpu_guest_context_any_t *ctx, int vcpu)
844 {
845 guest_word_t instr;
846 int i;
847
848 instr = instr_pointer(ctx);
849 printf("Code (instr addr %08llx)\n", instr);
850 instr -= 21;
851 for(i=0; i<32; i++) {
852 unsigned char *c = map_page(ctx, vcpu, instr+i);
853 if (!c)
854 return -1;
855 if (instr+i == instr_pointer(ctx))
856 printf("<%02x> ", *c);
857 else
858 printf("%02x ", *c);
859 }
860 printf("\n\n\n");
861 return 0;
862 }
863
print_stack_addr(guest_word_t addr,int width)864 static void print_stack_addr(guest_word_t addr, int width)
865 {
866 print_stack_word(addr, width);
867 printf(": ");
868 }
869
print_stack(vcpu_guest_context_any_t * ctx,int vcpu,int width,guest_word_t stk_addr_start)870 static int print_stack(vcpu_guest_context_any_t *ctx, int vcpu, int width,
871 guest_word_t stk_addr_start)
872 {
873 guest_word_t stack = stk_addr_start;
874 guest_word_t stack_limit;
875 guest_word_t frame;
876 guest_word_t word;
877 guest_word_t *p;
878
879 if ( width )
880 xenctx.bytes_per_line =
881 ((xenctx.bytes_per_line + width - 1) / width) * width;
882 stack_limit = ((stack_pointer(ctx) + XC_PAGE_SIZE)
883 & ~((guest_word_t) XC_PAGE_SIZE - 1))
884 + (xenctx.nr_stack_pages - 1) * XC_PAGE_SIZE;
885 if ( xenctx.lines )
886 {
887 printf("Stack:\n");
888 if ( print_lines(ctx, vcpu, width, stack, stack_limit) )
889 return -1;
890 }
891
892 if ( !guest_protected_mode )
893 return 0;
894
895 if(xenctx.stack_trace)
896 printf("Stack Trace:\n");
897 else
898 printf("Call Trace:\n");
899 if ( !xenctx.do_stack )
900 {
901 printf("%*s %c [<", width*2, "", xenctx.stack_trace ? '*' : ' ');
902 print_stack_word(instr_pointer(ctx), width);
903 printf(">]");
904
905 print_symbol(instr_pointer(ctx), KERNEL_TEXT_ADDR);
906 printf(" <--\n");
907 }
908 if (xenctx.frame_ptrs) {
909 stack = stack_pointer(ctx);
910 frame = frame_pointer(ctx);
911 while(frame && stack < stack_limit) {
912 if (xenctx.stack_trace) {
913 while (stack < frame) {
914 p = map_page(ctx, vcpu, stack);
915 if (!p)
916 return -1;
917 print_stack_addr(stack, width);
918 printf("| ");
919 print_stack_word(read_stack_word(p, width), width);
920 printf("\n");
921 stack += width;
922 }
923 } else {
924 stack = frame;
925 }
926
927 p = map_page(ctx, vcpu, stack);
928 if (!p)
929 return -1;
930 frame = read_stack_word(p, width);
931 if (xenctx.stack_trace) {
932 print_stack_addr(stack, width);
933 printf("|-- ");
934 print_stack_word(read_stack_word(p, width), width);
935 printf("\n");
936 }
937 stack += width;
938
939 if (frame) {
940 p = map_page(ctx, vcpu, stack);
941 if (!p)
942 return -1;
943 word = read_stack_word(p, width);
944 print_stack_addr(stack, width);
945 printf("%c [<", xenctx.stack_trace ? '|' : ' ');
946 print_stack_word(word, width);
947 printf(">]");
948 print_symbol(word, KERNEL_TEXT_ADDR);
949 printf("\n");
950 stack += width;
951 }
952 }
953 } else {
954 stack = stk_addr_start;
955 while(stack < stack_limit) {
956 p = map_page(ctx, vcpu, stack);
957 if (!p)
958 return -1;
959 word = read_mem_word(ctx, vcpu, stack, width);
960 if ( kernel_addr(word) >= KERNEL_TEXT_ADDR )
961 {
962 print_stack_addr(stack, width);
963 printf(" [<");
964 print_stack_word(word, width);
965 printf(">]");
966 print_symbol(word, KERNEL_TEXT_ADDR);
967 printf("\n");
968 } else if (xenctx.stack_trace) {
969 print_stack_addr(stack, width);
970 printf(" ");
971 print_stack_word(word, width);
972 printf("\n");
973 }
974 stack += width;
975 }
976 }
977 return 0;
978 }
979 #endif
980
dump_ctx(int vcpu)981 static void dump_ctx(int vcpu)
982 {
983 vcpu_guest_context_any_t ctx;
984
985 if (xc_vcpu_getcontext(xenctx.xc_handle, xenctx.domid, vcpu, &ctx) < 0) {
986 perror("xc_vcpu_getcontext");
987 return;
988 }
989
990 #if defined(__i386__) || defined(__x86_64__)
991 {
992 if (xenctx.dominfo.hvm) {
993 struct hvm_hw_cpu cpuctx;
994 xen_capabilities_info_t xen_caps = "";
995 if (xc_domain_hvm_getcontext_partial(
996 xenctx.xc_handle, xenctx.domid, HVM_SAVE_CODE(CPU),
997 vcpu, &cpuctx, sizeof cpuctx) != 0) {
998 perror("xc_domain_hvm_getcontext_partial");
999 return;
1000 }
1001 guest_protected_mode = (cpuctx.cr0 & CR0_PE);
1002 guest_word_size = (cpuctx.msr_efer & 0x400) ? 8 :
1003 guest_protected_mode ? 4 : 2;
1004 /* HVM guest context records are always host-sized */
1005 if (xc_version(xenctx.xc_handle, XENVER_capabilities, &xen_caps) != 0) {
1006 perror("xc_version");
1007 return;
1008 }
1009 ctxt_word_size = (strstr(xen_caps, "xen-3.0-x86_64")) ? 8 : 4;
1010 } else {
1011 unsigned int gw;
1012 if ( !xc_domain_get_guest_width(xenctx.xc_handle, xenctx.domid, &gw) )
1013 ctxt_word_size = guest_word_size = gw;
1014 }
1015 }
1016 #endif
1017
1018 #ifndef NO_TRANSLATION
1019 if ( xenctx.do_memory )
1020 {
1021 print_mem(&ctx, vcpu, guest_word_size, xenctx.mem_addr);
1022 return;
1023 }
1024 if ( xenctx.do_stack )
1025 {
1026 print_stack(&ctx, vcpu, guest_word_size, xenctx.stk_addr);
1027 return;
1028 }
1029 #endif
1030 print_ctx(&ctx);
1031 #ifndef NO_TRANSLATION
1032 if (print_code(&ctx, vcpu))
1033 return;
1034 if ( !guest_protected_mode ||
1035 kernel_addr(instr_pointer(&ctx)) >= KERNEL_TEXT_ADDR )
1036 if ( print_stack(&ctx, vcpu, guest_word_size,
1037 stack_pointer(&ctx)) )
1038 return;
1039 #endif
1040 }
1041
dump_all_vcpus(void)1042 static void dump_all_vcpus(void)
1043 {
1044 xc_vcpuinfo_t vinfo;
1045 int vcpu;
1046 for (vcpu = 0; vcpu <= xenctx.dominfo.max_vcpu_id; vcpu++)
1047 {
1048 if ( xc_vcpu_getinfo(xenctx.xc_handle, xenctx.domid, vcpu, &vinfo) )
1049 continue;
1050 if ( vinfo.online )
1051 {
1052 printf("vcpu%d:\n", vcpu);
1053 dump_ctx(vcpu);
1054 printf("\n");
1055 }
1056 else
1057 printf("vcpu%d offline\n\n", vcpu);
1058 }
1059 }
1060
usage(void)1061 static void usage(void)
1062 {
1063 printf("usage:\n\n");
1064
1065 printf(" xenctx [options] <DOMAIN> [VCPU]\n\n");
1066
1067 printf("options:\n");
1068 printf(" -f, --frame-pointers\n");
1069 printf(" assume the kernel was compiled with\n");
1070 printf(" frame pointers.\n");
1071 printf(" -s SYMTAB, --symbol-table=SYMTAB\n");
1072 printf(" read symbol table from SYMTAB.\n");
1073 printf(" -S, --stack-trace print a complete stack trace.\n");
1074 printf(" -k KADDR, --kernel-start=KADDR\n");
1075 printf(" set user/kernel split. (default 0x"FMT_32B_WORD")\n",
1076 kernel_start);
1077 printf(" -a, --all display more registers\n");
1078 printf(" -C, --all-vcpus print info for all vcpus\n");
1079 printf(" -n PAGES, --display-stack-pages=PAGES\n");
1080 printf(" Display N pages from the stack pointer. (default %d)\n",
1081 DEFAULT_NR_STACK_PAGES);
1082 printf(" Changes stack limit. Note: use with caution (easy\n");
1083 printf(" to get garbage).\n");
1084 printf(" -b <bytes>, --bytes-per-line <bytes>\n");
1085 printf(" change the number of bytes per line output for Stack.\n");
1086 printf(" (default %d) Note: rounded to native size (4 or 8 bytes).\n",
1087 DEFAULT_BYTES_PER_LINE);
1088 printf(" -l <lines>, --lines <lines>\n");
1089 printf(" change the number of lines output for Stack. (default %d)\n",
1090 DEFAULT_LINES);
1091 printf(" Can be specified as MAX. Note: Fewer lines will be output\n");
1092 printf(" if stack limit reached.\n");
1093 printf(" -D, --decode-as-ascii\n");
1094 printf(" add a decode of Stack dump as ascii.\n");
1095 printf(" -t, --tag-stack-dump\n");
1096 printf(" add address on each line of Stack dump.\n");
1097 #ifndef NO_TRANSLATION
1098 printf(" -m maddr, --memory=maddr\n");
1099 printf(" dump memory at maddr.\n");
1100 printf(" -d daddr, --dump-as-stack=daddr\n");
1101 printf(" dump memory as a stack at daddr.\n");
1102 #endif
1103 }
1104
main(int argc,char ** argv)1105 int main(int argc, char **argv)
1106 {
1107 int ch;
1108 int ret;
1109 const char *prog = argv[0];
1110 static const char *sopts = "fs:hak:SCn:b:l:Dt"
1111 #ifndef NO_TRANSLATION
1112 "m:d:"
1113 #endif
1114 ;
1115 static const struct option lopts[] = {
1116 {"stack-trace", 0, NULL, 'S'},
1117 {"symbol-table", 1, NULL, 's'},
1118 {"frame-pointers", 0, NULL, 'f'},
1119 {"kernel-start", 1, NULL, 'k'},
1120 {"display-stack-pages", 0, NULL, 'n'},
1121 {"decode-as-ascii", 0, NULL, 'D'},
1122 {"tag-stack-dump", 0, NULL, 't'},
1123 #ifndef NO_TRANSLATION
1124 {"memory", 1, NULL, 'm'},
1125 {"dump-as-stack", 1, NULL, 'd'},
1126 #endif
1127 {"bytes-per-line", 1, NULL, 'b'},
1128 {"lines", 1, NULL, 'l'},
1129 {"all", 0, NULL, 'a'},
1130 {"all-vcpus", 0, NULL, 'C'},
1131 {"help", 0, NULL, 'h'},
1132 {0, 0, 0, 0}
1133 };
1134 const char *symbol_table = NULL;
1135
1136 int vcpu = 0;
1137 int do_default = 1;
1138
1139 xenctx.bytes_per_line = DEFAULT_BYTES_PER_LINE;
1140 xenctx.lines = DEFAULT_LINES;
1141 xenctx.nr_stack_pages = DEFAULT_NR_STACK_PAGES;
1142
1143 while ((ch = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
1144 switch(ch) {
1145 case 'f':
1146 xenctx.frame_ptrs = 1;
1147 break;
1148 case 's':
1149 symbol_table = optarg;
1150 break;
1151 case 'S':
1152 xenctx.stack_trace = 1;
1153 break;
1154 case 'a':
1155 xenctx.disp_all = 1;
1156 break;
1157 case 'n':
1158 xenctx.nr_stack_pages = strtol(optarg, NULL, 0);
1159 if ( xenctx.nr_stack_pages < 1)
1160 {
1161 fprintf(stderr,
1162 "%s: Unsupported value(%d) for --display-stack-pages '%s'. Needs to be >= 1\n",
1163 prog, xenctx.nr_stack_pages, optarg);
1164 exit(-1);
1165 }
1166 break;
1167 case 'D':
1168 xenctx.decode_as_ascii = 1;
1169 break;
1170 case 't':
1171 xenctx.tag_stack_dump = 1;
1172 break;
1173 case 'b':
1174 xenctx.bytes_per_line = strtol(optarg, NULL, 0);
1175 if ( xenctx.bytes_per_line < 4 ||
1176 xenctx.bytes_per_line > MAX_BYTES_PER_LINE )
1177 {
1178 fprintf(stderr,
1179 "%s: Unsupported value for --bytes-per-line '%s'. Needs to be 4 <= %d <= %d\n",
1180 prog, optarg, xenctx.bytes_per_line,
1181 MAX_BYTES_PER_LINE);
1182 exit(-1);
1183 }
1184 break;
1185 case 'l':
1186 if ( !strcmp(optarg, "all") || !strcmp(optarg, "ALL") ||
1187 !strcmp(optarg, "max") || !strcmp(optarg, "MAX") )
1188 xenctx.lines = INT_MAX - 1;
1189 else
1190 xenctx.lines = strtol(optarg, NULL, 0);
1191 if ( xenctx.lines < 0 || xenctx.lines == INT_MAX)
1192 {
1193 fprintf(stderr,
1194 "%s: Unsupported value(%d) for --lines '%s'. Needs to be >= 0, < %d\n",
1195 prog, xenctx.lines, optarg, INT_MAX);
1196 exit(-1);
1197 }
1198 break;
1199 case 'C':
1200 xenctx.all_vcpus = 1;
1201 do_default = 0;
1202 break;
1203 case 'k':
1204 kernel_start = strtoull(optarg, NULL, 0);
1205 xenctx.kernel_start_set = 1;
1206 break;
1207 #ifndef NO_TRANSLATION
1208 case 'm':
1209 xenctx.mem_addr = strtoull(optarg, NULL, 0);
1210 xenctx.do_memory = 1;
1211 do_default = 0;
1212 break;
1213 case 'd':
1214 xenctx.stk_addr = strtoull(optarg, NULL, 0);
1215 xenctx.do_stack = 1;
1216 do_default = 0;
1217 break;
1218 #endif
1219 case 'h':
1220 usage();
1221 exit(-1);
1222 case '?':
1223 fprintf(stderr, "%s --help for more options\n", prog);
1224 exit(-1);
1225 }
1226 }
1227
1228 argv += optind; argc -= optind;
1229
1230 if (argc < 1 || argc > 2) {
1231 printf("usage: xenctx [options] <domid> <optional vcpu>\n");
1232 exit(-1);
1233 }
1234
1235 #ifndef NO_TRANSLATION
1236 if ( xenctx.frame_ptrs && xenctx.do_stack )
1237 {
1238 fprintf(stderr,
1239 "%s: both --frame-pointers and --dump-as-stack is not supported\n",
1240 prog);
1241 exit(-1);
1242 }
1243 #endif
1244
1245 xenctx.domid = atoi(argv[0]);
1246 if (xenctx.domid==0) {
1247 fprintf(stderr, "cannot trace dom0\n");
1248 exit(-1);
1249 }
1250
1251 if ( argc == 2 )
1252 {
1253 if ( xenctx.all_vcpus )
1254 {
1255 fprintf(stderr,
1256 "%s: both --all-vcpus and [VCPU] is not supported\n",
1257 prog);
1258 exit(-1);
1259 }
1260 vcpu = atoi(argv[1]);
1261 }
1262
1263 if (symbol_table)
1264 read_symbol_table(symbol_table);
1265
1266 xenctx.xc_handle = xc_interface_open(0,0,0); /* for accessing control interface */
1267 if (xenctx.xc_handle == NULL) {
1268 perror("xc_interface_open");
1269 exit(-1);
1270 }
1271
1272 ret = xc_domain_getinfo(xenctx.xc_handle, xenctx.domid, 1, &xenctx.dominfo);
1273 if (ret < 0) {
1274 perror("xc_domain_getinfo");
1275 exit(-1);
1276 }
1277
1278 ret = xc_domain_pause(xenctx.xc_handle, xenctx.domid);
1279 if (ret < 0) {
1280 perror("xc_domain_pause");
1281 exit(-1);
1282 }
1283
1284 #ifndef NO_TRANSLATION
1285 if ( xenctx.do_memory )
1286 {
1287 dump_ctx(vcpu);
1288 if ( xenctx.do_stack || xenctx.all_vcpus )
1289 printf("\n");
1290 }
1291 xenctx.do_memory = 0;
1292 if ( xenctx.do_stack )
1293 {
1294 dump_ctx(vcpu);
1295 if ( xenctx.all_vcpus )
1296 printf("\n");
1297 }
1298 xenctx.do_stack = 0;
1299 #endif
1300 if (xenctx.all_vcpus)
1301 dump_all_vcpus();
1302 if ( do_default )
1303 dump_ctx(vcpu);
1304
1305 ret = xc_domain_unpause(xenctx.xc_handle, xenctx.domid);
1306 if (ret < 0) {
1307 perror("xc_domain_unpause");
1308 exit(-1);
1309 }
1310
1311 ret = xc_interface_close(xenctx.xc_handle);
1312 if (ret < 0) {
1313 perror("xc_interface_close");
1314 exit(-1);
1315 }
1316
1317 return 0;
1318 }
1319
1320 /*
1321 * Local variables:
1322 * mode: C
1323 * c-file-style: "BSD"
1324 * c-basic-offset: 4
1325 * tab-width: 4
1326 * indent-tabs-mode: nil
1327 * End:
1328 */
1329