ia64/xen-unstable

view tools/libxc/xc_ptrace.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 3233e7ecfa9f
children 619e3d6f01b3 3133e64d0462
line source
1 #include <sys/ptrace.h>
2 #include <sys/wait.h>
3 #include "xc_private.h"
4 #include <time.h>
6 #define X86_CR0_PE 0x00000001 /* Enable Protected Mode (RW) */
7 #define X86_CR0_PG 0x80000000 /* Paging (RW) */
9 #define BSD_PAGE_MASK (PAGE_SIZE-1)
10 #define PG_FRAME (~((unsigned long)BSD_PAGE_MASK)
11 #define PDRSHIFT 22
12 #define PSL_T 0x00000100 /* trace enable bit */
14 #define VCPU 0 /* XXX */
16 /*
17 * long
18 * ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
19 */
22 int waitdomain(int domain, int *status, int options);
24 char * ptrace_names[] = {
25 "PTRACE_TRACEME",
26 "PTRACE_PEEKTEXT",
27 "PTRACE_PEEKDATA",
28 "PTRACE_PEEKUSER",
29 "PTRACE_POKETEXT",
30 "PTRACE_POKEDATA",
31 "PTRACE_POKEUSER",
32 "PTRACE_CONT",
33 "PTRACE_KILL",
34 "PTRACE_SINGLESTEP",
35 "PTRACE_INVALID",
36 "PTRACE_INVALID",
37 "PTRACE_GETREGS",
38 "PTRACE_SETREGS",
39 "PTRACE_GETFPREGS",
40 "PTRACE_SETFPREGS",
41 "PTRACE_ATTACH",
42 "PTRACE_DETACH",
43 "PTRACE_GETFPXREGS",
44 "PTRACE_SETFPXREGS",
45 "PTRACE_INVALID",
46 "PTRACE_INVALID",
47 "PTRACE_INVALID",
48 "PTRACE_INVALID",
49 "PTRACE_SYSCALL",
50 };
52 struct gdb_regs {
53 long ebx; /* 0 */
54 long ecx; /* 4 */
55 long edx; /* 8 */
56 long esi; /* 12 */
57 long edi; /* 16 */
58 long ebp; /* 20 */
59 long eax; /* 24 */
60 int xds; /* 28 */
61 int xes; /* 32 */
62 int xfs; /* 36 */
63 int xgs; /* 40 */
64 long orig_eax; /* 44 */
65 long eip; /* 48 */
66 int xcs; /* 52 */
67 long eflags; /* 56 */
68 long esp; /* 60 */
69 int xss; /* 64 */
70 };
72 #define FETCH_REGS(cpu) \
73 if (!regs_valid[cpu]) \
74 { \
75 int retval = xc_domain_get_vcpu_context(xc_handle, domid, cpu, &ctxt[cpu]); \
76 if (retval) \
77 goto error_out; \
78 cr3[cpu] = ctxt[cpu].ctrlreg[3]; /* physical address */ \
79 regs_valid[cpu] = 1; \
80 } \
82 #define printval(x) printf("%s = %lx\n", #x, (long)x);
83 #define SET_PT_REGS(pt, xc) \
84 { \
85 pt.ebx = xc.ebx; \
86 pt.ecx = xc.ecx; \
87 pt.edx = xc.edx; \
88 pt.esi = xc.esi; \
89 pt.edi = xc.edi; \
90 pt.ebp = xc.ebp; \
91 pt.eax = xc.eax; \
92 pt.eip = xc.eip; \
93 pt.xcs = xc.cs; \
94 pt.eflags = xc.eflags; \
95 pt.esp = xc.esp; \
96 pt.xss = xc.ss; \
97 pt.xes = xc.es; \
98 pt.xds = xc.ds; \
99 pt.xfs = xc.fs; \
100 pt.xgs = xc.gs; \
101 }
103 #define SET_XC_REGS(pt, xc) \
104 { \
105 xc.ebx = pt->ebx; \
106 xc.ecx = pt->ecx; \
107 xc.edx = pt->edx; \
108 xc.esi = pt->esi; \
109 xc.edi = pt->edi; \
110 xc.ebp = pt->ebp; \
111 xc.eax = pt->eax; \
112 xc.eip = pt->eip; \
113 xc.cs = pt->xcs; \
114 xc.eflags = pt->eflags; \
115 xc.esp = pt->esp; \
116 xc.ss = pt->xss; \
117 xc.es = pt->xes; \
118 xc.ds = pt->xds; \
119 xc.fs = pt->xfs; \
120 xc.gs = pt->xgs; \
121 }
124 #define vtopdi(va) ((va) >> PDRSHIFT)
125 #define vtopti(va) (((va) >> PAGE_SHIFT) & 0x3ff)
127 /* XXX application state */
130 static int xc_handle;
131 static long nr_pages = 0;
132 unsigned long *page_array = NULL;
133 static int regs_valid[MAX_VIRT_CPUS];
134 static unsigned long cr3[MAX_VIRT_CPUS];
135 static vcpu_guest_context_t ctxt[MAX_VIRT_CPUS];
137 static inline int paging_enabled(vcpu_guest_context_t *v)
138 {
139 unsigned long cr0 = v->ctrlreg[0];
141 return (cr0 & X86_CR0_PE) && (cr0 & X86_CR0_PG);
142 }
144 /* --------------------- */
146 static void *
147 map_domain_va(unsigned long domid, int cpu, void * guest_va, int perm)
148 {
149 unsigned long pde, page;
150 unsigned long va = (unsigned long)guest_va;
151 long npgs = xc_get_tot_pages(xc_handle, domid);
153 static unsigned long cr3_phys[MAX_VIRT_CPUS];
154 static unsigned long *cr3_virt[MAX_VIRT_CPUS];
155 static unsigned long pde_phys[MAX_VIRT_CPUS];
156 static unsigned long *pde_virt[MAX_VIRT_CPUS];
157 static unsigned long page_phys[MAX_VIRT_CPUS];
158 static unsigned long *page_virt[MAX_VIRT_CPUS];
160 static int prev_perm[MAX_VIRT_CPUS];
162 if (nr_pages != npgs) {
163 if (nr_pages > 0)
164 free(page_array);
165 nr_pages = npgs;
166 if ((page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL) {
167 printf("Could not allocate memory\n");
168 goto error_out;
169 }
171 if (xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages) {
172 printf("Could not get the page frame list\n");
173 goto error_out;
174 }
175 }
177 FETCH_REGS(cpu);
179 if (cr3[cpu] != cr3_phys[cpu])
180 {
181 cr3_phys[cpu] = cr3[cpu];
182 if (cr3_virt[cpu])
183 munmap(cr3_virt[cpu], PAGE_SIZE);
184 if ((cr3_virt[cpu] = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
185 PROT_READ,
186 cr3_phys[cpu] >> PAGE_SHIFT)) == NULL)
187 goto error_out;
188 }
189 if ((pde = cr3_virt[cpu][vtopdi(va)]) == 0) /* logical address */
190 goto error_out;
191 if ((ctxt[cpu].flags & VGCF_VMX_GUEST) && paging_enabled(&ctxt[cpu]))
192 pde = page_array[pde >> PAGE_SHIFT] << PAGE_SHIFT;
193 if (pde != pde_phys[cpu])
194 {
195 pde_phys[cpu] = pde;
196 if (pde_virt[cpu])
197 munmap(pde_virt[cpu], PAGE_SIZE);
198 if ((pde_virt[cpu] = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
199 PROT_READ,
200 pde_phys[cpu] >> PAGE_SHIFT)) == NULL)
201 goto error_out;
202 }
203 if ((page = pde_virt[cpu][vtopti(va)]) == 0) /* logical address */
204 goto error_out;
205 if (ctxt[cpu].flags & VGCF_VMX_GUEST && paging_enabled(&ctxt[cpu]))
206 page = page_array[page >> PAGE_SHIFT] << PAGE_SHIFT;
207 if (page != page_phys[cpu] || perm != prev_perm[cpu])
208 {
209 page_phys[cpu] = page;
210 if (page_virt[cpu])
211 munmap(page_virt[cpu], PAGE_SIZE);
212 if ((page_virt[cpu] = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
213 perm,
214 page_phys[cpu] >> PAGE_SHIFT)) == NULL) {
215 printf("cr3 %lx pde %lx page %lx pti %lx\n", cr3[cpu], pde, page, vtopti(va));
216 page_phys[cpu] = 0;
217 goto error_out;
218 }
219 prev_perm[cpu] = perm;
220 }
221 return (void *)(((unsigned long)page_virt[cpu]) | (va & BSD_PAGE_MASK));
223 error_out:
224 return NULL;
225 }
227 int
228 xc_waitdomain(int domain, int *status, int options)
229 {
230 dom0_op_t op;
231 int retval;
232 struct timespec ts;
233 ts.tv_sec = 0;
234 ts.tv_nsec = 10*1000*1000;
236 if (!xc_handle)
237 if ((xc_handle = xc_interface_open()) < 0)
238 {
239 printf("xc_interface_open failed\n");
240 return -1;
241 }
242 op.cmd = DOM0_GETDOMAININFO;
243 op.u.getdomaininfo.domain = domain;
244 retry:
246 retval = do_dom0_op(xc_handle, &op);
247 if (retval || op.u.getdomaininfo.domain != domain) {
248 printf("getdomaininfo failed\n");
249 goto done;
250 }
251 *status = op.u.getdomaininfo.flags;
253 if (options & WNOHANG)
254 goto done;
257 if (!(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED)) {
258 nanosleep(&ts,NULL);
259 goto retry;
260 }
261 done:
262 return retval;
264 }
266 long
267 xc_ptrace(enum __ptrace_request request, u32 domid, long eaddr, long edata)
268 {
269 dom0_op_t op;
270 int status = 0;
271 struct gdb_regs pt;
272 long retval = 0;
273 unsigned long *guest_va;
274 int cpu = VCPU;
275 void *addr = (char *)eaddr;
276 void *data = (char *)edata;
278 op.interface_version = DOM0_INTERFACE_VERSION;
280 if (!xc_handle)
281 if ((xc_handle = xc_interface_open()) < 0)
282 return -1;
283 #if 0
284 printf("%20s %d, %p, %p \n", ptrace_names[request], domid, addr, data);
285 #endif
286 switch (request) {
287 case PTRACE_PEEKTEXT:
288 case PTRACE_PEEKDATA:
289 if ((guest_va = (unsigned long *)map_domain_va(domid, cpu, addr, PROT_READ)) == NULL) {
290 status = EFAULT;
291 goto error_out;
292 }
294 retval = *guest_va;
295 break;
296 case PTRACE_POKETEXT:
297 case PTRACE_POKEDATA:
298 if ((guest_va = (unsigned long *)map_domain_va(domid, cpu, addr, PROT_READ|PROT_WRITE)) == NULL) {
299 status = EFAULT;
300 goto error_out;
301 }
303 *guest_va = (unsigned long)data;
304 break;
305 case PTRACE_GETREGS:
306 case PTRACE_GETFPREGS:
307 case PTRACE_GETFPXREGS:
308 FETCH_REGS(cpu);
310 if (request == PTRACE_GETREGS) {
311 SET_PT_REGS(pt, ctxt[cpu].user_regs);
312 memcpy(data, &pt, sizeof(struct gdb_regs));
313 } else if (request == PTRACE_GETFPREGS)
314 memcpy(data, &ctxt[cpu].fpu_ctxt, sizeof(ctxt[cpu].fpu_ctxt));
315 else /*if (request == PTRACE_GETFPXREGS)*/
316 memcpy(data, &ctxt[cpu].fpu_ctxt, sizeof(ctxt[cpu].fpu_ctxt));
317 break;
318 case PTRACE_SETREGS:
319 op.cmd = DOM0_SETDOMAININFO;
320 SET_XC_REGS(((struct gdb_regs *)data), ctxt[VCPU].user_regs);
321 op.u.setdomaininfo.domain = domid;
322 /* XXX need to understand multiple vcpus */
323 op.u.setdomaininfo.vcpu = cpu;
324 op.u.setdomaininfo.ctxt = &ctxt[cpu];
325 retval = do_dom0_op(xc_handle, &op);
326 if (retval)
327 goto error_out;
329 break;
330 case PTRACE_ATTACH:
331 op.cmd = DOM0_GETDOMAININFO;
332 op.u.getdomaininfo.domain = domid;
333 retval = do_dom0_op(xc_handle, &op);
334 if (retval || op.u.getdomaininfo.domain != domid) {
335 perror("dom0 op failed");
336 goto error_out;
337 }
338 if (op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) {
339 printf("domain currently paused\n");
340 goto error_out;
341 }
342 printf("domain not currently paused\n");
343 op.cmd = DOM0_PAUSEDOMAIN;
344 op.u.pausedomain.domain = domid;
345 retval = do_dom0_op(xc_handle, &op);
346 break;
347 case PTRACE_SINGLESTEP:
348 ctxt[VCPU].user_regs.eflags |= PSL_T;
349 op.cmd = DOM0_SETDOMAININFO;
350 op.u.setdomaininfo.domain = domid;
351 op.u.setdomaininfo.vcpu = 0;
352 op.u.setdomaininfo.ctxt = &ctxt[cpu];
353 retval = do_dom0_op(xc_handle, &op);
354 if (retval) {
355 perror("dom0 op failed");
356 goto error_out;
357 }
358 /* FALLTHROUGH */
359 case PTRACE_CONT:
360 case PTRACE_DETACH:
361 if (request != PTRACE_SINGLESTEP) {
362 FETCH_REGS(cpu);
363 /* Clear trace flag */
364 if (ctxt[cpu].user_regs.eflags & PSL_T) {
365 ctxt[cpu].user_regs.eflags &= ~PSL_T;
366 op.cmd = DOM0_SETDOMAININFO;
367 op.u.setdomaininfo.domain = domid;
368 op.u.setdomaininfo.vcpu = cpu;
369 op.u.setdomaininfo.ctxt = &ctxt[cpu];
370 retval = do_dom0_op(xc_handle, &op);
371 if (retval) {
372 perror("dom0 op failed");
373 goto error_out;
374 }
375 }
376 }
377 regs_valid[cpu] = 0;
378 op.cmd = DOM0_UNPAUSEDOMAIN;
379 op.u.unpausedomain.domain = domid > 0 ? domid : -domid;
380 retval = do_dom0_op(xc_handle, &op);
381 break;
382 case PTRACE_SETFPREGS:
383 case PTRACE_SETFPXREGS:
384 case PTRACE_PEEKUSER:
385 case PTRACE_POKEUSER:
386 case PTRACE_SYSCALL:
387 case PTRACE_KILL:
388 #ifdef DEBUG
389 printf("unsupported xc_ptrace request %s\n", ptrace_names[request]);
390 #endif
391 /* XXX not yet supported */
392 status = ENOSYS;
393 break;
394 case PTRACE_TRACEME:
395 printf("PTRACE_TRACEME is an invalid request under Xen\n");
396 status = EINVAL;
397 }
399 if (status) {
400 errno = status;
401 retval = -1;
402 }
403 error_out:
404 return retval;
405 }