ia64/xen-unstable

view tools/debugger/libxendebug/xendebug.c @ 6424:4abd299ef2f6

merge?
author cl349@firebug.cl.cam.ac.uk
date Thu Aug 25 14:16:38 2005 +0000 (2005-08-25)
parents e24fd7012ffb 6e899a3840b2
children 3428d58a85e1
line source
1 /*
2 * xendebug.c
3 *
4 * alex ho
5 * http://www.cl.cam.ac.uk/netos/pdb
6 *
7 * xendebug_memory_page adapted from xc_ptrace.c
8 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <sys/mman.h>
15 #include <xenctrl.h>
16 #include "list.h"
18 #if defined(__i386__)
19 #define L1_PAGETABLE_SHIFT 12
20 #define L2_PAGETABLE_SHIFT 22
21 #elif defined(__x86_64__)
22 #define L1_PAGETABLE_SHIFT 12
23 #define L2_PAGETABLE_SHIFT 21
24 #define L3_PAGETABLE_SHIFT 30
25 #define L4_PAGETABLE_SHIFT 39
26 #endif
28 #define PAGE_SHIFT L1_PAGETABLE_SHIFT
29 #define PAGE_SIZE (1UL<<PAGE_SHIFT)
30 #define PAGE_MASK (~(PAGE_SIZE - 1))
32 /* from xen/include/asm-x86/processor.h */
33 #define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
35 typedef int boolean;
36 #define true 1
37 #define false 0
40 typedef struct bwcpoint /* break/watch/catch point */
41 {
42 struct list_head list;
43 unsigned long address;
44 u32 domain;
45 u8 old_value; /* old value for software bkpt */
46 } bwcpoint_t, *bwcpoint_p;
48 static bwcpoint_t bwcpoint_list;
52 typedef struct domain_context /* local cache of domain state */
53 {
54 struct list_head list;
55 u32 domid;
56 boolean valid[MAX_VIRT_CPUS];
57 vcpu_guest_context_t context[MAX_VIRT_CPUS];
59 long total_pages;
60 unsigned long *page_array;
62 unsigned long cr3_phys[MAX_VIRT_CPUS];
63 unsigned long *cr3_virt[MAX_VIRT_CPUS];
64 unsigned long pde_phys[MAX_VIRT_CPUS];
65 unsigned long *pde_virt[MAX_VIRT_CPUS];
66 unsigned long page_phys[MAX_VIRT_CPUS];
67 unsigned long *page_virt[MAX_VIRT_CPUS];
68 int page_perm[MAX_VIRT_CPUS];
69 } domain_context_t, *domain_context_p;
71 static domain_context_t domain_context_list;
73 /* initialization */
75 static boolean xendebug_initialized = false;
77 static __inline__ void
78 xendebug_initialize()
79 {
80 if ( !xendebug_initialized )
81 {
82 memset((void *) &domain_context_list, 0, sizeof(domain_context_t));
83 INIT_LIST_HEAD(&domain_context_list.list);
85 memset((void *) &bwcpoint_list, 0, sizeof(bwcpoint_t));
86 INIT_LIST_HEAD(&bwcpoint_list.list);
88 xendebug_initialized = true;
89 }
90 }
92 /**************/
94 static domain_context_p
95 xendebug_domain_context_search (u32 domid)
96 {
97 struct list_head *entry;
98 domain_context_p ctxt;
100 list_for_each(entry, &domain_context_list.list)
101 {
102 ctxt = list_entry(entry, domain_context_t, list);
103 if ( domid == ctxt->domid )
104 return ctxt;
105 }
106 return (domain_context_p)NULL;
107 }
109 static __inline__ domain_context_p
110 xendebug_get_context (int xc_handle, u32 domid, u32 vcpu)
111 {
112 int rc;
113 domain_context_p ctxt;
115 xendebug_initialize();
117 if ( (ctxt = xendebug_domain_context_search(domid)) == NULL)
118 return NULL;
120 if ( !ctxt->valid[vcpu] )
121 {
122 if ( (rc = xc_domain_get_vcpu_context(xc_handle, domid, vcpu,
123 &ctxt->context[vcpu])) )
124 return NULL;
126 ctxt->valid[vcpu] = true;
127 }
129 return ctxt;
130 }
132 static __inline__ int
133 xendebug_set_context (int xc_handle, domain_context_p ctxt, u32 vcpu)
134 {
135 dom0_op_t op;
136 int rc;
138 if ( !ctxt->valid[vcpu] )
139 return -EINVAL;
141 op.interface_version = DOM0_INTERFACE_VERSION;
142 op.cmd = DOM0_SETDOMAININFO;
143 op.u.setdomaininfo.domain = ctxt->domid;
144 op.u.setdomaininfo.vcpu = vcpu;
145 op.u.setdomaininfo.ctxt = &ctxt->context[vcpu];
147 if ( (rc = mlock(&ctxt->context[vcpu], sizeof(vcpu_guest_context_t))) )
148 return rc;
150 rc = xc_dom0_op(xc_handle, &op);
151 (void) munlock(&ctxt->context[vcpu], sizeof(vcpu_guest_context_t));
153 return rc;
154 }
156 /**************/
158 int
159 xendebug_attach(int xc_handle,
160 u32 domid,
161 u32 vcpu)
162 {
163 domain_context_p ctxt;
165 xendebug_initialize();
167 if ( (ctxt = malloc(sizeof(domain_context_t))) == NULL )
168 return -1;
169 memset(ctxt, 0, sizeof(domain_context_t));
171 ctxt->domid = domid;
172 list_add(&ctxt->list, &domain_context_list.list);
174 return xc_domain_pause(xc_handle, domid);
175 }
177 int
178 xendebug_detach(int xc_handle,
179 u32 domid,
180 u32 vcpu)
181 {
182 domain_context_p ctxt;
184 xendebug_initialize();
186 if ( (ctxt = xendebug_domain_context_search (domid)) == NULL)
187 return -EINVAL;
189 list_del(&ctxt->list);
191 if ( ctxt->page_array ) free(ctxt->page_array);
193 free(ctxt);
195 return xc_domain_unpause(xc_handle, domid);
196 }
198 int
199 xendebug_read_registers(int xc_handle,
200 u32 domid,
201 u32 vcpu,
202 cpu_user_regs_t **regs)
203 {
204 domain_context_p ctxt;
205 int rc = -1;
207 xendebug_initialize();
209 ctxt = xendebug_get_context(xc_handle, domid, vcpu);
210 if (ctxt)
211 {
212 *regs = &ctxt->context[vcpu].user_regs;
213 rc = 0;
214 }
216 return rc;
217 }
219 int
220 xendebug_read_fpregisters (int xc_handle,
221 u32 domid,
222 u32 vcpu,
223 char **regs)
224 {
225 domain_context_p ctxt;
226 int rc = -1;
228 xendebug_initialize();
230 ctxt = xendebug_get_context(xc_handle, domid, vcpu);
231 if (ctxt)
232 {
233 *regs = ctxt->context[vcpu].fpu_ctxt.x;
234 rc = 0;
235 }
237 return rc;
238 }
240 int
241 xendebug_write_registers(int xc_handle,
242 u32 domid,
243 u32 vcpu,
244 cpu_user_regs_t *regs)
245 {
246 domain_context_p ctxt;
247 int rc = -1;
249 xendebug_initialize();
251 ctxt = xendebug_get_context(xc_handle, domid, vcpu);
252 if (ctxt)
253 {
254 memcpy(&ctxt->context[vcpu].user_regs, regs, sizeof(cpu_user_regs_t));
255 rc = xendebug_set_context(xc_handle, ctxt, vcpu);
256 }
258 return rc;
259 }
261 int
262 xendebug_step(int xc_handle,
263 u32 domid,
264 u32 vcpu)
265 {
266 domain_context_p ctxt;
267 int rc;
269 xendebug_initialize();
271 ctxt = xendebug_get_context(xc_handle, domid, vcpu);
272 if (!ctxt) return -EINVAL;
274 ctxt->context[vcpu].user_regs.eflags |= X86_EFLAGS_TF;
276 if ( (rc = xendebug_set_context(xc_handle, ctxt, vcpu)) )
277 return rc;
279 ctxt->valid[vcpu] = false;
280 return xc_domain_unpause(xc_handle, domid);
281 }
283 int
284 xendebug_continue(int xc_handle,
285 u32 domid,
286 u32 vcpu)
287 {
288 domain_context_p ctxt;
289 int rc;
291 xendebug_initialize();
293 ctxt = xendebug_get_context(xc_handle, domid, vcpu);
294 if (!ctxt) return -EINVAL;
296 if ( ctxt->context[vcpu].user_regs.eflags & X86_EFLAGS_TF )
297 {
298 ctxt->context[vcpu].user_regs.eflags &= ~X86_EFLAGS_TF;
299 if ( (rc = xendebug_set_context(xc_handle, ctxt, vcpu)) )
300 return rc;
301 }
302 ctxt->valid[vcpu] = false;
303 return xc_domain_unpause(xc_handle, domid);
304 }
306 /*************************************************/
308 #define vtopdi(va) ((va) >> L2_PAGETABLE_SHIFT)
309 #define vtopti(va) (((va) >> PAGE_SHIFT) & 0x3ff)
311 /* access to one page */
312 static int
313 xendebug_memory_page (domain_context_p ctxt, int xc_handle, u32 vcpu,
314 int protection, unsigned long address, int length, u8 *buffer)
315 {
316 vcpu_guest_context_t *vcpu_ctxt = &ctxt->context[vcpu];
317 unsigned long pde, page;
318 unsigned long va = (unsigned long)address;
319 void *ptr;
320 long pages;
322 pages = xc_get_tot_pages(xc_handle, ctxt->domid);
324 if ( ctxt->total_pages != pages )
325 {
326 if ( ctxt->total_pages > 0 ) free( ctxt->page_array );
327 ctxt->total_pages = pages;
329 ctxt->page_array = malloc(pages * sizeof(unsigned long));
330 if ( ctxt->page_array == NULL )
331 {
332 printf("Could not allocate memory\n");
333 return 0;
334 }
336 if ( xc_get_pfn_list(xc_handle, ctxt->domid, ctxt->page_array,pages) !=
337 pages )
338 {
339 printf("Could not get the page frame list\n");
340 return 0;
341 }
342 }
344 if ( vcpu_ctxt->ctrlreg[3] != ctxt->cr3_phys[vcpu])
345 {
346 ctxt->cr3_phys[vcpu] = vcpu_ctxt->ctrlreg[3];
347 if ( ctxt->cr3_virt[vcpu] )
348 munmap(ctxt->cr3_virt[vcpu], PAGE_SIZE);
349 ctxt->cr3_virt[vcpu] = xc_map_foreign_range(xc_handle, ctxt->domid,
350 PAGE_SIZE, PROT_READ, ctxt->cr3_phys[vcpu] >> PAGE_SHIFT);
351 if ( ctxt->cr3_virt[vcpu] == NULL )
352 return 0;
353 }
356 if ( (pde = ctxt->cr3_virt[vcpu][vtopdi(va)]) == 0) /* logical address */
357 return 0;
358 if (ctxt->context[vcpu].flags & VGCF_VMX_GUEST)
359 pde = ctxt->page_array[pde >> PAGE_SHIFT] << PAGE_SHIFT;
360 if (pde != ctxt->pde_phys[vcpu])
361 {
362 ctxt->pde_phys[vcpu] = pde;
363 if ( ctxt->pde_virt[vcpu])
364 munmap(ctxt->pde_virt[vcpu], PAGE_SIZE);
365 ctxt->pde_virt[vcpu] = xc_map_foreign_range(xc_handle, ctxt->domid,
366 PAGE_SIZE, PROT_READ, ctxt->pde_phys[vcpu] >> PAGE_SHIFT);
367 if ( ctxt->pde_virt[vcpu] == NULL )
368 return 0;
369 }
371 if ((page = ctxt->pde_virt[vcpu][vtopti(va)]) == 0) /* logical address */
372 return 0;
373 if (ctxt->context[vcpu].flags & VGCF_VMX_GUEST)
374 page = ctxt->page_array[page >> PAGE_SHIFT] << PAGE_SHIFT;
375 if (page != ctxt->page_phys[vcpu] || protection != ctxt->page_perm[vcpu])
376 {
377 ctxt->page_phys[vcpu] = page;
378 if (ctxt->page_virt[vcpu])
379 munmap(ctxt->page_virt[vcpu], PAGE_SIZE);
380 ctxt->page_virt[vcpu] = xc_map_foreign_range(xc_handle, ctxt->domid,
381 PAGE_SIZE, protection, ctxt->page_phys[vcpu] >> PAGE_SHIFT);
382 if ( ctxt->page_virt[vcpu] == NULL )
383 {
384 printf("cr3 %lx pde %lx page %lx pti %lx\n",
385 vcpu_ctxt->ctrlreg[3], pde, page, vtopti(va));
386 ctxt->page_phys[vcpu] = 0;
387 return 0;
388 }
389 ctxt->page_perm[vcpu] = protection;
390 }
392 ptr = (void *)( (unsigned long)ctxt->page_virt[vcpu] |
393 (va & ~PAGE_MASK) );
395 if ( protection & PROT_WRITE )
396 {
397 memcpy(ptr, buffer, length);
398 }
399 else
400 {
401 memcpy(buffer, ptr, length);
402 }
404 return length;
405 }
407 /* divide a memory operation into accesses to individual pages */
408 static int
409 xendebug_memory_op (domain_context_p ctxt, int xc_handle, u32 vcpu,
410 int protection, unsigned long address, int length, u8 *buffer)
411 {
412 int remain; /* number of bytes to touch past this page */
413 int bytes = 0;
415 while ( (remain = (address + length - 1) - (address | (PAGE_SIZE-1))) > 0)
416 {
417 bytes += xendebug_memory_page(ctxt, xc_handle, vcpu, protection,
418 address, length - remain, buffer);
419 buffer += (length - remain);
420 length = remain;
421 address = (address | (PAGE_SIZE - 1)) + 1;
422 }
424 bytes += xendebug_memory_page(ctxt, xc_handle, vcpu, protection,
425 address, length, buffer);
427 return bytes;
428 }
430 int
431 xendebug_read_memory(int xc_handle,
432 u32 domid,
433 u32 vcpu,
434 unsigned long address,
435 u32 length,
436 u8 *data)
437 {
438 domain_context_p ctxt;
440 xendebug_initialize();
442 ctxt = xendebug_get_context(xc_handle, domid, vcpu);
444 xendebug_memory_op(ctxt, xc_handle, vcpu, PROT_READ,
445 address, length, data);
447 return 0;
448 }
450 int
451 xendebug_write_memory(int xc_handle,
452 u32 domid,
453 u32 vcpu,
454 unsigned long address,
455 u32 length,
456 u8 *data)
457 {
458 domain_context_p ctxt;
460 xendebug_initialize();
462 ctxt = xendebug_get_context(xc_handle, domid, vcpu);
463 xendebug_memory_op(ctxt, xc_handle, vcpu, PROT_READ | PROT_WRITE,
465 address, length, data);
467 return 0;
468 }
470 int
471 xendebug_insert_memory_breakpoint(int xc_handle,
472 u32 domid,
473 u32 vcpu,
474 unsigned long address,
475 u32 length)
476 {
477 bwcpoint_p bkpt;
478 u8 breakpoint_opcode = 0xcc;
480 printf("insert breakpoint %d:%lx %d\n",
481 domid, address, length);
483 xendebug_initialize();
485 bkpt = malloc(sizeof(bwcpoint_t));
486 if ( bkpt == NULL )
487 {
488 printf("error: breakpoint length should be 1\n");
489 return -1;
490 }
492 if ( length != 1 )
493 {
494 printf("error: breakpoint length should be 1\n");
495 free(bkpt);
496 return -1;
497 }
499 bkpt->address = address;
500 bkpt->domain = domid;
502 xendebug_read_memory(xc_handle, domid, vcpu, address, 1,
503 &bkpt->old_value);
505 xendebug_write_memory(xc_handle, domid, vcpu, address, 1,
506 &breakpoint_opcode);
508 list_add(&bkpt->list, &bwcpoint_list.list);
510 printf("breakpoint_set %d:%lx 0x%x\n",
511 domid, address, bkpt->old_value);
513 return 0;
514 }
516 int
517 xendebug_remove_memory_breakpoint(int xc_handle,
518 u32 domid,
519 u32 vcpu,
520 unsigned long address,
521 u32 length)
522 {
523 bwcpoint_p bkpt = NULL;
525 printf ("remove breakpoint %d:%lx\n",
526 domid, address);
528 struct list_head *entry;
529 list_for_each(entry, &bwcpoint_list.list)
530 {
531 bkpt = list_entry(entry, bwcpoint_t, list);
532 if ( domid == bkpt->domain && address == bkpt->address )
533 break;
534 }
536 if (bkpt == &bwcpoint_list || bkpt == NULL)
537 {
538 printf ("error: no breakpoint found\n");
539 return -1;
540 }
542 list_del(&bkpt->list);
544 xendebug_write_memory(xc_handle, domid, vcpu, address, 1,
545 &bkpt->old_value);
547 free(bkpt);
548 return 0;
549 }
551 int
552 xendebug_query_domain_stop(int xc_handle, int *dom_list, int dom_list_size)
553 {
554 xc_dominfo_t *info;
555 u32 first_dom = 0;
556 int max_doms = 1024;
557 int nr_doms, loop;
558 int count = 0;
560 if ( (info = malloc(max_doms * sizeof(xc_dominfo_t))) == NULL )
561 return -ENOMEM;
563 nr_doms = xc_domain_getinfo(xc_handle, first_dom, max_doms, info);
565 for (loop = 0; loop < nr_doms; loop++)
566 {
567 printf ("domid: %d", info[loop].domid);
568 printf (" %c%c%c%c%c%c",
569 info[loop].dying ? 'D' : '-',
570 info[loop].crashed ? 'C' : '-',
571 info[loop].shutdown ? 'S' : '-',
572 info[loop].paused ? 'P' : '-',
573 info[loop].blocked ? 'B' : '-',
574 info[loop].running ? 'R' : '-');
575 printf (" pages: %ld, vcpus %d",
576 info[loop].nr_pages, info[loop].vcpus);
577 printf ("\n");
579 if ( info[loop].paused && count < dom_list_size)
580 {
581 dom_list[count++] = info[loop].domid;
582 }
583 }
585 free(info);
587 return count;
588 }
590 /*
591 * Local variables:
592 * mode: C
593 * c-set-style: "BSD"
594 * c-basic-offset: 4
595 * tab-width: 4
596 * indent-tabs-mode: nil
597 * End:
598 */